看完这篇,Promise面试就搞定了...

1,049 阅读4分钟

1.Promise

Promise是目前比较流行的异步解决方案,本质上一个构造函数。

1.1状态

promise有三种状态,初始状态是pedding,包括:

  • 成功状态 pedding => resolve
  • 失败状态 pedding => reject
  • 等待状态 pedding

我们先来看一个简单的例子

let promise = new Promise(function(resolve,reject){
    //throw new Error('出错了')
    //resolve()
    reject()
});
promise.then(()=>{
    console.log('success')
},()=>{
    console.log('error');
});

每个promise的实例都有then方法,包额括两个参数,分别是成功的回调会失败的回调,同时支持多次then,成功就回调所有成功方法失败也是如此,本质上then是一个异步的,也称为微任务。 其他方法还包括:

  • Promise.all() 所有的promise对象成功才会触发成功状态,否则失败状态
  • Promise.race() 任意一个子pormise的状态触发后会被父promise立即调用,完成一个即可

2. 自己实现一个Promise

所有的promise都要遵循promiseA+规范

2.1简易版

function Promise(executor){ 
    let self = this;
    self.value = undefined; //定义成功的value
    self.reason = undefined; //定义失败的reson
    self.status = 'pending'; //初始化状态为pedding
    function resolve(value){
        if(self.status === 'pending'){ //只有pedding的时候状态才可以改变
            self.value = value;
            self.status = 'resolved';
        }
    }
    function reject(reason){
        if(self.status === 'pending'){ //只有pedding的时候状态才可以改变
            self.reason = reason;
            self.status = 'rejected';
        }
    }
    // 如果函数执行时发生异常throw new Error,就失败
    try{
        executor(resolve,reject); //executor 默认new的时候就自动执行
    }catch(e){
        reject(e);
    }
}
Promise.prototype.then = function(onFulfilled,onRejected){
    let self = this;
    //判断当前状态
    // 成功状态时
    if(self.status === 'resolved'){//如果成功,执行成功,并把成功原因传过去
        onFulfilled(self.value);//上面的实例then中成功回调(console.log('success'))
    }
    // 失败状态时
    if(self.status === 'rejected'){//如果失败,执行失败,并把失败原因传过去
        onRejected(self.reason);//上面的实例then中失败回调(console.log('error'))
    }
}
module.exports = Promise;

2.2 稍微完善

但当在new Promise 中加入有异步方法,如下3秒后才开始执行成功,此时resolve会延迟执行,then中的状态又不是成功,又不是失败,因此会不执行成功或者失败方法,因为需要将成功或者失败的方法用数组存起来

let promise = new Promise(function(resolve,reject){
    setTimeout(()=>{
        resolve()
    },3000)
});

来完善的例子

function Promise(executor){
    let self = this;
    self.value = undefined;
    self.reason = undefined;
    self.status = 'pending';
    self.onResolvedCallbacks = [];// 存放then中成功的回调
    self.onRejectedCallbacks = []; // 存放then中失败的回调
    function resolve(value){
        if(self.status === 'pending'){
            self.value = value;
            self.status = 'resolved';
            self.onResolvedCallbacks.forEach(fn=>fn());//循环执行成功
        }
    }
    function reject(reason){
        if(self.status === 'pending'){
            self.reason = reason;
            self.status = 'rejected';
            self.onRejectedCallbacks.forEach(fn=>fn());//循环执行失败
        }
    }
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}
// onFulfilled成功的回调 onRejected失败的回调
Promise.prototype.then = function(onFulfilled,onRejected){
    let self = this;
    if(self.status === 'resolved'){
        onFulfilled(self.value);
    }
    if(self.status === 'rejected'){
        onRejected(self.reason);
    }
    if(self.status === 'pending'){//当等待状态时候,保存回调函数
        self.onResolvedCallbacks.push(()=>{
            onFulfilled(self.value);
        });
        self.onRejectedCallbacks.push(()=>{
            onRejected(self.reason)
        });
    }
}
module.exports = Promise;

2.3 链式调用

我们知道Promise可以一直then下去,来实现链式调用,但上面的例子明显不可以实现 例如

