面试中经常问道能否自己实现某个api其实如果对其掌握扎实都是不 难的;promise主要是通过状态去进行任务的队列管理,规避回调地狱;
自己实现的话首先就是思考promise是什么,都包含那些属性和方法;
state;reject;resolve;then;catch;all;race;
大致搭个架子
class Promise{
constructor(){
this.state = 'pending'
this.value = ''
}
reject(){};
resolve(){};
then(){};
catch(){};
all(){};
race(){};
}
简单核对一下,大致也就这样了
executor
executor是带有 resolve 和 reject 两个参数的函数 。Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回所建promise实例对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦异步操作执行完毕(可能成功/失败),要么调用resolve函数来将promise状态改成fulfilled,要么调用reject 函数将promise的状态改为rejected。如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。
然后promise有个executor方法,会立即执行添加进去;
class Promise {
constructor(e) {
this.state = 'pending'
this.value = ''
this.executor(e)
}
executor(e) {
if(typeof e === 'function'){
e( this.resolve.bind(this),this.reject.bind(this))//这里后边捣了不少乱,一开始没绑定this,后来又发现写反了。。。
}else{
this.state = 'rejected';
throw new Error('Promise resolver undefined is not a function')
}
}
reject(e) {
if(this.state ==='pending'){
this.state = 'rejected';
this.value = e;
console.log(e)
}
}
resolve(e) {
if(this.state ==='pending'){
this.state = 'fulfilled';
this.value = e;
console.log(e)
}
}
then() { }
catch(){}
all() { }
race() { }
}
//测试一下看着没啥问题
let a = new Promise(function(resolve, reject){
console.log(111)
let num = Math.floor(Math.random()*10);
setTimeout(() => {
console.log('promise timeout')
if(num>=5) {
resolve('fine')
}else{
reject('error')
};
}, 1000);
});
then
添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.
接受两个参数(onFulfilled, onRejected)都是可选参数,就是一个红鲤鱼与绿鲤鱼的问题
then(onFulfilled, onRejected) {
console.log('then=='+this.state)
if (this.state === 'resolved') {
if (typeof onFulfilled === 'function') {
onFulfilled(this.value);
}
}
if (this.state === 'rejected') {
if (typeof onRejected === 'function') {
onRejected(this.value);
}
}
};
测试时这里的log就先跑出来了,换句话说压根没等异步完成直接就处理了,再调整一下,这里只写了添加了的,要不一贴一大坨脑仁疼
constructor(e) {
this.resolvedFun = [];
this.rejectedFun = [];
};
reject(e) {
this.rejectedFun.map(x => x(e));
}
resolve(e) {
this.resolvedFun.map(x => x(e));
}
then(onFulfilled, onRejected) {
if(this.state==='pending'){
if (typeof onFulfilled === 'function') {
this.resolvedFun.push(onFulfilled);
}
if (typeof onRejected === 'function') {
this.rejecteddFun.push(onRejected);
}
}else{...}
};
catch
catch就省事多了,本质上和then是一样的,而且只有一个onRejected
catch(onRejected){
if (typeof onRejected === 'function') {
this.rejecteddFun.push(onRejected);
}
}
链式调用
连续执行两个或者多个异步操作是一个常见的需求,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。我们可以通过创造一个 Promise 链来实现这种需求;then() 函数会返回一个和原来不同的新的Promise:
then(onFulfilled, onRejected){
return new Promise()
}
这里轻敌了。。折腾了俩小时没倒腾出来,又经历了断网没保存的折腾心态有点炸了,仔细翻了下重写了;
如果promise的then方法中函数返回结果是一个promise,会自动执行,并延用他的状态,如果成功将会吧成功的结果向外层的下一个then传递;
如果返回的是一个普通值,那就将这个普通值作为下一次成功的结果
需要做的
- 判断成功失败函数返回的结果,也就是判断then中传递的函数的返回结果
- 判断是不是promise,如果是promise就采用他的状态
- 如果不是promise,直接将结果往下传递
修改之前的代码
then(onFulfilled, onRejected) {
return new Promise((resolve, reject) => {
if (this.state === 'pending') {
if (typeof onFulfilled === 'function') {
this.resolvedFun.push(()=>{onFulfilled(this.value)});
}
if (typeof onRejected === 'function') {
this.rejectedFun.push(() => { onRejected(this.value) });
}
}
if (this.state === 'resolved') {
if (typeof onFulfilled === 'function') {
let x = onFulfilled(this.value);
resolve(x)//把promise的resolve传递给promise2
}
}
if (this.state === 'rejected') {
if (typeof onRejected === 'function') {
let x = onRejected(this.value);
reject(x)
}
}
})
};
//test
let a = new Promise((resolve, reject) => {
resolve()
})
a.then(e => { console.log('then1'); return 100 })
.then(e => { console.log('then2') })
.then(e => { console.log('then3') })
这基本上就齐活了,但是这个then只能处理普通值,面对promise就无力招架了,需要添加个判断看看是不是promise如果是就then不是再传,并且代码有些冗余了,所以还得继续改
then(onFulfilled, onRejected) {
let promise2 = new Promise((resolve, reject) => {//这里修改是因为内部函数this只能取到本身传参有问题
if (this.state === 'pending') {
this.resolvedFun.push(()=>{
//添加trycatch防止抛出异常promise错误
try {
setTimeout(() => { //修改为异步,否则拿不到promise2
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject)
}, 0);
} catch (err) {
reject(err);
}
});
this.rejectedFun.push(() => {
...
});
}
if (this.state === 'resolved') {
...
}
if (this.state === 'rejected') {
...
}
})
return promise2
};
然后补充核心的resolvePromise方法,这里可以照猫画虎照葫芦画瓢,这个是瓢,参看2.3
promise A+
const resolvePromise = (promise2,x,resolve,reject){
if(promise2 === x){
return reject(new TypeError('chaining cycle detected for promise#<promise>'))//promiseA+规定
}
if(typeof x==='object' && x !== null || typeof x==='function'){
try{
let then = x.then;
if(typeof then === 'function'){
then.call(x,y=>{resolve(y)},r=>{reject(r)})
}else{
resolve(x)
}
}catch(e){
reject(e)
}
}else{
reslove(x)//普通值就把刚刚的处理方式丢过来,直接成功并传递值
}
}
至此大功告成