今回はJSを使ってPromiseライブラリを実装する方法を紹介します。JSを使ってPromiseライブラリを実装する際の注意点を以下に挙げます。
はじめに
ECMAScript は JavaScript 言語の国際標準であり、JavaScript は ECMAScript の実装です。 ES6 の目標は、JavaScript 言語を使用して大規模で複雑なアプリケーションを作成できるようにし、エンタープライズ レベルの開発言語になることです。
Concept
ES6 はネイティブに Promise オブジェクトを提供します。
いわゆる Promise は、非同期操作のメッセージを配信するために使用されるオブジェクトです。これは結果が将来になるまで分からないイベント (通常は非同期操作) を表し、このイベントはさらなる処理のための統合 API を提供します。
考えるべき 3 つの質問
私が最初にフロントエンドを書き始めたとき、私は非同期リクエストを処理するためにシンプルで便利なコールバックをよく使用しました。その後、私が書いたように、コールバックを放棄し、非同期の問題に対処するために Promise を使用し始めました。確かに Promise の方が美しく記述できますが、内部構造が深く理解されていないため、複雑な状況に遭遇するたびに Promise を使用するのは簡単ではなく、デバッグに時間がかかります。
そこで、この記事では、ゼロから始めて、基本的に使用可能な Promise を手書きで書く方法を説明します。これを書き留めると、Promise とは何か、その内部構造を明確に理解できるようになり、将来的には複雑なシナリオで Promise を使用できるようになります。
そして、皆さんが実際に Promise を完全にマスターしているかどうかをテストするために、記事の最後に Promise に関連した練習問題をいくつか示します。これらは演習であると言われていますが、実際には、誰もがプロジェクトで遭遇する実際のシナリオを抽象化したものであり、それらを上手に習得することで、誰もがフロントエンド スキルを向上させることができます。
3 つの練習問題が事前に提供されています。以下の内容は無視して、どのように解決するかを頭の中で大まかに想像してください。
Promise 配列の連鎖呼び出し?
Promise による同時実行性を制御するにはどうすればよいですか?
Promise を使用して非同期キャッシュを行うにはどうすればよいですか?
上記の 3 つの思考の問題は、実際には Promise を使用するかどうかとはあまり関係ありませんが、Promise を深く理解していないと、これら 3 つの問題を解決するのは実際にはそれほど簡単ではありません。
約束とは
本文に戻って、約束とは何ですか?率直に言うと、Promise は将来終了するイベント (通常は非同期操作) の結果を保存するコンテナです。
まず、ES6ではPromiseオブジェクトはPromiseインスタンスを生成するために使用されるコンストラクターであると規定されています。次に、このコンストラクターは関数 (実行プログラム) をパラメーターとして受け取ります。関数の 2 つのパラメーターは、resolve と request です。最後に、Promise インスタンスが生成された後、then メソッドを使用して、解決された状態と拒否された状態にそれぞれコールバック関数 (onFulfilled および onRejected) を指定できます。
具体的な使用方法は次のようなコードで表されます:
const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); promise.then(function(value) { // success }, function(error) { // failure });
これを理解した後、大胆に独自のプロミスの構築を開始できます: CutePromise
Promise を実装します: CutePromise
ES6 クラスを直接使用して CutePromise を作成します。ES6 構文に詳しくない場合は、戻る前に ES6 のコア構文を紹介する他の 2 つの記事を読んでください。 ES6/ES2015 のコアコンテンツを 30 分でマスターする (パート 1)、ES6/ES2015 のコアコンテンツを 30 分でマスターする (パート 2)
class CutePromise { // executor是我们实例化CutePromise时传入的参数函数,它接受两个参数,分别是resolve和reject。 // resolve和reject我们将会定义在constructor当中,供executor在执行的时候调用 constructor(executor) { const resolve = () => {} const reject = () => {} executor(resolve, reject) } // 为实例提供一个then的方法,接收两个参数函数, // 第一个参数函数必传,它会在promise已成功(fulfilled)以后被调用 // 第二个参数非必传,它会在promise已失败(rejected)以后被调用 then(onFulfilled, onRejected) {} }
CutePromise を作成した後、重要なポイントを理解しましょう。約束のオブジェクト。
Promise オブジェクトは、独自の状態を通じて非同期操作を制御します。 Promise インスタンスには 3 つの状態があります:
非同期操作の保留中 (保留中)
非同期操作の成功 (満たされた)
非同期操作の失敗 (拒否)
上記 3 つの状態のうち、満たされたものと拒否された場合、それは解決済み (確定済み) と呼ばれます。ステータスを切り替えるには 2 つのパスしかありません。1 つは pending=>fulfilled からのもので、もう 1 つは pending=>rejected からのものです。ステータスが切り替わると、変更することはできません。
次に、CutePromise にステータスを追加しましょう。おおよそのプロセスは次のとおりです。
首先,实例化初始过程中,我们先将状态设为PENDING,然后当executor执行resolve的时候,将状态更改为FULFILLED,当executor执行reject的时候将状态更改为REJECTED。同时更新实例的value。
constructor(executor) { ... this.state = 'PENDING'; ... const resolve = (result) => { this.state = 'FULFILLED'; this.value = result; } const reject = (error) => { this.state = 'REJECTED'; this.value = error; } ... }
再来看下我们的then函数。then函数的两个参数,onFulfilled表示当promise异步操作成功时调用的函数,onRejected表示当promise异步操作失败时调用的函数。假如我们调用then的时候,promise已经执行完成了(当任务是个同步任务时),我们可以直接根据实例的状态来执行相应的函数。假如promise的状态还是PENDING, 那我们就将onFulfilled和onRejected直接存储到chained这个变量当中,等promise执行完再调用。
constructor(executor) { ... this.state = 'PENDING'; // chained用来储存promise执行完成以后,需要被依次调用的一系列函数 this.chained = []; const resolve = (result) => { this.state = 'FULFILLED'; this.value = result; // promise已经执行成功了,可以依次调用.then()函数里的onFulfilled函数了 for (const { onFulfilled } of this.chained) { onFulfilled(res); } } ... } then(onFulfilled, onRejected) { if (this.state === 'FULFILLED') { onFulfilled(this.value); } else if (this.state === 'REJECTED') { onRejected(this.value); } else { this.$chained.push({ onFulfilled, onRejected }); } }
这样我们就完成了一个CutePromise的创建,下面是完整代码,大家可以复制代码到控制台测试一下:
class CutePromise { constructor(executor) { if (typeof executor !== 'function') { throw new Error('Executor must be a function'); } this.state = 'PENDING'; this.chained = []; const resolve = res => { if (this.state !== 'PENDING') { return; } this.state = 'FULFILLED'; this.internalValue = res; for (const { onFulfilled } of this.chained) { onFulfilled(res); } }; const reject = err => { if (this.state !== 'PENDING') { return; } this.state = 'REJECTED'; this.internalValue = err; for (const { onRejected } of this.chained) { onRejected(err); } }; try { executor(resolve, reject); } catch (err) { reject(err); } } then(onFulfilled, onRejected) { if (this.state === 'FULFILLED') { onFulfilled(this.internalValue); } else if (this.$state === 'REJECTED') { onRejected(this.internalValue); } else { this.chained.push({ onFulfilled, onRejected }); } } }
提供一下测试代码:
let p = new CutePromise(resolve => { setTimeout(() => resolve('Hello'), 100); }); p.then(res => console.log(res)); p = new CutePromise((resolve, reject) => { setTimeout(() => reject(new Error('woops')), 100); }); p.then(() => {}, err => console.log('Async error:', err.stack)); p = new CutePromise(() => { throw new Error('woops'); }); p.then(() => {}, err => console.log('Sync error:', err.stack));
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上がJsを使用してPromiseライブラリを実装するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。