JavaScriptのPromiseとarray.reduceを合わせて使う
順番に非同期の処理をしたい要素たちを配列に入れて、各要素に対してPromiseを返す関数を実行する。
例)['a', 'b', 'c']という配列があったときに、それぞれの文字を2秒おきにコンソールに表示したい
//これだと2秒後にほぼ同時に「a」「b」「c」がコンソールに表示されるのでNG function wait2sec (item) { //2秒後に引数itemをコンソールに表示するfunction return new Promise( function(resolve, reject) { window.setTimeout(function() { console.log(item); resolve(); }, 2000); }); } ['a', 'b', 'c'].forEach(function (item) { wait2sec(item); });
//2秒おきにconsole.log()される! function wait2sec (item) { //このfunctionはさっきと同じ return new Promise(function (resolve, reject) { window.setTimeout(function () { console.log(item); resolve(); }, 2000); }); } ['a', 'b', 'c'].reduce(function (prevValue, currentValue) { return prevValue.then(function () { ////直前の要素の処理(2秒かかる)が終わってから次の要素をwait2sec()に渡す return wait2sec(currentValue); }); }, Promise.resolve());
たまにIE8から対応とかあるのでjQueryだけでどうにかする(だいぶ無理矢理感が・・・)
function wait2sec (list, i) { var dfd = new $.Deferred(); window.setTimeout(function () { console.log(list[i]); dfd.resolve(i + 1); }, 2000); return dfd.promise(); } var list = ['a', 'b', 'c']; var i = 0; var prevValue = new $.Deferred().resolve(0); for (i = 0; i < list.length; i += 1) { prevValue = prevValue.then( function (next_i) { return wait2sec(list, next_i); }); };
Array.prototype.reduceについて
使ったことなかったですが、便利ですね!
Array.prototype.reduce() - JavaScript | MDN
IE9以降で使えるそう。過去に書いたコードの中にも、これを使えばもう少し簡潔に書けたものがありそうな気する・・・。