用法 ?
let p = new Promise((resolve, reject) => {
if (success) resolve('ok')
else reject('error')
})
p.then(
res => console.log('成功', res),
err => console.log('失敗', err)
)
.catch(err => console.log('失敗', err))
.finally(() => console.log('無論成功失敗都執行'))
Promise.resolve('ok')
Promise.reject('error')
Promise.all([p1, p2, p3]).then(res => {
// res 每個 promise 的結果組成的陣列
})
Promise.race([p1, p2, p3]).then(res => {
// 最早完成的 promise 的結果
})
複製程式碼
原理 ?
Promise
的狀態只能從pending => resolved
或 從pending => rejected
,狀態一旦改變不會再變- 要建立一個
Promise
物件,需要new Promise(executor)
,並傳入一個executor
,該函式預設有兩個方法引數(resolve, reject
),在executor
內執行使用者邏輯(非同步或同步程式碼),執行完根據成功/失敗情況呼叫resolve/reject
Promise
會根據Promise
物件當前的狀態決定走.then
中的onFullfilled/onRejected
(使用者傳入的成功處理函式、失敗處理函式)Promise
物件可以無限.then
則代表每次返回的都是一個新的Promise
物件,每個.then
函式返回的data
都會作為下一個.then
函式的引數
基本實現 ???
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// resolve 方法,將 Promise 物件的狀態改變為成功,並將成功值賦給 value 供給 .then方法的 onFullfilled 使用
let resolve = (value) => {
if (this.status === PENDING) {
this.status = RESOLVED;
this.value = value;
}
}
// reject 方法,將 Promise 物件的狀態改變未失敗,並將失敗值賦給 reason 供給 .then 方法的 onRejected 使用
let reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
// 捕獲同步程式碼產生的錯誤
try {
executor(resolve, reject);
} catch(e) {
reject(err)
}
}
// Promise 例項的 then 方法
then(onFullfilled, onRejected) {
// 如果狀態是 成功態,執行 成功的回撥
if (this.status === RESOLVED) {
onFullfilled(this.value)
}
// 如果狀態是 失敗態,執行 失敗的回撥
if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
複製程式碼
到這裡實現了最基本的狀態變更、資料儲存及成功或失敗的回撥呼叫,使用一下
let p = new Promise((resolve, reject) => {
resolve('ok')
})
p.then(res => console.log('成功', res)) // 成功ok
複製程式碼
加強 ?
Promise
中的 executor
支援非同步邏輯,即resolve/reject
並不是立即呼叫
// 增加非同步時回撥的儲存
class Promise {
constructor(props) {
// ...
this.onFullfilledCallbacks = []; // 儲存成功回撥
this.onRejectedCallbacks = []; // 儲存失敗回撥
let resolve = (value) => {
// ... 修改狀態,儲存 value 值
// 依次執行儲存的回撥函式
// 如果 resolve 的 value 是 Promise,則執行 .then 取到最終值再返回
if (value instanceof Promise) {
return value.then(resolve, reject)
}
this.onFullfilledCallbacks.forEach(fn => fn());
}
let reject = (reason) => {
// ...
this.onRejectedCallbacks.forEach(fn => fn());
}
}
then(onFullfilled, onRejected) {
// ...
// 如果是非同步,未立即修改 Promise 物件的狀態,儲存使用者傳入的成功、失敗回撥函式,
if (this.status === PENDING) {
this.onFullfilledCallbacks.push(() => {
// aop 切面思想,預留處理其它問題
onFullfilled(this.value)
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
複製程式碼
到這裡實現了存在非同步時,等待返回最終狀態再執行回撥,使用下
new Promise((resolve) => {
setTimeout(() => {
resolve('ok')
},2000)
}).then(res => console.log('2秒後', res)) // 等2秒後輸出結果
複製程式碼
加強 ??
Promise
支援無限鏈式呼叫,每次.then
又返回一個可以.then
的Promise
物件
function resolvePromise(promise2, x, resolve, reject) {
// promise2 === x 會造成迴圈呼叫直接拋錯
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 => {
resolvePromise(promise2, y, resolve, reject)
}, r => {
reject(r)
})
} else {
// 普通物件或普通函式
resolve(x)
}
} catch(e) {
reject(e)
}
} else {
// 普通值直接返回
resolve(x)
}
}
class Promise {
constructor(props) {
// ...
}
then(onFullfilled, onRejected) {
// 當未傳入 onFullfilled/onRejected 時,給預設函式
onFullfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
onRejected = typeof onFulfilled === 'function' ? onRejected: err => { throw err }
// 每次執行 .then 返回一個新的 Promise 物件
let promise2 = new Promise((resolve, reject) => {
if (this.status === RESOLVED) {
// 新增定時器是因為當處理當前結果時還取不到 promise2
setTimeout(() => {
// 捕獲非同步中出現的錯誤
try {
// 執行使用者的成功回撥,取到返回結果
let x = onFullfilled(this.value)
// 對返回結果進行統一處理
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
}
if (this.status === PENDING) {
this.onFullfilledCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFullfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch(e) {
reject(e)
}
}, 0)
})
}
})
return promise2;
}
}
複製程式碼
實現了
promise
鏈式呼叫then
返回Promise
物件時取到最終資料的處理- 異常捕獲處理
至此 Promise
的實現全部完成 ?,如果有幫助請點贊分享,感謝!
參考
- Promise a+ 規範 promisesaplus.com/