let p = new Promise((resolve,reject) =>{
    resolve(123)
})
let p1 = new Promise((resolve,reject) =>{
    resolve(111)
})
p.then((data)=>{
    console.log(data)
    return p1 //返回的p1是一个新的promise,继续成功下去,把111传给下一个newData,失败也是如此,如果返回的是普通值,直接把值作为下一层then的参数,所以需要判断p1是不是promise
}).then((newData)=>{
    console.log('p1',data)
})

完善代码

function Promise(executor) {
    let self = this;
    self.value = undefined; 
    self.reason = undefined; 
    self.status = 'pending'; 
    self.onResolvedCallbacks = [];  
    self.onRejectedCallbacks = [];
    function resolve(value) { 
        if (self.status === 'pending') {
            self.value = value;
            self.status = 'resolved';
            self.onResolvedCallbacks.forEach(fn => fn());
        }
    }
    function reject(reason) { 
        if (self.status === 'pending') {
            self.reason = reason;
            self.status = 'rejected';
            self.onRejectedCallbacks.forEach(fn => fn());
        }
    }
    try {
        executor(resolve, reject);
    } catch (e) {
        reject(e);
    }
}
/**
 * 
 * @param {*} promise2  then的返回值 (返回的新的promise)
 * @param {*} x  then中成功或者失败函数的返回值
 * @param {*} resolve promise2的resolve
 * @param {*} reject  promise2的reject
 */
function resolvePromise(promise2,x,resolve,reject){
    // promise2和函数执行后返回的结果是同一个对象,自己等待自己执行,不可以
    <!--例如 let p1 = p.then((data)=>{-->
    <!--    return p1 //返回的promise既不会成功也不会失败,自己等待自己-->
    <!--})-->
    if(promise2 === x){
        return reject(new TypeError('Chaining cycle'));
    }
    let called;
    // x可能是一个promise 或者是一个普通值
    if(x!==null && (typeof x=== 'object' || typeof x === 'function')){
        try{
            let then = x.then; // 这个promise可能是别人乱写的,所以try catch
            // x可能还是一个promise 那么就让这个promise执行即可
            if(typeof then === 'function'){
                then.call(x,y=>{ // 返回promise后的成功结果
                    // 递归直到解析成普通值为止
                    if(called) return; // 防止多次调用
                    called = true;
                    // 递归 可能成功后的结果是一个promise 那就要循环的去解析
                    resolvePromise(promise2,y,resolve,reject);
                },err=>{ // promise的失败结果
                    if(called) return;
                    called = true;
                    reject(err);
                });
            }else{
                resolve(x);
            }
        }catch(e){
            if(called) return;
            called = true;
            reject(e);
        }
    }else{ // 如果x是一个常量
        resolve(x);
    }
}
Promise.prototype.then = function (onFulfilled, onRejected) {
    let self = this;
    let promise2;
    // 需要每次调用then时都返回一个新的promise
    promise2 = new Promise((resolve, reject) => {//相当于调完了then又返回了一个promise
        if (self.status === 'resolved') {
            setTimeout(()=>{
                try {
                    // 当执行成功回调的时候可能会出现异常,那就用这个异常作为promise2的错误的结果
                    let x = onFulfilled(self.value); //新的promise,也就是then的返回结果
                    //执行完当前成功回调后返回结果可能是promise
                    resolvePromise(promise2,x,resolve,reject);
                } catch (e) {
                    reject(e);
                }
            },0)
        }
        // 规范要求加setTimeout
        if (self.status === 'rejected') {
            setTimeout(()=>{
                try {
                    let x = onRejected(self.reason);
                    resolvePromise(promise2,x,resolve,reject);
                } catch (e) {
                    reject(e);
                }
            },0)
        }
        if (self.status === 'pending') {//等待的时候也要包装一个promise2
            self.onResolvedCallbacks.push(() => {
                setTimeout(()=>{
                    try {
                        let x = onFulfilled(self.value);
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                },0)
            });
            self.onRejectedCallbacks.push(() => {
                setTimeout(()=>{
                    try {
                        let x = onRejected(self.reason);
                        resolvePromise(promise2,x,resolve,reject);
                    } catch (e) {
                        reject(e);
                    }
                },0)
            });
        }
    });
    return promise2
}
module.exports = Promise;