序文
Promiseと初めて接触したのは、Microsoftが2012年にWindows 8オペレーティングシステムをリリースし、HTML5を使用して興味深い態度でMetroアプリケーションを作成したときでした。当時、HTML5に提供されたWINJSライブラリの非同期インターフェイスはすべて約束の形でした。当時私が考えていたのは、マイクロソフトが再びいじくり回っていたということでした。
予想外に、2015年までに、約束は実際にES6標準に書き込まれました。さらに、調査では、JSプログラマーがこのことを非常に高く使用していることが示されています。
皮肉なことに、2012年にはメトロアプリケーション開発インターフェイスで広く約束されているMicrosoftとして、独自のブラウザIEは2015年に死ぬまで約束をサポートしていませんでした。Microsoftにはこのテクノロジーがないが、IEの治療を実際にあきらめているようです。 。 。
今振り返ってみると、その時点で約束を見ることで最も厄介なことは、初心者が信じられないほどであり、JSプログラマーによって最も広く賞賛されている機能でもあるということでした。その後、機能コールチェーンです。
次に、関数コールチェーンは、本質的に、順番に複数の非同期プロセスを呼び出すことです。この記事はこの時点から始まり、約束の特徴を研究し、学びます。
約束が解決しました
次のシナリオを考慮して、関数が2秒ずつ遅延し、ログの行を印刷してから3秒遅れ、4秒遅れ、ログの行を印刷します。これは他のプログラミング言語では非常に簡単なことですが、JSに入ることはより困難であり、おそらくコードは次のように記述されます。
var myfunc = function(){settimeout(function(){console.log( "log1"); setimeout(function(){console.log( "log2"); setimeout(console.log( "log3");}、4000);}、3000);}、2000);}ネストされた多層コールバック構造により、ここで典型的なピラミッド構造が形成されます。ビジネスロジックがより複雑な場合、それは恐ろしいコールバック地獄になります。
より良い認識があり、単純な関数を抽出する方法を知っている場合、コードは次のようになります。
var func1 = function(){setimeout(func2、2000);}; var func2 = function(){console.log( "log1"); setimeout(func3、3000);}; var func3 = function(){console.log( "log2"); setimeout(func4、4000);}; var func4 = function(){console.log( "log3");};これは少し良く見えますが、いつも少し奇妙に感じます。 。 。実際、私のJSレベルは限られているので、なぜこれをうまく書けないのかは言えません。なぜこれが良くないのか知っていれば、約束を発明した場合は、私に知らせてください。
それでは、ポイントに戻って、約束のことについて話しましょう。
約束の説明
ここでMDNの約束の説明を引用させてください:
Promiseオブジェクトは、繰延計算と非同期計算に使用されます。 Promiseオブジェクトは、完了していないが、将来完了すると予想される操作を表します。
Promiseオブジェクトは、Promiseオブジェクトが作成されたときに知られていない場合があります。非同期操作の成功または失敗の取り扱い方法を指定できます。これにより、非同期メソッドは同期方法のような値を返すことができます。非同期メソッドは、元の戻り値の代わりに元の返品値を含む約束オブジェクトを返します。
Promiseオブジェクトには次の状態があります。
•保留中:初期状態、非充填または拒否。
•満たされた:操作の成功。
•拒否:操作に失敗しました。
保留中の状態を持つ約束のオブジェクトは、成功した価値を持つ充実した状態または拒否された状態に障害メッセージを使用して変換することができます。状態が移行すると、メソッドが約束するように拘束されます。 (メソッドを結合する場合、約束オブジェクトがすでに充実した状態または拒否状態にある場合、対応する方法はすぐに呼び出されます。したがって、非同期操作の完了とその結合方法の間に人種条件はありません。)
より多くの説明と約束の例については、MDNの約束のエントリまたはMSDNの約束の入力を参照してください。
私たちの問題を約束して解決してみてください
上記の約束の理解に基づいて、ネストされた多層コールバックの背後にあるコードが愚かで維持が困難であるという問題を解決するためにそれを使用できることを知っています。上記の2つのリンクは、約束の構文とパラメーターについてすでに非常に明確です。ここでは繰り返さず、コードをアップロードします。
まず、比較的単純なケースを試してみましょう。これは、遅延とコールバックを1回だけ実行します。
new Promise(function(res、rej){console.log(date.now() + "start setimeout"); setimeout(res、2000);})。MSDNの例から違いはないようで、実行結果は次のとおりです。
$ node promistest.js1450194136374 start setimeout1450194138391タイムアウトコールバック
したがって、別の遅延を実行したい場合は、これを書くことができます。
new Promise(function(res、rej){console.log(date.now() + "start setimeout 1"); setimeout(res、2000);})。 3000)。それも正しく機能しているようです:
$ node promistest.js1450194338710 START SETTIMEOUT 11450194340720 TIMEOUT 1 CALL BACK145019434340720開始21450194343722タイムアウト2コールバック
しかし、コードは愚かでかわいいように見えますよね?漠然とピラミッドを構築しています。これは、約束を導入する目的に反します。
では、何が問題なのでしょうか。正しい姿勢は何ですか?
答えは、then functionの戻り値と、then functionのonfulfiled(またはoncompleted)コールバック関数に隠されています。
まず第一に、Then関数は新しいPromise変数を返し、このようにこの新しいPromise変数のThen関数を再度呼び出すことができます。
new Promise(...)。then(...).then(...)。then(...)。then(...)。then(...)。
当時の関数によってどのようなプロムが返されますかは、Fulfulfilledコールバックの返品値に依存します。
実際、OnfulFilledは通常の変数または別のPromise変数を返すことができます。
onfulfilledが通常の値を返す場合、関数はデフォルトの約束変数を返します。この約束のその後の関数を実行すると、約束がすぐに満たされ、整理された関数が実行され、onfulfiledエントリパラメーターは以前のonfulfiledの返品値です。
OnfulFilledがPromise変数を返す場合、そのPromise変数はThen関数の返品値として使用されます。
MDNとMSDNに関するドキュメントには、Then関数と整理された関数のこの一連の設定について明確な肯定的な説明がありません。公式ES6 Document ECMAScript 2015(第6版、ECMA-262)について。 。 。私は本当に自分のレベルを理解できません。専門家が公式文書の2つの返品値の説明を説明できる場合は、アドバイスのためにメッセージを残してください! ! !
したがって、上記は私のフリープレイであり、言語組織を説明するのは少し難しいです。コードを読んだ後に理解できます。
まず、通常の変数を返す場合:
new Promise(function(res、rej){console.log(date.now() + "start setimeout 1"); setimeout(res、2000);})。 arg);上記のコード実行結果は次のとおりです。
$ node promistest.js1450277122125 Start Settimeout 11450277124129 Timeout 1 Call Back1450277124129最後のオンフルフィルドリターン1024
少し面白いですが、それは鍵ではありません。重要なのは、Onfulfilled関数が約束変数を返すことです。これにより、複数の非同期プロセスを連続して呼び出すことが便利です。たとえば、2つの遅延操作を連続して実行することができます。
New Promise(function(res、rej){console.log(date.now() + "start setimeout 1"); setimeout(res、2000);})。 3000);})。実行結果は次のとおりです。
$ node promistest.js1450277510275 Start Setimeout 11450277512276 Timeout 1 Call Back1450277512276 Statimeout 2145027751515327タイムアウト2 Call Back
これが素晴らしいことではないと思うなら、それを何度かするのは問題ではありません。
New Promise(function(res、rej){console.log(date.now() + "start setimeout 1"); setimeout(res、2000);})。 3000);} 「タイムアウト3コールバック "); return new Promise(res、rej){console.log() +" start setimeout 4 "); setimeout(res、5000);});})。$ node promistest.js1450277902714 Start Settimeout 11450277904722 Timeout 1 Call Back14502777904725 Timeout 2 Call Back1450277907725 Call Back1450277907725 Start Setimout 3145027911730 TimeUt 3 Call 30 Call Setimeout 41450277916744 Timeout 4 Call Back
複数の遅延コールバック関数が整然とした方法で配置されており、人気のあるピラミッドのような構造はありません。コードは非同期プロセスを呼び出しますが、それらはすべて同期プロセスで構成されているように見えます。これが約束が私たちにもたらす利益です。
冗長コードを別々の関数に蒸留する良い習慣がある場合、それはさらに美しいものになります:
function timeout1(){return new Promise(function(res、rej){console.log(date.now() + "start timeout1"); setimeout(res、2000);} function timeout2(){return new promise(res、rej){console.log(date.log) + "start timeout2"; timeout3(){return new Promise(function(res、rej){console.log(date.now() + "start timeout2"); setimeout(res、3000);} function timeout3(){return new promise(res、rej){console.log(date.log) + "start timetimeout(); Timeout4(){return new Promise(function(res、rej){console.log(date.now() + "start timeout4"); setimeout(res、5000);} timeout1();} then(timeout2).then(timeout3).then(timeout4).then(timeout4)。 });$ node promistest.js1450278983342 Start Timeout11450278985343 Start Timeout2145027898356 Start Timeout4145027897370 Timout4 Callback
次に、Fulfulfilled関数の着信パラメーターを渡す問題を調査し続けることができます。
以前のOnfulfilled関数が通常の値を返す場合、この値はonfulfilled関数のエントリパラメーターであることをすでに知っています。次に、以前のOnfulFildがPromise変数を返した場合、OnfulFiledのエントリパラメーターはどこから生まれますか?
答えは、このOnfulfilled関数のエントリパラメーターは、以前の約束で解決関数が呼び出されたときに渡された値であるということです。
しばらくジャンプを受け入れられませんでしたよね?うまくやってみましょう。
まず第一に、関数のpromise.resolveとは何ですか? MDN上のZou Zouのステートメントを使用します
成功価値のあるPromiseオブジェクトを解きます。値が継続可能である場合(その後、つまり当時の方法で)、返された約束オブジェクトは値に「従う」でしょう
要するに、これは非同期コールが成功したときのコールバックです。
通常の非同期インターフェイスでコールバックがどのように見えるかを見てみましょう。たとえば、nodejsでfs.readfile(file [、options]、callback)を取ります。その典型的な呼び出し例は次のとおりです
fs.readfile( '/etc/passwd'、function(err、data){if(err)shrow err; console.log(data);});Fs.ReadFile関数の場合、成功したか失敗したかにかかわらず、コールバック関数のコールバックを呼び出すため、このコールバックは2つのパラメーター、つまり障害ERRの例外説明と成功に関するリターン結果データを受け入れます。
それで、私たちがPromiseを使用してこの読み取りの例を再構築する場合、ファイルをどのように書くべきですか?
まず、fs.readfile関数をカプセル化します。
function readfile(filename){return new Promise(function(resolve、requed){fs.readfile(filename、function(err、data){if(err){relejed(err);} else {resolve(data);}});});});}2番目は呼び出しです:
readfile( 'thefile.txt')
ファイルのコンテンツが通常、他の言語の読み取りファイルの同期コールインターフェイスに配置される場所を想像してください。関数の戻り値は正しいですか?答えが出ています、この決意のエントリの高麗人参は何ですか?非同期コールが成功した場合、それは返品値です。
この概念では、「以前の約束で解像度関数を呼び出すときに渡された値である」「onfulfilefild関数の入力パラメーターが渡される値」を理解することは難しくありません。しっかりしたタスクは、以前の非同期呼び出しが成功した後に結果を処理することであるためです。
悲しいかな、ついにまっすぐになりました。 。 。
要約します
この記事で説明されているキーポイントを要約するために、コードを使用してください。
関数callp1(){console.log(date.now() + "callp1"を開始する); return new promise(function(res、rej){setimeout(res、2000);});} function callp2(){console.log(date.now() + "start callp2"); return new Promise(function(res、rej){setimeout(function(){res({arg1:4、arg2: "arg2値"});}、3000);} function callp3(arg){console.log(date.now()) + "arg =" + arg); return new Promise(function(res、rej){setimeout(function(){res( "callp3");}、arg * 1000);});} callp1()。 value = " + json.stringify(ret)); return callp3(ret.arg1);})。 $ node promistest.js1450191479575 Start Callp11450191481597 Callp1 return1450191481599 Callp2 Return with Ret value = {"arg1":4、 ":" 41450191488610 ret value = callp3をwith with with callp3のcallp3Multi-Layerの非同期呼び出しを解決するためにPromiseを使用する上記の単純な学習体験は、私があなたと共有するすべてのコンテンツです。参照を提供できることを願っています。wulin.comをもっとサポートできることを願っています。