一、 什么是Promise躏吊?
Promise
是異步編程的一種解決方案:從語法上講氛改,Promise
是一個(gè)對(duì)象,從它可以獲取異步操作的消息比伏;從本意上講胜卤,它是承諾,承諾它過一段時(shí)間會(huì)給你一個(gè)結(jié)果凳怨。Promise
有三種狀態(tài):pending(等待態(tài))
瑰艘,fulfiled(成功態(tài))
,rejected(失敗態(tài))
肤舞;狀態(tài)一旦改變紫新,就不會(huì)再變。創(chuàng)造Promise
實(shí)例后李剖,它會(huì)立即執(zhí)行芒率。
二、Promise/A+規(guī)范
詳細(xì)介紹了該
then
方法的行為篙顺,提供了可互操作的基礎(chǔ)偶芍,所有Promises/A+
兼容的Promise
實(shí)現(xiàn)都可以依靠該基礎(chǔ)來提供。因此德玫,該規(guī)范應(yīng)被認(rèn)為是非常穩(wěn)定的匪蟀。盡管Promises/A+
組織有時(shí)會(huì)通過向后兼容的微小更改來修訂此規(guī)范,以解決新發(fā)現(xiàn)的極端情況宰僧,但只有經(jīng)過仔細(xì)考慮材彪,討論和測(cè)試之后,我們才會(huì)集成大型或向后兼容的更改琴儿。
三段化、Promise的實(shí)現(xiàn)
1. Promise是具有then行為符合本規(guī)范的方法的對(duì)象或函數(shù)。
const promise = new Promise((resolve, reject) => {
// 異步處理操作
// 處理結(jié)束后調(diào)用resolve或reject
})
2. Promise States
Promise
是一個(gè)狀態(tài)機(jī)造成,有三種狀態(tài)分別是pending(等待)
显熏、fulfilled(完成態(tài))
、rejected(失敗態(tài))
晒屎。當(dāng)Promise
處于完成或者失敗狀態(tài)時(shí)喘蟆,它的狀態(tài)不可變
const PENDINT = 'pending';
const FULFILLED = 'fulfilled'; // 處于此狀態(tài)時(shí),狀態(tài)不可變
const REJECTED = 'rejected'; // 處于此狀態(tài)時(shí)鼓鲁,狀態(tài)不可變
3.1 then方法
Promise
必須提供一種then
訪問其當(dāng)前或最終價(jià)值或原因的方法蕴轨。then
方法接受兩個(gè)參數(shù),并且這兩個(gè)必須是方法坐桩,且都有默認(rèn)值
promise.then(onFulfilled, onRejected);
3.2 then必須返回一個(gè)Promise
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {
// 這里對(duì)返回值進(jìn)行處理
})
return promise2;
}
3.2.1 如果
onFulFilled
或者onRejected
返回一個(gè)值x
尺棋,需要對(duì)返回值進(jìn)行處理
3.2.2 如果任何一個(gè)onFulFilled
或onRejected
發(fā)生異常e
,則promise2
必須以e
為異常為onRejected
理由
4. Promise Resolution Procedure
// 使用此函數(shù)對(duì)promise2和x進(jìn)行處理
// 在`resolvePromise`函數(shù)中進(jìn)行處理時(shí),需要添加一個(gè)變量進(jìn)行`Promise state`控制
resolvePromise(promise2, x, resolve, reject);
4.1 如果
x
和promise2
是同一個(gè)Object
膘螟,則拋出類型錯(cuò)誤if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise #<Promise>')) }
4.2 如果
x
是不為null
的對(duì)象或者函數(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 包裹,如果有錯(cuò)誤荆残,則調(diào)用reject }else{ // 如果`x`只是一個(gè)普通的值奴艾,則返回即可 resolve(x); }
5. My Promise 的全部實(shí)現(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ì)死循環(huán)
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 如果 x 是不為Null對(duì)象或者函數(shù)
if (typeof x === 'object' && x !== null || typeof x === 'function') {
let called; // promise2的調(diào)用限制内斯,防止多次調(diào)用成功和失敗
// 去取值的then蕴潦,可能會(huì)出錯(cuò),使用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中很可能再次返回一個(gè)Promise實(shí)例
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)有錯(cuò)誤,則直接拋出
try {
execute(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
// 判斷是不是函數(shù)真朗,如果是函數(shù)此疹,則往下執(zhí)行,如果不是函數(shù)遮婶,則給一個(gè)函數(shù)蝗碎,返回當(dāng)前值
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) {
/**
* 這段邏輯不可抽離出去,抽離出去會(huì)報(bào)錯(cuò) cannot access 'promise2' before initialization
* 猜測(cè)可能在執(zhí)行函數(shù)旗扑,將抽離出去的代碼返回時(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'
}