この記事は、主に約束の使用を普及させています。
長い間、JavaScriptは常にコールバックの形で非同期に処理しており、フロントエンド開発の分野でのコールバックメカニズムは、人々の心にほぼ深く根ざしています。 APIを設計するとき、ブラウザメーカー、SDK開発者、またはさまざまなライブラリの著者であるかどうかにかかわらず、基本的にコールバックルーチンに従います。
近年、JavaScript開発モデルの徐々に成熟しているため、Promise Specificificationの提案を含め、CommonJS仕様が生まれました。約束により、JS非同期プログラミングの執筆が完全に変わり、非同期プログラミングが非常に理解しやすくなりました。
コールバックモデルでは、非同期キューを実行する必要があると仮定し、コードは次のようになる可能性があります。
loadimg( 'a.jpg'、function(){loadimg( 'b.jpg'、function(){loadimg( 'c.jpg'、function(){console.log( 'all done');});});});これが私たちがしばしばピラミッドを呼び出すものです。多くの非同期タスクがある場合、多数のコールバックを維持することは災害になります。今日、node.jsは非常に人気があります。多くのチームは、「ファッション」と仲良くするために何かを作りたいと思っているようです。操作およびメンテナンスのクラスメートとチャットすると、彼らはnode.jsを使用して何かをすることも計画しましたが、JSのコールバックのレイヤーを考えると、彼らは落胆します。
さて、ナンセンスが終わりました、トピックに到達しましょう。
約束の仕様は長い間発表されており、約束がES6に含まれており、ChromeとFirefoxのブラウザのより高いバージョンがネイティブに約束を実装しているため、約束はすべての人に精通しているかもしれませんが、最近のPopual PromiseクラスライブラリよりもAPIが少ないです。
いわゆる約束は文字通り「約束」として理解できます。つまり、b、BはAに「約束」を返すことを意味し、Aは計画を書くときにこれを書くことができます。それどころか、Bが何らかの理由で望ましい結果を与えない場合、Aは緊急計画S2を実行して、すべての潜在的なリスクがAの制御可能な範囲内にあるようにします。
上記の文は、次のようなコードに翻訳されます。
var resb = b(); var runa = function(){resb.then(execs1、execs2);}; runa();上記のコード行を見るだけで、特別なものは何もないようです。しかし、現実はこれよりもはるかに複雑かもしれません。 1つのことを達成するために、Aは複数の人Bの応答に依存する場合があります。複数の人に同時に尋ね、すべての回答を受け取った後に次の計画を実装する必要がある場合があります。コードへの最終的な翻訳は次のようになるかもしれません:
var resb = b(); var resc = c(); ... var runa = function(){reqb。(resc、execs2).then(resd、execs3).then(rese、execs4)... .then(execs1);}; runa();ここでは、さまざまな処理メカニズムが使用されます。各照会された応答が、期待に沿っていない応答があります。実際、約束の仕様はこれを必要とせず、何もしない(つまり、その2番目のパラメーターで渡さない)、または均一に処理することさえできます。
OK、約束/A+仕様を知りましょう:
then方法を実装しなければなりません(それは約束の中核であると言えます)。その後、同じ約束が複数回呼び出すことができ、コールバックの実行命令は、定義されているときの順序と一致していますご覧のとおり、Promise仕様にはあまりコンテンツがありませんので、次のPromiseを自分で実装してみてください。
以下は、私が多くの約束ライブラリを参照したという約束の簡単な実装です。コードのPromiseaに移動してください。
アイデアの簡単な分析:
コンストラクターの約束は、非同期タスクを渡すと理解できる関数resolverを受け入れます。リゾルバーは2つのパラメーターを受け入れます。1つは成功したときのコールバック、もう1つは失敗したときのコールバックです。これらの2つのパラメーターは、当時通過したパラメーターに等しくなります。
2つ目は、その後の実装です。約束には約束を返す必要があるため、その後の呼び出されたときに新しい約束が生成され、現在の約束の_nextに掛けられます。同じ約束の複数の呼び出しは、以前に生成された_nextのみを返します。
Thenメソッドで受け入れられた2つのパラメーターはオプションであり、タイプに制限がないため、関数、特定の値、または別の約束になります。次の具体的な実装は次のとおりです。
promise.prototype.then = function(resolve、requed){var next = this._next || (this._next = promise()); var status = this.status; var x; if( 'phends' === status){isfn(resolve)&& this._resolves.push(resolve); isfn(拒否)&& this._rejects.push(reject);次に戻ります。 } if( 'Resolved' === status){if(!isfn(resolve)){next.resolve(resolve); } else {try {x = resolve(this.value); Resolvex(次、x); } catch(e){this.reject(e); }} return next; } if( '拒否' === status){if(!isfn(redject)){next.Reject(reject); } else {try {x = reject(this.reason); Resolvex(次、x); } catch(e){this.reject(e); }} return next; }};ここでは、他のPromiseクラスライブラリの実装を簡素化し、実装はこれよりもはるかに複雑であり、さらに機能があります。たとえば、3番目のパラメーターがあります - 通知は、現在の約束の進捗状況を示しています。これは、デザインファイルなどをアップロードするときに非常に役立ちます。興味のある学生は、他のタイプのPromiseライブラリの実装を参照できます。
その後、少なくとも2つの方法が必要である必要があります。つまり、保留から解決または拒否への約束の状態の変換を完了し、対応するコールバックキュー、つまりresolve()およびreject()メソッドを実行するためです。
この時点で、簡単な約束が設計されています。以下は、次の2つの約束された機能の簡単な実装です。
function sleep(ms){return function(v){var p = promise(); setimeout(function(){p.Resolve(v);}、MS); pを返します。 };};関数getimg(url){var p = promise(); var img = new Image(); img.onload = function(){p.resolve(this); }; img.onerror = function(err){p.reject(err); }; img.url = url; p;}を返します; Promise Constructorは非同期タスクをパラメーターとして受け入れるため、 getImg次のように呼ばれることもあります。
function getimg(url){return promise(function(resolve、rexy){var img = new image(); img.onload = function(){resolve(this);}; img.onerror = function(err){reject(err);}; img.url = url;});};};次に(奇跡を目撃する瞬間)、これを実装するためのBT要件があるとします:JSON構成を非同期に取得し、JSONデータを解析して写真を入力してから、写真を順番にロードし、写真がロードされないときにロード効果を与えます。
function addimg(img){$( '#list')。find( '> li:last-child')。html( '')。append(img);}; function prepend(){$( '<li>').html( 'loading ...').appendto( '#list'); getData( 'map.json').then(function(data){$( 'h4')。html(data.name); return data.list.reduce(function(promise、item){return promise .then(prepend).then(sleep(1000)).then(function(){return getimg(itemg); promise.resolve();}).then(sleep(300))。ここでの睡眠は、効果を確認するために追加されます。クリックしてデモを表示できます!もちろん、node.jsの例はここで見ることができます。
ここでは、 Promise.resolve(v)は、肯定的な結果としてVを使用して約束を返すだけです。 vを渡すことはできません。また、 thenを含む関数またはオブジェクトまたは関数(つまり、その後)にすることができます。
同様の静的方法には、 Promise.cast(promise)が含まれます。
Promise.reject(reason)否定的な結果として理由で約束を生成します。
実際の使用シナリオは非常に複雑である可能性があり、多くの場合、複数の非同期タスクを散在さ、並列、または連続的に実行する必要があります。この時点で、 Promise.all()の実装、約束のキューを受け入れ、継続する前に完了するのをPromise.any()など、さまざまな拡張機能を作成することができます。
html5rocks javascriptの約束でこの記事を参照できます。現在、ChromeやFirefoxなどの高度なブラウザにはPromiseオブジェクトが組み込まれており、 Promise.all()などのより多くの操作インターフェイスを提供し、Promiseアレイでのパスをサポートし、すべての約束が完了したら実行します。また、より友好的で強力な例外キャプチャもあります。これは、毎日の非同期プログラミングに対処するのに十分なはずです。
今日最も人気のあるJSライブラリは、Dojo、Jquery、Zepto、When.js、Qなど、さまざまな程度に約束を実施していますが、ほとんどの露出したオブジェクトDeferred 。 jQuery(Zepto同様)を例として、上記のgetImg()を実装します。
関数getimg(url){var def = $ .deferred(); var img = new Image(); img.onload = function(){def.resolve(this); }; img.onerror = function(err){def.reject(err); }; img.src = url; return def.promise();};もちろん、JQueryでは、 animateやajaxなどの多くの操作が延期または約束を返します。
// ajax $ .ajax(ofacity ':0}、1000).promise().then(console.log(' done ');}); // ajax $ .ajax(options).then(success、faile); $。ajax(options).done(success).fail(ajax(ajax); $ .ajax(options2)).then(function(){console.log( 'all done。');}、function(){console.error( '何か間違っています。');}); jQueryは、実際には当時のメソッドのショートカットであるdone()およびfail()メソッドを実装しています。
約束のキューを処理するために、jQueryは$.when()メソッドを実装し、その使用はPromise.all()に似ています。
他のクラスライブラリの場合、ここでは、.jsがほとんどコードを持っていない場合、約束を完全に実装し、ブラウザーとnode.jsをサポートし、より豊富なAPIを提供することができます。これは良い選択です。スペースの制限により、もう拡張しません。
約束の実装がどれほど複雑であっても、その使用法は非常に単純であり、組織コードは非常に明確であることがわかります。これからは、コールバックによって拷問される必要はありません。
最後に、約束はとてもエレガントです!しかし、約束は、コールバックの深いネスティングの問題のみを解決します。 JavaScriptの非同期プログラミングを本当に簡素化するのはジェネレーターです。 node.js側では、ジェネレーターを考慮することをお勧めします。
次の記事、研究ジェネレーター。
githubオリジナルテキスト:https://github.com/chemdemo/chemdemo.github.io/issues/6