手写promise
开始之前做以下思考:
对于promise,每天都在使用,那么promise到底是什么?promise如何保证异步执行完了再去执行后面的代码?promise的链式调用怎么保证?为什么能在异步事件执行完成的回调之后再去触发 then 中的函数?
-
promise 是什么? 答:异步回调解决方案
-
promise 如何保证异步执行完了再去执行后面的代码? 答:使用 then 关键字 then 接受两个参数 第一个参数(函数)会在 promise resolve 之后执行 第二个参数(函数)会在 promise reject 之后执行
-
为什么能在异步事件执行完成的回调之后再去触发 then 中的函数?答:引入事件注册机制(将 then 中的代码注册事件 当异步执行完了之后再去触发事件)
-
怎么保证 promise 链式调用 形如 promise.then().then() 答:每个 then 返回的也是一个 promise 对象
-
怎么知道异步事件执行完毕或者执行失败? 答:需要状态表示
以下为思路具体实现
//这里使用es6 class实现
class Mypromise {
constructor(fn) {
// 表示状态
this.state = "pending";
// 表示then注册的成功函数
this.successFun = [];
// 表示then注册的失败函数
this.failFun = [];
let resolve = val => {
// 保持状态改变不可变(resolve和reject只准触发一种)
if (this.state !== "pending") return;
// 成功触发时机 改变状态 同时执行在then注册的回调事件
this.state = "success";
// 为了保证then事件先注册(主要是考虑在promise里面写同步代码) promise规范 这里为模拟异步
setTimeout(() => {
// 执行当前事件里面所有的注册函数
this.successFun.forEach(item => item.call(this, val));
});
};
let reject = err => {
if (this.state !== "pending") return;
// 失败触发时机 改变状态 同时执行在then注册的回调事件
this.state = "fail";
// 为了保证then事件先注册(主要是考虑在promise里面写同步代码) promise规范 这里模拟异步
setTimeout(() => {
this.failFun.forEach(item => item.call(this, err));
});
};
// 调用函数
try {
fn(resolve, reject);
} catch (error) {
reject(error);
}
}
// 实例方法 then
then(resolveCallback, rejectCallback) {
// 判断回调是否是函数
resolveCallback =
typeof resolveCallback !== "function" ? v => v : resolveCallback;
rejectCallback =
typeof rejectCallback !== "function"
? err => {
throw err;
}
: rejectCallback;
// 为了保持链式调用 继续返回promise
return new Mypromise((resolve, reject) => {
// 将回调注册到successFun事件集合里面去
this.successFun.push(val => {
try {
// 执行回调函数
let x = resolveCallback(val);
//(最难的一点)
// 如果回调函数结果是普通值 那么就resolve出去给下一个then链式调用 如果是一个promise对象(代表又是一个异步) 那么调用x的then方法 将resolve和reject传进去 等到x内部的异步 执行完毕的时候(状态完成)就会自动执行传入的resolve 这样就控制了链式调用的顺序
x instanceof Mypromise ? x.then(resolve, reject) : resolve(x);
} catch (error) {
reject(error);
}
});
this.failFun.push(val => {
try {
// 执行回调函数
let x = rejectCallback(val);
x instanceof Mypromise ? x.then(resolve, reject) : reject(x);
} catch (error) {
reject(error);
}
});
});
}
//静态方法
static all(promiseArr) {
let result = [];
//声明一个计数器 每一个promise返回就加一
let count = 0
return new Mypromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
promiseArr[i].then(
res => {
//这里不能直接push数组 因为要控制顺序一一对应(感谢评论区指正)
result[i] = res
count++
//只有全部的promise执行成功之后才resolve出去
if (count === promiseArr.length) {
resolve(result);
}
},
err => {
reject(err);
}
);
}
});
}
//静态方法
static race(promiseArr) {
return new Mypromise((resolve, reject) => {
for (let i = 0; i < promiseArr.length; i++) {
promiseArr[i].then(
res => {
//promise数组只要有任何一个promise 状态变更 就可以返回
resolve(res);
},
err => {
reject(err);
}
);
}
});
}
}
// 使用
let promise1 = new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve(123);
}, 2000);
});
let promise2 = new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve(1234);
}, 1000);
});
// Mypromise.all([promise1,promise2]).then(res=>{
// console.log(res);
// })
// Mypromise.race([promise1, promise2]).then(res => {
// console.log(res);
// });
promise1
.then(
res => {
console.log(res); //过两秒输出123
return new Mypromise((resolve, reject) => {
setTimeout(() => {
resolve("success");
}, 1000);
});
},
err => {
console.log(err);
}
)
.then(
res => {
console.log(res); //再过一秒输出success
},
err => {
console.log(err);
}
);