tag:crieit.net,2005:https://crieit.net/tags/fetch/feed 「fetch」の記事 - Crieit Crieitでタグ「fetch」に投稿された最近の記事 2019-06-09T23:58:56+09:00 https://crieit.net/tags/fetch/feed tag:crieit.net,2005:PublicArticle/15080 2019-06-09T23:58:56+09:00 2019-06-09T23:58:56+09:00 https://crieit.net/posts/fetch-fetch fetchがよくわからなかったのでオレオレfetchを作って雰囲気を掴む <p>前回、<a href="https://crieit.net/posts/Promise-Promise">こんな記事</a>を書きました。<br /> 上の記事のそもそもの発端は、fetchを使おうとしたけども、よくわからなかったからというものでした。<br /> 根本的には、fetchがわからないというよりはPromiseがよくわかってなかったという方が近いので、前回Promiseの雰囲気を掴んだ時点で7割方解決しているのだけれど、そもそもの発端を解決させようと思います。</p> <h2 id="そもそもの発端"><a href="#%E3%81%9D%E3%82%82%E3%81%9D%E3%82%82%E3%81%AE%E7%99%BA%E7%AB%AF">そもそもの発端</a></h2> <p>超絶ざっくり書くと、fetchというのは下記のようになるかと。</p> <pre><code class="JavaScript">fetch(url) .then((response)=>{ return response.json(); }) .then(()=>{ //json使って何か処理 }) .catch((error)=>{ //エラー処理 }) </code></pre> <p>まあ、こんな感じのものを見て、非同期をよくわかっていなかった僕はちんぷんかんぷんになって、どうにか、fetchというのは非同期で動くものらしい、というところまではわかった。<br /> なのでどうにかして非同期を勉強しなければいけない。<br /> そこでググったら出てくるわけです。</p> <pre><code class="JavaScript">const hoge = ()=>{ return new Promise((resolve,reject)=>{ setTimeout(()=>{ console.log('wait 3 sec!') resolve('wait 3 sec!') },3000) }) } </code></pre> <p>……。さっきまでPromiseとかresolveとかrejectとか出てこなかったじゃん。<br /> ってなって挫折していた。<br /> 今思えば至極単純で、Promiseとかresolveとかrejectとかはfetchの中で勝手にやっていることなので、fetchを使う分には登場しない。<br /> もちろん、理解する必要はあって、そのために今回もオレオレfetchを作ることで雰囲気を掴もうと思う。</p> <h2 id="注意"><a href="#%E6%B3%A8%E6%84%8F">注意</a></h2> <p>あくまで雰囲気を掴むだけです。実際の実装は微塵も知りません。<br /> いろんなドキュメントを読んだ上での筆者の解釈(を筆者の実装レベルでできるとこだけ再現したもの)です。とんちんかんかもしれません。<br /> 妥協しまくりです。<br /> あまりにもとんちんかんなこと言ってたら教えて下さい。<br /> 信用しないでください。<br /> レベル不足でクソコードです。</p> <h2 id="まず呼び出すコードから"><a href="#%E3%81%BE%E3%81%9A%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%99%E3%82%B3%E3%83%BC%E3%83%89%E3%81%8B%E3%82%89">まず呼び出すコードから</a></h2> <p>こんな感じのjsonを作ります。<br /> json-serverとかで適当にapiを作ります。</p> <pre><code class="json">{ "wizards":[ { "id":1, "name":"Arietta", "feature":"monster" }, { "id":2, "name":"Relum", "feature":"fool" }, { "id":3, "name":"Elise", "feature":"poor" } ] } </code></pre> <p>で、呼び出し側</p> <pre><code class="html"><html lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script type="text/javascript" src="promise.js"></script> <script type="text/javascript" src="fetch.js"></script> <script type="text/javascript" src="index.js"></script> <style> table{ border:solid 1px; } th{ border:solid 1px; } td{ border:solid 1px; } </style> </head> <body> hello async <button onclick="getData()"> fetch </button> <table > <thead> <th>id</th> <th>name</th> <th>feature</th> </thead> <tbody id="tbody"> </tbody> </table> </body> </html> </code></pre> <pre><code class="JavaScript">const getData = () => { const url = 'https://localhost:3000/wizards' //json-serverとかでよしなに fetch(url) //oreoreFetch(url) //これに置き換えても動くようにするのが目標 .then((response)=>{ return response.json(); }) .then((json)=>{ const tbody = document.getElementById('tbody'); json.forEach((wiz)=>{ let tr = ` <tr> <td>${wiz.id}</td> <td>${wiz.name}</td> <td>${wiz.feature}</td> </tr> `; tbody.insertAdjacentHTML("beforeend",tr); }); }) } </code></pre> <p><a href="https://crieit.now.sh/upload_images/59edc21d3f7f537d3dfb5ec99e2cfb135cf9c8d15ca25.JPG" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/59edc21d3f7f537d3dfb5ec99e2cfb135cf9c8d15ca25.JPG?mw=700" alt="WS000001.JPG" /></a><br /> まー、動くよね</p> <h2 id="で、fetchのコード"><a href="#%E3%81%A7%E3%80%81fetch%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89">で、fetchのコード</a></h2> <pre><code class="JavaScript">const oreoreFetch = (url)=>{ return new Promise((resolve,reject)=>{ httpRequest(resolve,reject,url) }); //最終的に前回のオレオレPromiseで動いてほしい //けど、Promiseチェーンが実装できなかったんだよな… //return new oreorePromise((resolve,reject)=>{ // httpRequest(resolve,reject,url) //}); } const httpRequest = (resolve,reject,url) =>{ const xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { switch ( xhr.readyState ) { //めんどいので4以外省略 case 0: break; case 1: // データ送信中. break; case 2: // 応答待ち. break; case 3: // データ受信中. break; case 4: // データ受信完了. if( xhr.status == 200 || xhr.status == 304 ) { const data = new oreoreResponse(xhr.responseText); resolve(data); } else { reject(xhr.statusText); } break; } } xhr.open( 'GET', url, true ); xhr.send(null); } class oreoreResponse{ constructor(data){ this.data = data; } json(){ return JSON.parse(this.data); } } </code></pre> <p>fetchができればいいのでResponseクラスは適当です。<br /> (実際はコンストラクタに引数はないし、jsonメソッドはPromiseを返す)<br /> Promiseの勉強で出てきたresolveとかrejectは(たぶん)fetchの中にあって、よしなにやってくれるので、fetchを使う分には意識しなくていいよ、ってのがわかる。</p> <p>ということで動かす。</p> <pre><code class="JavaScript">const getData = () => { const url = 'https://localhost:3000/wizards' //fetch(url) oreoreFetch(url) //これに置き換えても動くようにするのが目標 .then((response)=>{ return response.json(); }) .then((json)=>{ const tbody = document.getElementById('tbody'); json.forEach((wiz)=>{ let tr = ` <tr> <td>${wiz.id}</td> <td>${wiz.name}</td> <td>${wiz.feature}</td> </tr> `; tbody.insertAdjacentHTML("beforeend",tr); }); }) } </code></pre> <p><a href="https://crieit.now.sh/upload_images/8b94c3234843b3b4306df2d82355801c5cf9c8ec8f968.JPG" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/8b94c3234843b3b4306df2d82355801c5cf9c8ec8f968.JPG?mw=700" alt="WS000000.JPG" /></a><br /> まー、それっぽく動く。</p> <h2 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h2> <p>みんな、async/await使おうぜ!</p> hammhiko