Promise的使用和特點
- Promise是一個構造函數,接收一個函數(executor)作為參數,這個函數的參數有兩個,resolve,reject
- executor是立即執(zhí)行函數,也就是在new Promise的時候,在Promise構造函數中直接被調用的
- resolve, 是內部創(chuàng)建的函數,用戶調用該函數可以讓promise變成成功態(tài)(fufilled)
- reject,是內部創(chuàng)建的函數,用戶調用該函數可以讓promise變成失敗態(tài)(rejected)
- promise有三種狀態(tài),默認是padding(等待態(tài))、成功態(tài)(fufilled)、失敗態(tài)(rejected)
- 狀態(tài)不可逆,一旦成功就不能失敗,一旦失敗就不能成功
- 常用的then方法
- 是原型方法
- then方法調用接收兩個參數作為參數,1. onFulfilled / 2. onRejected
- then方法支持鏈式調用,可以一直.then().then()....
- then方法的兩個參數onFulfilled和onRejected的返回值,會作為下一次then的結果,如果返回值是一個promise,會解析這個promise,將promise的結果作為下一次then的結果
// 1. 創(chuàng)建promise實例
const p = new Promise((resolve, reject) => {
// 直接執(zhí)行的邏輯...
})
p.then(res => {
return 100
return new Promise((resolve, reject) => { resolve('hello') })
}).then(res => {
console.log(res) // 100 / 'hello'
})
Promise A+ 規(guī)范,實現符合規(guī)范的promise
實現流程:
- Promise是一個構造函數,參數是一個executor函數
- executor的參數是resove和reject
- promise的三個狀態(tài),狀態(tài)不可逆
- promise的兩個值:1. 成功的value 2. 失敗的原因reason
- executor中邏輯異步的處理,使用發(fā)布訂閱的模式處理異步
- then方法中兩個參數onFulfilled和onRejected的返回值的處理,使用resolvePromise來遞歸解析promise
實現代碼:
class Promise {
constructor(executor) {
// promise 的三個狀態(tài) padding fulfilled rejected
this.value = null;
this.reason = null;
this.fulfilledCbs = []; // 成功回調
this.rejectedCbs = [];
this.status = 'padding'
const resolve = (value) => {
if (this.status === 'padding') {
this.status = 'fulfilled';
this.value = value
for (let i = 0; i < this.fulfilledCbs.length; i++) {
const fn = this.fulfilledCbs[i];
fn()
}
}
}
const reject = (reason) => {
if (this.status === 'padding') {
this.status = 'rejected'
this.reason = reason
for (let i = 0; i < this.rejectedCbs.length; i++) {
const fn = this.rejectedCbs[i];
fn()
}
}
}
try {
executor(resolve, reject)
} catch (e) {
reject(e)
}
}
// then 方法返回一個新的promise,叫promsie2
// then 方法中的回調函數返回值可以是普通值或者promsie,如果是promise,會解析promise的值作為下一次then的值
then(onFulfilled, onRejected) {
const isFunction = val => typeof val === 'function';
onFulfilled = isFunction(onFulfilled) ? onFulfilled : (value) => value; // 將then的結果透傳給下一次then
onRejected = isFunction(onRejected) ? onRejected : (error) => {
throw error
}
let promise2; // then方法返回的promise叫promise2
if (this.status === 'padding') { // 說明executor中的邏輯是異步執(zhí)行的
promise2 = new Promise((resolve, reject) => {
this.fulfilledCbs.push(() => {
setTimeout(() => {
try {
// then方法回調的返回值叫做x
const x = onFulfilled(this.value)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
this.rejectedCbs.push(() => {
setTimeout(() => {
try {
// then方法回調的返回值叫做x
const x = onRejected(this.reason)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
})
} else if (this.status === 'fulfilled') {
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// then方法回調的返回值叫做x
const x = onFulfilled(this.value)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
} else if (this.status === 'rejected') {
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
// then方法回調的返回值叫做x
const x = onRejected(this.reason)
resovlePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
})
}
return promise2;
}
}
function resovlePromise(promise2, x, resolve, reject) {
// 返回的x可能是一個promise,但是一定不能和promise2相同
if (promise2 === x) {
return reject(new TypeError("same promise"));
}
// 分析x的值,可能是一個普通的值,可能是一個promise
// 1. 如果 x 是一個 promise,使用它的狀態(tài)
if (x instanceof Promise) {
x.then(val => {
// y有可能也是一個promise,遞歸解析
resovlePromise(promise2, val, resolve, reject)
}, reject)
}
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
let flag = false;
if (typeof then === 'function') {
try {
// x 作為this調用then
then.call(x, y => {
if (!flag) {
resovlePromise(promise2, y, resolve, reject)
flag = true;
}
}, r => {
if (!flag) {
reject(r)
flag = true;
}
})
} catch (e) {
if (!flag) {
reject(e)
flag = true;
}
}
} else {
resolve(x)
}
} catch (e) {
reject(e)
}
} else {
resolve(x)
}
}
測試promise
- 增加測試代碼
Promise.deferred = function () {
let def = {};
def.promise = new Promise(function (resolve, reject) {
def.resolve = resolve;
def.reject = reject;
});
return def;
}
module.exports = Promise
- 安裝測試包
npm install -g promises-aplus-tests
promises-aplus-tests promise.js