メインコンテンツへ移動

手を動かして promise を実装

無料2015-12-13#JS#Tool#promise polyfill#JavaScript Promise Polyfill#promise workaround#promise兼容方案#promise内部原理剖析

js の promise は promise A+ 規範の 1 つの実装に過ぎず、自分で実装することもでき、いわゆる polyfill が得られます

一.インターフェース分析

###1.コア機能

  • resolve(value)/reject(err)

コンストラクタパラメータ resolve/reject は静的メソッドでもインスタンスメソッドでもありませんが、データエントリーポイントであるため、promise API のコアです。promise メカニズムの大部分の秘密はここにあり、すべての公開インターフェースはこれを基に動作します

  • then(onFulfilled, onRejected)

resolve/reject 以外に、then は絶対に最も重要です。他のすべてのインスタンスメソッド/静的メソッドは必須ではありませんが、then は不可欠です。言い換えれば、new Promise できて then もサポートできれば、promise メカニズム全体が完成し、他のインターフェースはすべて錦上添花のもので、promise をより使いやすくするだけです

###2.インスタンスメソッド

  • catch(onRejected)

promise.then(null, onRejected) と等価で、ユーザーは少し少ないコードを書け、同時に意味を付与します(catch error)

###3.静的メソッド

  • Promise.resolve(value)

wrapper を提供し、value が Promise インスタンスかどうかわからない時に、このメソッドを使用して包装された Promise インスタンスを取得できます。内部メカニズムは比較的複雑で、詳細情報は [6.Promise.resolve(value) 解決](/articles/完全理解 promise/#articleHeader14) を参照

  • Promise.reject(reason)

同様に wrapper を提供し、否定 Promise を作成するショートカット方式で、内部メカニズムは Promise.resolve(value) よりずっとシンプルです

  • Promise.all(iterable)

すべて正常に完了するか、またはエラーで中断され、未完成のものはすべて停止

  • Promise.race(iterable)

「競争」、結果が肯定か否定かに関わらず、最も速いもののみ

###4.高度機能

  • 結果自動後投げ

     // 错误后抛
     new Promise(function(resolve, reject) {reject('x')})
     .then(null)
     .then(null)
     .catch(function(err) {console.log(err)})
     // 值后抛
     new Promise(function(resolve, reject) {resolve('x')})
     .catch(null)
     .catch(null)
     .then(function(future) {console.log(future)})
    

エラーは最後の catch に投げられ、「食べられ」なければ自動的に後投げされ、最後に「食べられる」か、トップ層に投げられてエラー報告

  • 結果自動外投げ

     // 外层 then 能够拿到内层 future 和 error
     new Promise(function(resolve, reject) {
         resolve(new Promise(function(resolve, reject) {
             resolve(12);
             // reject(new Error('reject in nested Promise'));
         }).then(function(future) {
             return future + 1;
         }, function(error) {
             return new Error('reject again in nested Promise');
         }));
     }).then(onFulfilled, onRejected);
    

外層の then は内層の future と error を取得でき、手動で状態を維持する必要を避け、エラー集中処理にも有利

二.難点

難点は promise メカニズム自体が非同期であることです。例は以下の通り:

var p = new Promise(function(resolve, reject) {resolve(1)}).then(function(future) {return 2;});
// 立即输出 p
console.log(p);
// 1s 后输出 p
setTimeout(function() {
    console.log(p);
}, 1000);

即時出力の結果は:

// console
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}

1 秒後出力の結果は:

// console
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2}

このような非同期メカニズムの下で、returnthrow はどちらも問題になります。例えば:

// 异步
function nextTick(fn) {
    setTimeout(fn, 0);
}
// test
try {
    nextTick(function() {
        throw new Error('x');
    });
}
catch (err) {
    console.log('err: ' + err.message);
}

結果はエラーを catch できず、x はトップ層に投げられ、コンソールに表示されます。try..catch を入れることを簡単に考えられます。はい、エラーは確かに catch されましたが、どのように外層に通知すればよいでしょうか?

returnthrow はすべて値伝達の手段で、非同期環境では直接使用できず、自分で 1 つの値伝達メカニズムを実装する必要があります。これが難点です

P.S. ある記事で try...catch の欠点について言及しています。詳細情報は 前端コード異常監視 を参照

三.プロジェクトアドレス

アドレス:ayqy / myPromise - コードホスティング - オープンソース中国コミュニティ

注意:現在バージョン(v0.1.0 2015/12/13)には大きな問題があり、絶対に直接使用しないでください。現在内部メカニズムは同期のためです

P.S. バージョンが使用可能に更新された時、筆者はここで説明します。それ之前は、より信頼できる taylorhakes/promise-polyfill · GitHub を使用することを推奨。非常に軽量な実装です

参考資料

  • [翻訳] We have a problem with promises:promise の実行メカニズムを理解すればこれらの問題は発生しません。4 種類の promise の違いについても言うことはありませんが、文中で言及されたエラーは注意に値します

コメント

コメントはまだありません

コメントを書く