前回、こんな記事を書きました。
上の記事のそもそもの発端は、fetchを使おうとしたけども、よくわからなかったからというものでした。
根本的には、fetchがわからないというよりはPromiseがよくわかってなかったという方が近いので、前回Promiseの雰囲気を掴んだ時点で7割方解決しているのだけれど、そもそもの発端を解決させようと思います。
超絶ざっくり書くと、fetchというのは下記のようになるかと。
fetch(url)
.then((response)=>{
return response.json();
})
.then(()=>{
//json使って何か処理
})
.catch((error)=>{
//エラー処理
})
まあ、こんな感じのものを見て、非同期をよくわかっていなかった僕はちんぷんかんぷんになって、どうにか、fetchというのは非同期で動くものらしい、というところまではわかった。
なのでどうにかして非同期を勉強しなければいけない。
そこでググったら出てくるわけです。
const hoge = ()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
console.log('wait 3 sec!')
resolve('wait 3 sec!')
},3000)
})
}
……。さっきまでPromiseとかresolveとかrejectとか出てこなかったじゃん。
ってなって挫折していた。
今思えば至極単純で、Promiseとかresolveとかrejectとかはfetchの中で勝手にやっていることなので、fetchを使う分には登場しない。
もちろん、理解する必要はあって、そのために今回もオレオレfetchを作ることで雰囲気を掴もうと思う。
あくまで雰囲気を掴むだけです。実際の実装は微塵も知りません。
いろんなドキュメントを読んだ上での筆者の解釈(を筆者の実装レベルでできるとこだけ再現したもの)です。とんちんかんかもしれません。
妥協しまくりです。
あまりにもとんちんかんなこと言ってたら教えて下さい。
信用しないでください。
レベル不足でクソコードです。
こんな感じのjsonを作ります。
json-serverとかで適当にapiを作ります。
{
"wizards":[
{
"id":1,
"name":"Arietta",
"feature":"monster"
},
{
"id":2,
"name":"Relum",
"feature":"fool"
},
{
"id":3,
"name":"Elise",
"feature":"poor"
}
]
}
で、呼び出し側
<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>
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);
});
})
}
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);
}
}
fetchができればいいのでResponseクラスは適当です。
(実際はコンストラクタに引数はないし、jsonメソッドはPromiseを返す)
Promiseの勉強で出てきたresolveとかrejectは(たぶん)fetchの中にあって、よしなにやってくれるので、fetchを使う分には意識しなくていいよ、ってのがわかる。
ということで動かす。
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);
});
})
}
みんな、async/await使おうぜ!
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント