Promises / A +仕様
最新のJavaScriptインフラストラクチャの一部として、Promiseはフロントエンド開発者にとって非常に重要です。
これは、async / await構文の基礎であり、JavaScriptで非同期を処理する標準形式です。さらに、将来のWeb APIは、非同期である限り、Promisesの形式で表示されます。
Promisesの知識と操作メカニズムを理解していないと、将来的にWeb開発の日常業務を完了できなくなる可能性があります。
したがって、Promisesは、フロントエンドのインタビューで必ず尋ねる質問の1つになっています。インターネットでは、多くのPromises技術記事を検索することもできます。セールスポイントとしてPromises / A +仕様を最初から実装する方法を教えるフロントエンドの有料チュートリアルもあります。
Promisesをすでに理解している開発者にとって、Promises / A +の実装は有用なトレーニングです。
予備作業
用語を理解する
1.1 “promise” is an object or function with a then method whose behavior conforms to this specification.
1.2 “thenable” is an object or function that defines a then method.
1.3 “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
1.4 “exception” is a value that is thrown using the throw statement.
1.5 “reason” is a value that indicates why a promise was rejected.
仕様の最初の部分では、いくつかの用語の意味について説明しています。
promiseは、仕様で指定された動作に準拠するthenメソッドを含むオブジェクトまたは関数です。
Thenableは、thenとオブジェクトまたは関数を含むメソッドです。
valueは、正当なJS値です。
例外は、throwステートメントによってスローされる値です。
reasonは、promiseが拒否された理由を示す値です。
約束のステータス
A promise must be in one of three states: pending, fulfilled, or rejected.
2.1 When pending, a promise:
2.1.1 may transition to either the fulfilled or rejected state.
2.2 When fulfilled, a promise:
2.2.1 must not transition to any other state.
2.2.2 must have a value, which must not change.
2.3 When rejected, a promise:
2.3.1 must not transition to any other state.
2.3.1 must have a reason, which must not change.
約束には3つの状態があり、それらは保留中、履行済み、および拒否されます。
保留状態では、promiseを履行または拒否に切り替えることができます。
フルフィルド状態では、他の状態に移行することはできず、不変の値を持っている必要があります。
拒否された状態では、別の状態に移行することはできず、不変の理由が必要です。
次にメソッド
A promise must provide a then method to access its current or eventual value or reason.
A promise’s then method accepts two arguments:
promise.then(onFulfilled, onRejected)
promiseには、onFulfilledパラメーターとonRejectedパラメーターを受け入れるthenメソッドが必要です。
onFulfilledのパラメーターはvalueであり、onRejected関数のパラメーターはreasonです。
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
// 执行器
this.status = PENDING
this.value = undefined
this.reason = undefined
let resolved = (value) => {
if (this.status === PENDING) {
this.value = value
this.status = RESOLVED
}
}
let rejected = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED
}
}
try {
executor(resolved, rejected)
} catch (e) {
rejected(e)
}
}
then(onFulfilled, onRejected) {
if (this.status === RESOLVED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
非同期状況の処理
class Promise {
constructor {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.status === PENDING) {
this.value = value;
this.status = RESOLVED;
this.onFulfilledCallbacks.forEach(fn => fn()); // 订阅
}
}
let reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
// 根据x的值来判断promise2的状态
setTimeout(() => {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
}, 0);
}
if (this.status === REJECTED) {
onRejected(this.reason);
}
// 处理异步的情况
if (this.status === PENDING) {
//发布订阅模式
this.onFulfilledCallbacks.push(() => {
onFulfilled(this.value);
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason);
})
}
})
return promise2;
}
}
約束の解決手順
[外部リンク画像の転送に失敗しました。元のサイトにヒル防止リンクメカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします(img-pQiIDhqv-1614052331001)(…/…/ .vuepress / public / img / promise .jpg)]
最初のステップで、結果が現在のプロミス自体である場合、TypeErrorがスローされます。
2番目のステップでは、結果が別の約束である場合、その状態と結果の状態が使用されます。
結果がthenableオブジェクトである場合の3番目のステップ。最初にthen関数を取得し、次にthen関数を呼び出して、Promise ResolutionProcedureプロセスに再度入ります。
const resolvePromise = (promise2, x, resolve, reject) => {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>]'));
}
if(typeof x === 'object' && x !== 'null' || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
resolve(y);
}, r => {
reject(r);
})
}
} catch (e) {
reject(e);
}
let then = x.then;
} else {
resolve(x);
}
}
総括する
手作業で約束を実行できることは、約束に習熟するのに役立ちません。Promise / A +仕様は、実装方法に焦点を当てています。使い方ではありません。
約束に習熟したい場合は、日々の開発のさまざまな非同期シナリオについて、より多くのことを考え、訓練する必要があります。