在看本文章之前,需要熟悉 promise 的使用,不了解 promise 使用的同学,可以先去学习 es6——promise
1. 初识 promise
首先我们知道 promise 是一个构造函数,这里我们用 es6 新特性 class 类来创建一个 promise。
class Promise {
constructor() {
}
}
module.exports = Promise;
我们在使用 promise 的时候知道要先创建 promise 实例,然后传入一个函数,函数里包括 resolve、reject 两个参数
var promise = new Promise((resolve, reject) => {
})
像是这样,那么我们就要在构造函数中接受这个函数,这里我们把函数参数命名为 excutor
class Promise {
constructor(excutor) {
excutor(resolve, reject)
}
}
module.exports = Promise;
2. promise 状态
让我们首先看一下 Promise/A+ 规范中要求
- promise 需要有三个状态 pending 、 fulfilled 、 rejected ,默认状态是 pending
- 当时 fulfilled 成功状态时,promise 不能转换为其他状态了,而却必须有一个返回值
- 当时 rejected 失败状态时,promise 不能转换为其他状态了,而却必须有一个失败原因
所以我们的 promise 构造函数现在是这样
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECTED = 'REJECTED';
class Promise {
constructor(excutor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
let resolve = (value) => {
if (this.state === PENDING) {
this.state = RESOLVE;
this.value = value;
}
}
let reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
}
}
excutor(resolve, reject)
}
}
module.exports = Promise;
3. promise then 方法
让我们看一下 promise/A+ 中的介绍 一个 promise 必须提供 then 方法来访问当前或最终的结果或原因 一个 promise 方法接收两个参数 onFulfilled, onRejected
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECTED = 'REJECTED';
class Promise {
constructor(excutor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
let resolve = (value) => {
if (this.state === PENDING) {
this.state = RESOLVE;
this.value = value;
}
}
let reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
}
}
excutor(resolve, reject)
}
then(onFulfilled, onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
if(this.state === RESOLVE) {
onFulfilled(this.value);
}
if(this.state === REJECTED) {
onRejected(this.reason);
}
}
}
module.exports = Promise;
到这里已经实现了同步 promise ,下面我们来实现异步 promise
4. 异步 promise 实现
当我们在 promise 里使用异步的时候 state 状态会一直是 pending 状态,这里我们可以先把成功和失败的函数先存到对应的数组中,等状态发生变化(resolve, reject)时我们在遍历调用,这就是一个发布订阅思想
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECTED = 'REJECTED';
class Promise {
constructor(excutor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.state === PENDING) {
this.state = RESOLVE;
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
excutor(resolve, reject)
}
then(onFulfilled, onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
if(this.state === RESOLVE) {
onFulfilled(this.value);
}
if(this.state === REJECTED) {
onRejected(this.reason);
}
if(this.state === PENDING) {
this.onResolvedCallbacks.push(() => onFulfilled(this.value))
this.onRejectedCallbacks.push(() => onRejected(this.reason))
}
}
}
module.exports = Promise;
4. promise 链式调用
解决完异步操作,我们来看看链式调用,当我们使用 promise 的时候会用到链式调用 then 方法来解决回调地狱,那么这是怎么实现的呢,其实就是我们 then 函数的返回值是一个新的 promise2 这样递归,我们就可以实现链式调用。
then(onFulfilled, onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if(this.state === RESOLVE) {
let x = onFulfilled(this.value);
resolve(x);
}
if(this.state === REJECTED) {
let x = onRejected(this.reason);
reject(x);
}
if(this.state === PENDING) {
this.onResolvedCallbacks.push(() => {
let x = onFulfilled(this.value);
resolve(x);
})
this.onRejectedCallbacks.push(() => {
let x = onRejected(this.reason);
reject(x)
})
}
})
return promise2;
}
x 的值可以是普通值,也可能是 promise ,这里我们需要判断 x 的值,这里我们写一个 resolvePromise 方法
then(onFulfilled, onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if(this.state === RESOLVE) {
setTimeout(() => {
let x = onFulfilled(this.value);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
},0)
}
if(this.state === REJECTED) {
setTimeout(() => {
let x = onRejected(this.reason);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
},0)
}
if(this.state === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
let x = onFulfilled(this.value);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
},0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
let x = onRejected(this.reason);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
},0)
})
}
})
return promise2;
}
}
由于 promise 会立即执行,导致我们不能直接获得 promise2 参数,这里我们用宏任务 setTimeOut 包裹一下,等微任务执行完才会执行宏任务,这样我们就会拿到 promise2 参数。
resolvePromise 函数
我们先看 promise/A+ 里的说明
let resolvePromise = (promise2,x,resolve,reject) => {
// 首先 x 值不能是 promise 自己
if(promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
}
// x 值是对象或者是函数
if(typeof x === 'object' && x !== null || typeof x === 'function') {
let called; // 防止多次调用
try {
let then = x.then;
if(typeof then === 'function') {
then.call(x, y => { // y 可能还是 promise 递归
if(called) {
return;
}
called = true;
resolvePromise(promise2, y, resolve, reject); // 采用 promise 成功结果的值向下传递
},r => {
if(called) {
return;
}
called = true;
reject(r);// 采用失败结果向下传递
})
} else {
resolve(x); // 说明x 是一个普通值 直接成功
}
} catch(e) {
if(called) {
return;
}
called = true;
reject(e);
}
} else {
resolve(x);
}
}
到这里基本就完成了一个简单的 promise,catch、resolve、reject、finally、all、race 方法放在完整 promise 代码中,大家可以看代码理解就可以了~
5. 完整 promise
const PENDING = 'PENDING';
const RESOLVE = 'RESOLVE';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.state = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = (value) => {
if (this.state === PENDING) {
this.state = RESOLVE;
this.value = value;
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.state === PENDING) {
this.state = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject)
} catch(e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : data => data;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.state === RESOLVE) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e)
}
},0)
}
if (this.state === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e)
}
},0)
}
if (this.state === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e)
}
},0)
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
// x 可能是普通纸 也可能是 promise
resolvePromise(promise2, x, resolve, reject);
} catch(e) {
reject(e)
}
},0)
})
}
})
return promise2;
}
catch(fn) {
return this.then(null, fn);
}
}
// resolve 方法
Promise.resolve = function(val){
return new Promise((resolve,reject)=>{
resolve(val)
});
}
// reject 方法
Promise.reject = function(val){
return new Promise((resolve,reject)=>{
reject(val)
});
}
// race 方法
Promise.race = function(promises){
return new Promise((resolve,reject)=>{
for(let i=0;i < promises.length;i++){
promises[i].then(resolve,reject)
};
})
}
// all 方法
Promise.all = function(values) {
return new Promise((resolve, reject) => {
let arr = [];
let index = 0;
function processData(key, value) {
arr[key] = value;
if(index++ == values.length) {
resolve(arr);
}
}
for(let i = 0; i < values.length; i++) {
let current = values[i];
if (isPromise(current)) {
current.then((data) => {
processData(i, data);
}, reject);
}else {
processData(i, current);
}
}
})
}
// finally 方法
Promise.prototype.finally = function(cb) {
return this.then(data => {
return Promise.resolve(cb()).then(() => data);
}, err => {
Promise.resolve(cb()).then(() => {
throw err;
});
})
}
const isPromise = (value) => {
if(typeof value === 'object' && value !== null || typeof value === 'function') {
if (typeof value.then === 'function') {
return true;
}else {
return false;
}
}
}
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') {
let called; // 内部测试
try {
let then = x.then;
if(typeof then === 'function') {
then.call(x, y => { // y 可能还是 promise 递归
if(called) {
return;
}
called = true;
resolvePromise(promise2, y, resolve, reject); // 采用 promise 成功结果的值向下传递
},r => {
if(called) {
return;
}
called = true;
reject(r);// 采用失败结果向下传递
})
} else {
resolve(x); // 说明x 是一个普通的对象 直接成功
}
} catch(e) {
if(called) {
return;
}
called = true;
reject(e);
}
} else {
resolve(x);
}
}
module.exports = Promise;