目的
Webアプリケーションを作成する際に、一旦サーバ上の設定ファイルやレンダリング用のモデルデータを事前に読み込んでおきたい場合に、どうしてもシーケンシャル(同時にアクセスしたくない場合)がある。jQueryのDeferredでも同じことができるが、fetch、async/awaitを用いることでもっと単純に処理ができるので、備忘として記載する。同じことを示した記事はいろいろとあるけど、どれもsetTimeoutやjQueryのDeferred、generatorなどの経緯も込みで書いてあるので、それはそちらにまかせて、ここではfetch + async/awaitのみを書く。
fetch + async/await
これでOK
getConfig = async() => {
var conf1 = await (await fetch("/conf/conf1.yml?_="+(new Date()).getDate())).text();
console.log(conf1);
var conf2 = await (await fetch("/conf/conf2.yml?_="+(new Date()).getDate())).text();
console.log(conf2);
}
window.onload = function(){
getConfig();
}
fetchやfetchの text() / json() / blob() などはPromiseを返却するので、以下のように書くと理屈がわかりやすい。
getConfig = async() => {
var promise1 = await fetch("/conf/conf1.yml?_="+(new Date()).getDate());
var conf1 = await promise1.text();
console.log(conf1);
var promise2 = await fetch("/conf/conf2.yml?_="+(new Date()).getDate());
var conf2 = await promise2.text();
console.log(conf2);
}
window.onload = function(){
getConfig();
}
fetchの代わりに、Promiseを返却する関数を指定しても同じことができる。
また、fetchは4xx系、5xx系のエラーコードが返却されても、正常処理としてしまうので、try catchが使えない。※ネットワーク系のエラーの場合のみcatchが使える。4xx、5xx系はstatusを見て判断しろという事らしい。
そのため、エラーハンドリングをしたい場合は以下のようにすることができる。
getConfig = async() => {
var conf1 = await (await fetch("/conf/conf1.yml?_="+(new Date()).getDate())
.then(handler)
.catch(error)
).text();
console.log(conf1);
var conf2 = await (await fetch("/conf/conf2.yml?_="+(new Date()).getDate())
.then(handler)
.catch(error)
).text();
console.log(conf2);
}
function handler(response){
if(!response.ok){
throw Error(response.statusText);
}
return response;
}
function error(e){
console.log(e);
}
window.onload = function(){
getConfig();
}
まとめ
- fetch は Promise を返却する
- await は async なメソッドの中でのみ実行可能
- await は Promise を待つ
- 上記のコードは、getConfig() 自体が同期になるわけではない。
- 上記のコードは
python -m SimpleHTTPServer 80
では動かないので注意 - トランスパイルなんてしたくない!!古いブラウザは捨てたい!!
大企業の古いブラウザバージョンいつまでもケアは頭がおかしい。
添付
- async/await対応状況 https://caniuse.com/#search=async%20functions
- fetch対応状況 https://caniuse.com/#feat=fetch