[js] 非同期処理のdone, failを卒業する
非同期処理を普段どう書いていますか?
僕はdone-failを用いて書いています。実はこの書き方保守性の面であまり良くない。
*jqueryを使用
$.ajax({
url: 'https://zipcloud.ibsnet.co.jp/api/search?zipcode=7830060'
})
.done(function(res) {
console.log(res);
})
.fail(function(res){
console.log(res);
});
// =>
// {
// 'message': null,
// 'results': [{ ... }],
// 'status': 200
// }
*以下ajaxの中は簡略化します。
問題1. errorキャッチができない
doneの中でエラーが出たときにfailがキャッチしそうですが実はキャッチできません。
もしdoneの中でエラーハンドリングを行いたい場合はtry-catchを毎回書く必要があります。
さらにtry-catchでネストが深くなるのも嬉しくない。
$.ajax()
.done(function(res) {
throw 'error';
console.log(res);
})
.fail(function(e) {
// キャッチできない
console.log(e);
});
// Uncaught error
問題2. コールバック地獄
例えば「ajax通信を複数使いたいが同期的に行いたい時」や「スコープ外の変数へのアクセスのためにコールバックを用いたい時」にネストを深くするスパイラルから抜け出せなくなります。
所謂コールバック地獄。
function successFunc(data) {
// ...
}
function fetch(callback) {
$.ajax()
.done(function(res1) {
$.ajax()
.done(function(res2) {
// 終了時の処理
callback(res2);
})
.fail(function(res) { ... })
})
.fail(function(res) { ... })
})
fetch(successFunc)
解決策
コールバックを防ぐ手段としてPromiseで制御する方法があります。
Promiseに続くthenは同期的に処理を行うことを示しています。したがってコールバック地獄から抜け出せる。また、then-catchを用いることでエラーハンドリングも可能。
少し今風の書き方に変えてこんな感じで書ける。
const fetch = () => {
return new Promise((resolve, reject) => {
$.ajax()
.done(res => {
// ...
resolve(res)
})
.fail(res => reject(res));
});
}
// then-catch
fetch().then(res => ... ).catch(e => )
さらにjQueryの$.ajaxはPromiseを内包したDeferredオブジェクトが返ってくるので、より簡潔に書ける。
参考:爆速でわかるjQuery.Deferred超入門
const fetch = () => {
return $.ajax();
}
fetch().then(res => {
// ...
return var
}).then(var => {
// ...
throw 'error'
}).catch(e => console.log(e))
// => error
ここで注目すべきところはdone-failは連結できないがthenは連結できるというところ。
理由はthenがPromiseオブジェクトを返すから。
参考:Promiseチェーン
async/await
さてPromiseオブジェクトを返しthen-catchを使うことでdone-failを卒業できそうな気がします。
ただ毎回resolve,rejectを書くのは忘れてしまいそうですしthenの見通しが少し悪い気もします。
もっと直感的な書き方はできないのか。。。
ありました!
その名もasync-await!
asyncはPromiseを返し、resolveやrejectを明示的に使わずthenチェーンがかけます。
また、asyncの中でawaitをつけた関数がある場合、awaitの関数が終了するまで後続の処理は実行されません。
const fetch = () => {
return $.ajax(...)
}
const timer2Seconds = res => {
return new Promise(resolve => {
setTimeout( () => {
console.log(res);
resolve('timeout');
}, 2000);
});
}
const main = async () => {
const res = await fetch();
const timer = await timer2Seconds(res);
return timer
}
main().then(message => {throw message}).catch(e => console.log(e));
// => timeout
メリットはこちらの記事がわかりやすいです。
JavaScriptのasync/awaitがPromiseよりもっと良い
Author And Source
この問題について([js] 非同期処理のdone, failを卒業する), 我々は、より多くの情報をここで見つけました https://qiita.com/www_y118/items/a7e9408c046f581b954d著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .