先端非同期プログラミングスキームの進化を理解する文章
2935 ワード
JSにとって、非同期プログラミングはコールバック関数、イベントリスニング、サブスクリプションの発行などのスキームを採用することができ、ES 6の後、Promise、Genertor、Async/Awaitのスキームを追加しました.本稿では,コールバック関数からAsync/Awaitへの発展の歴史とそれらの関係について述べる.
1.非同期プログラミングの進化
まず、1つのページをレンダリングするには、非同期のシリアル要求A,B,Cのみがページのデータを取得してページを要求すると仮定します.
異なる非同期プログラミング方式に対して、次のコードが得られます.
1.1コールバック関数
コールバック関数のネストはますます深くなっている.絶え間ないコールバックでは、request(A)コールバック関数の他の論理がrequest(B)に影響し、request(C)の論理、同様に、request(B)の他の論理もrequest(C)に影響します.この例では、request(A)がrequest(B)を呼び出し、request(B)がrequest(C)を呼び出し、request(C)が実行済みに戻り、request(B)が実行済みに戻り、request(A)が実行済みに戻る.我々はすぐに前後順に混乱を生じ,非同期コールバックの結果を直感的に解析することは困難である.これをコールバック地獄と呼ぶ.
このような状況を解決するために、ES 6はPromiseオブジェクトを追加した.
1.2 Promise
Promiseオブジェクトはthen関数でコールバックを指定します.したがって,1.1でのコールバック関数の例を前述のように変更することができる.Promiseはコールバック地獄を解消していないが、thenチェーンを通じてコードロジックをより明確にしていることがわかる.この例では、request(A)がrequest(B)を呼び出し、request(B)がrequest(C)を呼び出し、request(C)が実行済みに戻ってくる.現在、request(A)の内容は、宣言されたdataを表示することによってのみrequest(C)に影響を与えることができます.コールバックで宣言されていない場合、request(C)に影響を与えることはできません.言い換えれば、各セグメントのコールバックはほぼ独立した分割になります.
しかしPromise自体にはthenが山積しており,同期コードを書くように非同期コードを書くことはできないため,JSはGeneratorを導入した.
1.3 Generator
GeneratorはES 6上でのコモンシップの実装であり、コモンシップとは、1つのスレッド上の異なる関数間の実行権が互いに切り替えられることを意味する.この例ではgen()を実行し、yieldに遭遇したときに一時停止し、実行権をrequest(A)に渡し、next()メソッドが呼び出されるまで実行権をgen()に返します.
協働によりJSは同期方式で非同期のコードを書くことを実現したが,Generatorの使用はアクチュエータに合わせる必要があり,これは当然面倒である.そこでAsync/Awaitがありました.
Generatorの自動アクチュエータはco関数ライブラリであり,興味のある学生は『co関数ライブラリの意味と使い方』を読むことで理解できる.
1.4 Async/Await
コードを比較すると、1.4のコードは1.3のコードのうち*=>async、yieldをawaitに変えるだけです.しかしAsync関数の実現は、Generator関数とオートエフェクタを一つの関数にパッケージすることである[1].spawnは自動アクチュエータです.
これに加えて、Async関数はGenerator関数よりも優れた拡張性を有する.yieldはPromise関数/Thunk関数に接続されているが、awaitは一般関数も含むことができる.普通の関数ではawait式の演算結果が待っているものです.そうでなければawaitがPromise関数である場合、awaitはresolveまたはrejectまでこのPromise関数にコンシステントし、その後メイン関数にコンシステントする[2].もちろんAsync関数もGenerator関数よりも読みやすく理解しやすい.
2.まとめ
本論文では,コールバック関数からAsync/Awaitへの発展の歴史を述べた.Async関数は、パラレル非同期処理においてPromiseを利用するにもかかわらず、究極の解決策として機能する.all()ですが、他の面では十分完璧です.
リファレンスドキュメント『ECMAScript 6非同期プログラミングを深く把握する』シリーズ 『JavaScriptを理解するasync/await』
1.非同期プログラミングの進化
まず、1つのページをレンダリングするには、非同期のシリアル要求A,B,Cのみがページのデータを取得してページを要求すると仮定します.
異なる非同期プログラミング方式に対して、次のコードが得られます.
1.1コールバック関数
// request
request(A, function () {
request(B, function () {
request(C, function () {
//
})
})
})
コールバック関数のネストはますます深くなっている.絶え間ないコールバックでは、request(A)コールバック関数の他の論理がrequest(B)に影響し、request(C)の論理、同様に、request(B)の他の論理もrequest(C)に影響します.この例では、request(A)がrequest(B)を呼び出し、request(B)がrequest(C)を呼び出し、request(C)が実行済みに戻り、request(B)が実行済みに戻り、request(A)が実行済みに戻る.我々はすぐに前後順に混乱を生じ,非同期コールバックの結果を直感的に解析することは困難である.これをコールバック地獄と呼ぶ.
このような状況を解決するために、ES 6はPromiseオブジェクトを追加した.
1.2 Promise
// request Promise
request(A).then(function () {
return request(B)
}).then(function () {
return request(C)
}).then(function () {
//
})
Promiseオブジェクトはthen関数でコールバックを指定します.したがって,1.1でのコールバック関数の例を前述のように変更することができる.Promiseはコールバック地獄を解消していないが、thenチェーンを通じてコードロジックをより明確にしていることがわかる.この例では、request(A)がrequest(B)を呼び出し、request(B)がrequest(C)を呼び出し、request(C)が実行済みに戻ってくる.現在、request(A)の内容は、宣言されたdataを表示することによってのみrequest(C)に影響を与えることができます.コールバックで宣言されていない場合、request(C)に影響を与えることはできません.言い換えれば、各セグメントのコールバックはほぼ独立した分割になります.
しかしPromise自体にはthenが山積しており,同期コードを書くように非同期コードを書くことはできないため,JSはGeneratorを導入した.
1.3 Generator
function* gen(){
var r1 = yield request(A)
var r2 = yield request(B)
var r3 = yield request(C)
//
};
GeneratorはES 6上でのコモンシップの実装であり、コモンシップとは、1つのスレッド上の異なる関数間の実行権が互いに切り替えられることを意味する.この例ではgen()を実行し、yieldに遭遇したときに一時停止し、実行権をrequest(A)に渡し、next()メソッドが呼び出されるまで実行権をgen()に返します.
協働によりJSは同期方式で非同期のコードを書くことを実現したが,Generatorの使用はアクチュエータに合わせる必要があり,これは当然面倒である.そこでAsync/Awaitがありました.
Generatorの自動アクチュエータはco関数ライブラリであり,興味のある学生は『co関数ライブラリの意味と使い方』を読むことで理解できる.
1.4 Async/Await
async function gen() {
var r1 = await request(A)
var r2 = await request(B)
var r3 = await request(C)
//
}
コードを比較すると、1.4のコードは1.3のコードのうち*=>async、yieldをawaitに変えるだけです.しかしAsync関数の実現は、Generator関数とオートエフェクタを一つの関数にパッケージすることである[1].spawnは自動アクチュエータです.
async function fn(args){
// ...
}
//
function fn(args){
return spawn(function*() {
// ...
});
}
これに加えて、Async関数はGenerator関数よりも優れた拡張性を有する.yieldはPromise関数/Thunk関数に接続されているが、awaitは一般関数も含むことができる.普通の関数ではawait式の演算結果が待っているものです.そうでなければawaitがPromise関数である場合、awaitはresolveまたはrejectまでこのPromise関数にコンシステントし、その後メイン関数にコンシステントする[2].もちろんAsync関数もGenerator関数よりも読みやすく理解しやすい.
2.まとめ
本論文では,コールバック関数からAsync/Awaitへの発展の歴史を述べた.Async関数は、パラレル非同期処理においてPromiseを利用するにもかかわらず、究極の解決策として機能する.all()ですが、他の面では十分完璧です.
リファレンスドキュメント