※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。
本記事は下記の記事の続きとなります。
#非同期処理のチェーンとは
非同期処理のチェーンとは、一つの非同期処理が終了した後に、次の非同期処理を開始し、チェーンのようにどんどんつなげていく処理のことです。
今この様な非同期処理を行うプログラムがあるとします。
function sleep() {
setTimeout(function () {
console.log(0);
}, 1000);
}
1000ミリ秒後に0を出力するプログラムです。
非同期処理をつなげるには、内部でさらに非同期処理を呼び出してあげます。
function sleep() {
setTimeout(function () {
console.log(0);
sleep(); //1000ミリ待機後、関数sleep自体が呼び出される。
}, 1000);
}
上記のプログラムでは、呼び出された関数sleepが、さらにsleep関数を呼び出し無限ループしてします。
そこで引数として関数sleepを呼び出す関数を渡してあげます。
function sleep(callback) {
setTimeout(function () {
console.log(0);
callback();
}, 1000);
}
sleep(function () { sleep( function(){} ) });
この様にすることで、非同期処理を繋げることができました。
※二回目の関数sleepには何もしない処理をコールバックに渡しています。
話が脱線しますが、下記のプログラムだとエラーになります。
function sleep(callback) {
setTimeout(function () {
console.log(0);
callback();
}, 1000);
}
sleep( sleep( function(){} ));
理由は、引数として渡される値が、「関数」か、「関数の戻り値」かの違いです。
正しい方のプログラムでは引数として
function () { sleep( function(){} ) }
無名関数自体を渡していますが、エラープログラムでは
sleep( function(){} )
引数で中で、先にsleep関数を実行させちゃっています。
console.log(function () { sleep( function(){} ) });
console.log(sleep( function(){} ));
上記のプログラムを実行してみたらわかりますが、正しいプログラムの出力結果は[Function (anonymous)]で、エラープログラムの方の結果は、「undefined」となります。(関数sleep自体は戻り値を返すプログラムではないので)
よって、エラーバージョンのプログラムは下記を実行していることになります。
function sleep(callback) {
setTimeout(function () {
console.log(0);
callback();
}, 1000);
}
sleep( sleep( undefined ));
もちろん、引数に渡したundefinedは、関数ではないので、下記の様なエラーが出力されます。
TypeError: callback is not a function
//本来、仮引数callbackは、関数を受け取るが、それ以外が渡って来てるよという意味
話を戻します。
非同期処理の結果を次の非同期処理に渡すこともできます。
function sleep(callback, n) {
setTimeout(function () {
console.log(n);
n++
callback(n);
}, 1000);
}
sleep(function (n) { sleep(function () { }, n) } , 0);
少し分かりづらいですが、一回目のsleepでは、第二引数に0を渡しています。
内部処理でnは1加算され、その結果をコールバック関数に渡しています。
↓ こういうこと
function (1) { sleep(function () { }, 1) }
二回目のsleepは、一回目の処理結果nを受けて、その結果を出力します。結果は
0
1
となります。
では同じように関数sleepを五回つなげてみます。
function sleep(callback, n) {
setTimeout(function () {
console.log(n);
n++
callback(n);
}, 1000);
}
sleep(function (n) { sleep(function (n) { sleep(function (n) { sleep(function (n) { sleep(function (n) { sleep(function (n) { }, n); }, n); }, n); }, n); }, n); }, 0);
この様に、引数の中に再帰的に、sleepを呼び出す関数とnを受け渡していきます。これだとあまりにもヘルが過ぎるのでインデントをすると
function sleep(callback, n) {
setTimeout(function () {
console.log(n);
n++
callback(n);
}, 1000);
}
sleep(function (n) {
sleep(function (n) {
sleep(function (n) {
sleep(function (n) {
sleep(function (n) {
sleep(function (n) {
}, n);
}, n);
}, n);
}, n);
}, n);
}, 0);
これだと多少見やすくなりましたが、それでも分かりづらいですよね。
この様に、コールバックのネストが深くなっていきコードの見通しが悪くなっていくことを 「コールバックヘル」 と呼びます。
このような、コールバックヘルを回避するために 「Promise」 という処理があります。
次に続きます。
また、下記の記事でより詳細に非同期処理を記載いたしました。
もしよければ、下記の記事もご参考ください。