ES 6—Asyncと非同期プログラミング(11)
6419 ワード
シングルスレッドはJavascript言語の最も本質的な特性の一つで、Javascriptエンジンはjsコードを実行する時、同じ時間に単一のタスクしか実行できません.
このモードのメリットは実現が比較的簡単で、実行環境が比較的単純であることです.
悪いところは一つのタスクがある限り、時間がかかります.後のタスクは並んで待つ必要があります.プログラム全体の実行を遅らせます.よくあるブラウザは無応答(仮死)で、あるJavascriptコードが長時間運行されているため、ページカード全体がこの場所にあるため、他のタスクは実行できません.
ですから、非同期プログラミングはJavaScript言語にとって重要です.
一部の子供たちはまだ「非同期」をよく理解していないかもしれません.
「非同期」とは、一つの任務を二つの段階に分けて、最初の段階を実行して、他の任務を実行します.準備ができたら、また後ろに回って第二段を実行します.
例えば、ファイルを読み込んで処理するジョブがありますが、ジョブの最初のセグメントはオペレーティングシステムに要求し、ファイルの読み込みを要求します.その後、プログラムは他のタスクを実行し、オペレーティングシステムがファイルに戻ってから、タスクの第二段(処理ファイル)を実行します.このような不連続な実行は、非同期と呼ばれる.
したがって、連続して実行することを同期という.連続実行ですので、他のタスクを挿入できません.オペレーティングシステムがハードディスクからファイルを読み込むまでの間は、プログラムは待つしかありません.
話の通俗点:
朱自清の『後ろ姿』で、父は朱自清に対して言いました.「蜜柑をいくつか買いに行きます.ここにいます.歩かないでください.」
朱自清は歩いていません.ミカンを買った父が一緒にみかんを食べるのを待っています.同期といいます.
父を待たずに一人で行ったら、父と一緒にみかんを食べられない.
1、非同期プログラミング
私たちはユーザー登録という特に一般的なシーンを例にとって、非同期プログラミングについて説明します.
第一歩は、ユーザが登録されているかどうかを検証する.
第二ステップ、登録されていません.認証コードを送信します.
第三段階、検証コード、パスワードを記入し、検証コードが正しいかどうかを確認する.
この過程には一定の順序があります.前のステップが完成してこそ、次のステップがスムーズに進みます.
1.1コールバック関数
また、度重なるコールバック関数に異常があったら、デバッグは非常に潰されます.try-catchは非同期の異常を捕まえられないので、私たちはデバッグを書いて追跡するしかないです.
このような幾重もの入れ子はリフロー地獄と呼ばれています.
1.2 Promise方式
Promiseは地獄問題を解決するために提出されました.これは新しい文法機能ではなく、新しい書き方です.コールバック関数のネストをチェーン式呼出しに変えられます.Promiseを採用し、複数のファイルを連続して読み込み、次のように書きます.
Promiseコードの読み取り可能性は、コールバック関数よりも高く、コードの実行順序は一目瞭然です.
Promiseの方式は地獄を転調しましたが、最大の問題はコード冗長で、元の任務はPromiseに包装されました.どんな操作でも、一目で見たらthenがいっぱいになり、元の意味がよく分かりません.コードフローは実行フローをよく表していません.
みんなは中学校で電気回路を習ったことがあります.これは電気回路の直列のようです.習ったことがないなら大丈夫です.jqueryにチェーン操作があると知っています.これはチェーン操作の書き方に似ています.
1.3 async/await方式
async文法はnew Promiseの包装に対してで、await文法はthen方法に対する洗練です.
doregisterの前にキーワードasyncをつければ、関数内の非同期タスクの前にawait声明を追加すればいいです.これらの追加のキーワードを無視すれば、ほぼ完全な同期の書き方です.
2、asyncの使い方
2.1 Promiseオブジェクトに戻る
async関数はPromiseオブジェクトを返します.
async関数の内部return文で返した値は、thenメソッドのコールバック関数のパラメータになります.
通常、awaitコマンドの後にPromiseオブジェクトがあり、そのオブジェクトの結果に戻ります.Promiseオブジェクトでない場合は、直接に対応する値を返します.
await命令はasync関数でしか使えません.普通の関数で使うと、エラーが発生します.
async/awaitを使うことによって、私達はtry/catchと協力して非同期の作業中の問題を捕獲できます.Promiseの中でrejectのデータを含みます.
awaitの後ろにrejectがあるかもしれません.try...catchコードブロックの中で
async/await文法は確かに簡単で使いやすいですが、使い方も間違えやすいので、具体的なビジネスシーンの需要によって決めます.
例えば、画像のサイズ情報を取得したいです.
4、まとめ
最初のコールバック関数からPromiseオブジェクトに至るまで、毎回改善されていますが、中途半端な感じがします.それらはいずれも追加的な複雑さがあり、抽象的な底部の動作機構を理解する必要がある.
例えば、3つの要求が発生する必要があり、第3の要求は第2の要求の結果に依存し、第2の要求は第1の要求の結果に依存する.ES 5で実現すれば、3層のコールバックがあり、コードの横方向発展をもたらします.Promiseで実現するには少なくとも3つのthenが必要で、コードの縦方向の発展をもたらします.しかし、async/awaitはこれらの問題を解決しました.
実現してきたasync/awaitは、ジェネレータ、Promiseに基づいて構築された新しい文法です.
しかし、async/awaitを軽視しないでください.同期方式で非同期コードを書くのはとても強いです.
async/awaitは語義化、コードの簡略化、エラー処理などの面で多くの利点があります.async/waitで条件コードを作成するのは簡単で、同じコード構造(周知のtry/catch文)を使って同期と非同期エラーを処理することができます.だから、JavaScript異歩プログラミングの最終解決案と呼ばれています.その重要性と利点が分かります.
今後の実戦プロジェクトで、たくさん練習してこそ、async/awaitの真の技術を身につけることができると思います.
このモードのメリットは実現が比較的簡単で、実行環境が比較的単純であることです.
悪いところは一つのタスクがある限り、時間がかかります.後のタスクは並んで待つ必要があります.プログラム全体の実行を遅らせます.よくあるブラウザは無応答(仮死)で、あるJavascriptコードが長時間運行されているため、ページカード全体がこの場所にあるため、他のタスクは実行できません.
ですから、非同期プログラミングはJavaScript言語にとって重要です.
一部の子供たちはまだ「非同期」をよく理解していないかもしれません.
「非同期」とは、一つの任務を二つの段階に分けて、最初の段階を実行して、他の任務を実行します.準備ができたら、また後ろに回って第二段を実行します.
例えば、ファイルを読み込んで処理するジョブがありますが、ジョブの最初のセグメントはオペレーティングシステムに要求し、ファイルの読み込みを要求します.その後、プログラムは他のタスクを実行し、オペレーティングシステムがファイルに戻ってから、タスクの第二段(処理ファイル)を実行します.このような不連続な実行は、非同期と呼ばれる.
したがって、連続して実行することを同期という.連続実行ですので、他のタスクを挿入できません.オペレーティングシステムがハードディスクからファイルを読み込むまでの間は、プログラムは待つしかありません.
話の通俗点:
朱自清の『後ろ姿』で、父は朱自清に対して言いました.「蜜柑をいくつか買いに行きます.ここにいます.歩かないでください.」
朱自清は歩いていません.ミカンを買った父が一緒にみかんを食べるのを待っています.同期といいます.
父を待たずに一人で行ったら、父と一緒にみかんを食べられない.
1、非同期プログラミング
私たちはユーザー登録という特に一般的なシーンを例にとって、非同期プログラミングについて説明します.
第一歩は、ユーザが登録されているかどうかを検証する.
第二ステップ、登録されていません.認証コードを送信します.
第三段階、検証コード、パスワードを記入し、検証コードが正しいかどうかを確認する.
この過程には一定の順序があります.前のステップが完成してこそ、次のステップがスムーズに進みます.
1.1コールバック関数
function testRegister(){} //
function sendMessage(){} // x
function testMessage(){} //
function doRegister(){ //
testRegister(data){
if(data===false){ //
}else{ //
sendMessage(data){
if(data===true){ //
testMessage(data){
if(data===true){ //
}else{ //
}
}
}
}
}
}
}
コードには既に多くの問題があります.例えば、乱雑なif判断文、幾重にもネストされた関数は、コードの可読性の差をもたらし、維持が困難です.また、度重なるコールバック関数に異常があったら、デバッグは非常に潰されます.try-catchは非同期の異常を捕まえられないので、私たちはデバッグを書いて追跡するしかないです.
このような幾重もの入れ子はリフロー地獄と呼ばれています.
1.2 Promise方式
Promiseは地獄問題を解決するために提出されました.これは新しい文法機能ではなく、新しい書き方です.コールバック関数のネストをチェーン式呼出しに変えられます.Promiseを採用し、複数のファイルを連続して読み込み、次のように書きます.
let state=1; //
function step1(resolve,reject){
console.log('1. ');
if(state==1){
resolve(' ');
}else{
reject(' ');
}
}
function step2(resolve,reject){
console.log('2. ');
if(state==1){
resolve(' ');
}else{
reject(' ');
}
}
function step3(resolve,reject){
console.log('3. ');
if(state==1){
resolve(' ');
}else{
reject(' ');
}
}
new Promise(testRegister).then(function(val){ //
console.log(val);
return new Promise(sendMessage); //
}).then(function(val){
console.log(val);
return new Promise(testMessage); //
}).then(function(val){
console.log(val);
return val;
});
コールバック関数は、ネスト方式で、testRegister()、sendMessage()とtestMessage()を順次呼び出し、Promiseはthenを使ってそれらをリンクします.Promiseコードの読み取り可能性は、コールバック関数よりも高く、コードの実行順序は一目瞭然です.
Promiseの方式は地獄を転調しましたが、最大の問題はコード冗長で、元の任務はPromiseに包装されました.どんな操作でも、一目で見たらthenがいっぱいになり、元の意味がよく分かりません.コードフローは実行フローをよく表していません.
みんなは中学校で電気回路を習ったことがあります.これは電気回路の直列のようです.習ったことがないなら大丈夫です.jqueryにチェーン操作があると知っています.これはチェーン操作の書き方に似ています.
1.3 async/await方式
async文法はnew Promiseの包装に対してで、await文法はthen方法に対する洗練です.
async function doRegister(url) {
let data = await testRegister(); //
let data2 = await sendMessage(data); //
let data3 = await testMessage(data2); //
return data3
}
上のコードは短いですが、どれも重要です.dataはawait testRegisterの返却結果、data 2はsendMessageのパラメータとしてdataを使用し、data 3はtestMessageのパラメータとしてdata 2を使用した.doregisterの前にキーワードasyncをつければ、関数内の非同期タスクの前にawait声明を追加すればいいです.これらの追加のキーワードを無視すれば、ほぼ完全な同期の書き方です.
2、asyncの使い方
2.1 Promiseオブジェクトに戻る
async関数はPromiseオブジェクトを返します.
async関数の内部return文で返した値は、thenメソッドのコールバック関数のパラメータになります.
async function f() {
return 'aaa';
}
f().then(v => console.log(v))
//aaa
//Promise {: undefined}
2.2 await命令通常、awaitコマンドの後にPromiseオブジェクトがあり、そのオブジェクトの結果に戻ります.Promiseオブジェクトでない場合は、直接に対応する値を返します.
/* */
async function f() {
return await 123;
}
f().then(value => console.log(value)); // 123
/* */
async function f() {
return Promise.reject('error');
}
f().catch(e => console.error(e)); // error
注意事項:await命令はasync関数でしか使えません.普通の関数で使うと、エラーが発生します.
/* */
function f(db) {
let docs = [1, 2, 3];
for(let doc of docs) {
await db.push(doc);
}
return db; // Uncaught SyntaxError: Unexpected identifier
}
/* ( ) */
async function f(db) {
let docs = [1, 2, 3];
for(let doc of docs) {
await db.push(doc);
}
return db;
}
2.3 asyncにおける異常処理async/awaitを使うことによって、私達はtry/catchと協力して非同期の作業中の問題を捕獲できます.Promiseの中でrejectのデータを含みます.
awaitの後ろにrejectがあるかもしれません.try...catchコードブロックの中で
async function f() {
try {
await Promise.reject(' ');
} catch(e) {
console.error(e);
}
return Promise.resolve('hello');
}
f().then(v => console.log(v)); // hello
3、並列中のawaitasync/await文法は確かに簡単で使いやすいですが、使い方も間違えやすいので、具体的なビジネスシーンの需要によって決めます.
例えば、画像のサイズ情報を取得したいです.
async function allPicInfo (imgs) {
const result = [];
for (const img of imgs) {
result.push(await getSize(img));
}
}
コードの中では、getSizeを呼び出すたびに、前回の呼び出しが完了するのを待つ必要があります.同じように性能が無駄で、しかも時間がかかります.同じ機能を使うと、このような方法がより適切です.async function allPicInfo (imgs) {
return Promise.all(imgs.map(img => getSize(img)));
}
複数の非同期動作が、継承関係がない場合は、同時にトリガすることが望ましい.4、まとめ
最初のコールバック関数からPromiseオブジェクトに至るまで、毎回改善されていますが、中途半端な感じがします.それらはいずれも追加的な複雑さがあり、抽象的な底部の動作機構を理解する必要がある.
例えば、3つの要求が発生する必要があり、第3の要求は第2の要求の結果に依存し、第2の要求は第1の要求の結果に依存する.ES 5で実現すれば、3層のコールバックがあり、コードの横方向発展をもたらします.Promiseで実現するには少なくとも3つのthenが必要で、コードの縦方向の発展をもたらします.しかし、async/awaitはこれらの問題を解決しました.
実現してきたasync/awaitは、ジェネレータ、Promiseに基づいて構築された新しい文法です.
しかし、async/awaitを軽視しないでください.同期方式で非同期コードを書くのはとても強いです.
async/awaitは語義化、コードの簡略化、エラー処理などの面で多くの利点があります.async/waitで条件コードを作成するのは簡単で、同じコード構造(周知のtry/catch文)を使って同期と非同期エラーを処理することができます.だから、JavaScript異歩プログラミングの最終解決案と呼ばれています.その重要性と利点が分かります.
今後の実戦プロジェクトで、たくさん練習してこそ、async/awaitの真の技術を身につけることができると思います.