一、 什么是Promise?
Promise是異步編程的一種解決方案:從語法上講,Promise是一個對象,從它可以獲取異步操作的消息;從本意上講,它是承諾,承諾它過一段時間會給你一個結(jié)果。Promise有三種狀態(tài):pending(等待態(tài)),fulfiled(成功態(tài)),rejected(失敗態(tài));狀態(tài)一旦改變,就不會再變。創(chuàng)造Promise實例后,它會立即執(zhí)行。
二、Promise/A+規(guī)范
詳細介紹了該
then方法的行為,提供了可互操作的基礎(chǔ),所有Promises/A+兼容的Promise實現(xiàn)都可以依靠該基礎(chǔ)來提供。因此,該規(guī)范應(yīng)被認為是非常穩(wěn)定的。盡管Promises/A+組織有時會通過向后兼容的微小更改來修訂此規(guī)范,以解決新發(fā)現(xiàn)的極端情況,但只有經(jīng)過仔細考慮,討論和測試之后,我們才會集成大型或向后兼容的更改。
三、Promise的實現(xiàn)
1. Promise是具有then行為符合本規(guī)范的方法的對象或函數(shù)。
const promise = new Promise((resolve, reject) => {
// 異步處理操作
// 處理結(jié)束后調(diào)用resolve或reject
})
2. Promise States
Promise是一個狀態(tài)機,有三種狀態(tài)分別是pending(等待)、fulfilled(完成態(tài))、rejected(失敗態(tài))。當Promise處于完成或者失敗狀態(tài)時,它的狀態(tài)不可變
const PENDINT = 'pending';
const FULFILLED = 'fulfilled'; // 處于此狀態(tài)時,狀態(tài)不可變
const REJECTED = 'rejected'; // 處于此狀態(tài)時,狀態(tài)不可變
3.1 then方法
Promise必須提供一種then訪問其當前或最終價值或原因的方法。then方法接受兩個參數(shù),并且這兩個必須是方法,且都有默認值
promise.then(onFulfilled, onRejected);
3.2 then必須返回一個Promise
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// 這里對返回值進行處理
})
return promise2;
}
3.2.1 如果
onFulFilled或者onRejected返回一個值x,需要對返回值進行處理
3.2.2 如果任何一個onFulFilled或onRejected發(fā)生異常e,則promise2必須以e為異常為onRejected理由
4. Promise Resolution Procedure
// 使用此函數(shù)對promise2和x進行處理
// 在`resolvePromise`函數(shù)中進行處理時,需要添加一個變量進行`Promise state`控制
resolvePromise(promise2, x, resolve, reject);
4.1 如果
x和promise2是同一個Object,則拋出類型錯誤if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) }
4.2 如果
x是不為null的對象或者函數(shù),則需要做取值then操作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(err){ reject(err); } // 此過程中需要使用try catch 包裹,如果有錯誤,則調(diào)用reject }else{ // 如果`x`只是一個普通的值,則返回即可 resolve(x); }
5. My Promise 的全部實現(xiàn)代碼
let PENDING = 'PENDING';
let RESOLVE = 'RESOLVE';
let REJECT = 'REJECT';
const isPromise = (x) => {
if (typeof x === 'object' && x !== null || typeof x === 'function') {
if (typeof x.then === 'function') {
return true;
} else {
return false;
}
} else {
return false;
}
}
const resolvePromise = (promise2, x, resolve, reject) => {
// 判斷promise2 和 x 是否相等,如果相等則會死循環(huán)
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 如果 x 是不為Null對象或者函數(shù)
if (typeof x === 'object' && x !== null || typeof x === 'function') {
let called; // promise2的調(diào)用限制,防止多次調(diào)用成功和失敗
// 去取值的then,可能會出錯,使用try
try {
let then = x.then;
if (typeof then === 'function') {
// 如果是函數(shù),則去調(diào)用,調(diào)用要 call then user x
// y => resolve , r => reject
then.call(x, y => {
if (called) {
return;
}
called = true;
// resolve中很可能再次返回一個Promise實例
resolvePromise(promise2, y, resolve, reject);
// resolve(y)
}, r => {
if (called) {
return;
}
called = true;
reject(r);
})
} else {
if (called) {
return;
}
called = true;
resolve(x);
}
} catch (error) {
if (called) {
return;
}
called = true;
reject(error);
}
} else {
// 否則就是普通值
resolve(x);
}
}
class Promise {
constructor(execute = () => { }) {
// Promise整體狀態(tài)
this.status = PENDING;
// 成功回調(diào)
this.onFulfilledCb = [];
// 失敗回調(diào)
this.onREjectedCb = [];
let resolve = (value) => {
if (this.status === PENDING) {
this.status = RESOLVE;
this.value = value;
this.onFulfilledCb.forEach(cb => cb());
}
}
let reject = (value) => {
if (this.status === PENDING) {
this.status = REJECT;
this.value = value;
this.onREjectedCb.forEach(cb => cb());
}
}
// 如果執(zhí)行函數(shù)內(nèi)有錯誤,則直接拋出
try {
execute(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
// 判斷是不是函數(shù),如果是函數(shù),則往下執(zhí)行,如果不是函數(shù),則給一個函數(shù),返回當前值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err
};
let promise2 = new Promise((resolve, reject) => {
// 同步執(zhí)行
// 成功執(zhí)行
if (this.status === RESOLVE) {
/**
* 這段邏輯不可抽離出去,抽離出去會報錯 cannot access 'promise2' before initialization
* 猜測可能在執(zhí)行函數(shù),將抽離出去的代碼返回時,new Promise還沒有執(zhí)行完畢
*/
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
}
// 失敗執(zhí)行
if (this.status === REJECT) {
setTimeout(() => {
try {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
}
// 異步執(zhí)行
if (this.status === PENDING) {
this.onFulfilledCb.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
})
this.onREjectedCb.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error)
}
}, 0);
})
}
})
return promise2;
}
finally(cb) {
return this.then(
// 這里將 resolve.then返回,是為了保證 cb 中的代碼執(zhí)行完畢,返回then中返回的Promise
data => this.resolve(cb(data)).then(() => data),
err => this.resolve(cb(err)).then(() => { throw err; })
)
}
static resolve = (arg) => {
if (isPromise(arg)) {
let promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = arg.then();
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
reject(error);
}
}, 0);
})
return promise2;
} else {
return new Promise(resolve => {
resolve(arg);
})
}
}
static all = (values) => {
return new Promise((resolve, reject) => {
let arr = [];
let index = 0;
const pushIn = (key, data) => {
arr[key] = data;
index++;
if (index === values.length) resolve(arr);
}
for (let i = 0; i < values.length; i++) {
const item = values[i];
if (isPromise(item)) {
item.then(data => {
pushIn(i, data);
}, reject);
} else {
pushIn(i, item);
}
}
})
}
static defer = () => {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
static deferred = this.defer;
static author = 'lxh'
}