咱们都知道,then
方法返回一个新的 promise
实例,这是实现链式调用的根本。javascript
为了在 promise
状态发生变化时(resolve
/ reject
被调用时)再执行 then
里的函数,咱们使用一个 callbacks
数组先把传给then的函数暂存起来,等状态改变时再调用。java
那么,怎么保证后一个 then
里的方法在前一个 then
(多是异步)结束以后再执行呢?数组
好比下面示例中,最后一个 then
应该在 2 秒后再打印,值为 2promise
var p1 = new MyPromise((resolve, reject) => {
console.log('hhh')
setTimeout(() => {
resolve(1)
}, 1000);
}).then(res => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(res+1)
}, 1000);
})
}).then(res => {
console.log(res);
return res;
})
复制代码
将传给 then
的函数和新 promise
的 resolve
一块儿 push
到前一个 promise
的 callbacks
数组中,达到承前启后的效果markdown
promise
完成后,调用其 resolve
变动状态,在这个 resolve
里会依次调用 callbacks
里的回调,这样就执行了 then
里的方法了then
里的方法执行完成后,返回一个结果,若是这个结果是个简单的值,就直接调用新 promise
的 resolve
,让其状态变动,这又会依次调用新 promise
的 callbacks
数组里的方法,循环往复。。若是返回的结果是个 promise
,则须要等它完成以后再触发新 promise
的 resolve
,因此能够在其结果的 then
里调用新 promise
的 resolve
then(onFulfilled, onReject){
// 保存前一个promise的this
const self = this;
return new MyPromise((resolve, reject) => {
// 封装前一个promise成功时执行的函数
let fulfilled = () => {
try{
const result = onFulfilled(self.value); // 承前
return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //启后
}catch(err){
reject(err)
}
}
// 封装前一个promise失败时执行的函数
let rejected = () => {
try{
const result = onReject(self.reason);
return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
}catch(err){
reject(err)
}
}
switch(self.status){
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
})
}
复制代码
then
里的回调方法是同步注册的,但注册到了不一样的 callbacks
数组中,由于每次 then
都返回新的 promise
实例(参考上面的例子和图)callbacks
数组中提早注册的回调那么,什么状况下一个 callbaks
数组中会有多个回调呢?异步
好比这种:
p1
完成时,注册在 p1
的 callbacks
中的函数依次执行
如下代码 1 秒后打印出 1, 2 秒后打印出 2函数
var p1 = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 1000);
})
var p2 =p1.then(res => { //p1完成时的回调1
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(res+1)
}, 1000);
})
}).then(res => {
console.log(res); // 2
return res+1;
})
p1.then(res => { // p1完成时的回调2
console.log(res); // 1
})
复制代码
可是,若是这么写:ui
var p1 = new MyPromise((resolve, reject) => {
console.log('hhh')
setTimeout(() => {
resolve(1)
}, 1000);
}).then(res => {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(res+1)
}, 1000);
})
}).then(res => {
console.log(res); // 2
return res+1;
})
p1.then(res => {
console.log(res); // 3
})
复制代码
最后一个 p1.then
是在最后才打印出来的,由于 p1
的返回值是第三个 promise
,最后一个 then
里的函数也是注册进了第三个 promise
的 callbacks
中。this
// 定义三种状态
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECT = 'REJECT';
class MyPromise {
constructor(fn){
// 初始化状态
this.status = PENDING;
// 将成功、失败的结果放在this上,便于then、catch访问
this.value = null;
this.reason = null;
// 成功态、失败态回调函数队列,同步调用then时将对应态的函数注册进去, 在状态变动的时候调用
this.onFulfilledCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if(this.status === PENDING){
this.status = FULFILLED;
this.value = value;
// 成功态回调函数依次执行
this.onFulfilledCallbacks.forEach(fn => fn(this.value))
}
}
const reject = (reason) => {
if(this.status === PENDING){
this.status = REJECT;
this.reason = reason;
// 失败态回调函数依次执行
this.onRejectedCallbacks.forEach(fn => fn(this.reason))
}
}
// 生成实例后当即调用fn
// 把内部的resolve和reject传入fn,用户可调用resolve和reject
try{
fn(resolve, reject);
}catch(err){
// fn执行出错,将错误内容用reject抛出去
reject(err)
}
}
then(onFulfilled, onReject){
// 实现值穿透 当then中传入的不是函数,则这个promise返回上一个promise的值
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onReject = typeof onReject === 'function' ? onReject : reason => { throw new Error(reason) }
// 保存前一个promise的this
const self = this;
return new MyPromise((resolve, reject) => {
// 封装前一个promise成功时执行的函数
let fulfilled = () => {
try{
const result = onFulfilled(self.value); // 承前
return result instanceof MyPromise? result.then(resolve, reject) : resolve(result); //启后
}catch(err){
reject(err)
}
}
// 封装前一个promise失败时执行的函数
let rejected = () => {
try{
const result = onReject(self.reason);
return result instanceof MyPromise? result.then(resolve, reject) : reject(result);
}catch(err){
reject(err)
}
}
switch(self.status){
case PENDING:
self.onFulfilledCallbacks.push(fulfilled);
self.onRejectedCallbacks.push(rejected);
break;
case FULFILLED:
fulfilled();
break;
case REJECT:
rejected();
break;
}
})
}
// Promise.prototype.catch就是Promise.prototype.then(null, onRejected)的别名
catch(onRejected){
return this.then(null, onRejected);
}
static resolve(value){
// 若是是promise实例,直接返回
if(value instanceof MyPromise){
return value;
}else{
// 若是不是promise实例,返回一个新的promise对象,状态为fulfilled
return new MyPromise((resolve, reject) => resolve(value))
}
}
static reject(reason){
// Promise.reject方法的参数会原封不动地做为reject的参数
return new MyPromise((resolve, reject) => reject(reason))
}
/** * Promise.all() 接受一个数组,返回一个promise对象 * 全部的promise状态变为FULFILLED,返回的promise状态才变为FULFILLED。 * 一个promise状态变为REJECTED,返回的promise状态就变为REJECTED。 * 数组成员不必定都是promise,须要使用Promise.resolve()处理。 */
static all(promiseArr){
const len = promiseArr.length;
const values = new Array(len);
let count = 0; // 记录已经成功的promise个数
return new MyPromise((resolve, reject) => {
for(let i=0; i<len; i++){
// Promise.resolve()处理,确保每个都是promise实例
MyPromise.resolve(promiseArr[i]).then(
val => {
values[i] = val;
count++;
if(count === len) resolve(values); // 若是所有执行完,改变promise的状态为FulFilled
},
err => {
reject(err)
}
)
}
})
}
static race(promiseArr){
return new MyPromise((resolve, reject) => {
promiseArr.forEach(item => {
MyPromise,resolve(item).then(
val => resolve(val),
err => reject(err)
)
})
})
}
}
复制代码