javascript 之 Promise 实现

前言

        Promise 是一种异步解决方案,没有Promise的时候,异步方案就是回调函数,嵌套多了就会陷入回调地狱。以下旨在讲核心用法及实现。

1、promise 的 then

  1. then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。
  2. then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。
  3. then方法的回调函数的返回值,会作为参数,再传给then方法返回的这个Promise实例的resolve
  4. 采用链式的then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个Promise对象(即有异步操作),这时后一个回调函数,就会等待该Promise对象的状态发生变化,才会被调用。
  5. 如果Promise对象 返回的结果是reject,then不会被执行,会走到catch里

// then---demo1---针对上面第二点
new Promise((resolve, reject) => {
    resolve(100);               // resolve--> Promise对像由 Pending状态变为 onFulfilled 状态
}).then(data => {
    console.log(data);   // 100
  return 'adf'               // then 方法返回新的Promise实例,也就是说即使不return值,后面的then方法也会执行
})
.then(data => {
    console.log(data)    // 上面返回了固定值,所以直接resolve掉 输出 adf  
})



// then---demo2---针对上面第三点
function wait(ms = 1000, data) {            // 返回一个Promise对象,并在ms时间之后 resolve(data)
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             resolve(data)
        },ms)
    })
}

const promise = new Promise((resolve, reject) => {
        resolve(100);
}).then(data => {
    console.log(data); // 100
  return wait(2000, 'qwe'); 
})
.then(data => {
    console.log(data);  // 2秒之后 qwe
})

const promise = new Promise((resolve, reject) => {
    reject('some error')
}).then(data => {
    console.log(data);  // 不执行
}).catch(e => {
    console.log(e) // some error
})
复制代码

2、async await 语法糖

函数前面加上 async 就会返回Promise对象,所以就可以用then语法

// async---demo1

function wait(ms = 1000, data) {            // 返回一个Promise对象,并在ms时间之后 resolve(data)
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             resolve(data)
        },ms)
    })
}

async function foo(){
    console.log('begin');
  const w1 = await wait(1000, 'w1');
  console.log('target1');
  const w2 = await wait(2000, 'w2');
  console.log('target2');
}

foo().then(data => {
    console.log('finished', data)   // data 是undefined 因为上面的async 函数没有return,resolve的结果就为undefined
})  
复制代码

如果async函数里 出现了 reject,就相当于在Promise 里出现了reject,有catch会捕获,没有catch会抛错

function wait(ms = 1000, data) {            // 返回一个Promise对象,并在ms时间之后 resolve(data)
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             resolve(data)
        },ms)
    })
}

async function bar(){
  console.log('begin');
  const w1 = await wait(1000, 'w1');
  console.log('target1');
  const w2 = await wait(2000, 'w2');
    const x = await Promise.reject('some error');       // await 不能忘
}

bar().then(d => console.log(d)); // 出错

bar().catch(e => console.log(e));   // 可以catch到error


async function bar(){
  try{
    console.log('begin');
    const w1 = await wait(1000, 'w1');
    console.log('target1');
    const w2 = await wait(2000, 'w2');
    const x = Promise.reject('some error');
  } catch(ex) {
        console.log(ex, 'js捕获语法同样可以捕获')
  }
}
复制代码

3、并发和竞争

// 模拟异步的wait函数
    function wait(ms = 1000, data) {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve(data);
            }, ms)
        })
}

// Promise.all 数组里的每个异步都成功,返回一个数组
Promise.all([wait(2000, 1), wait(3000,2)]).then(data => {
    console.log(data);  // [1,2]
})

// Promise.race 返回最先回来的结果
Promise.race([wait(2000, 1), wait(3000, 2)]).then(data => {
    console.log(data)   // 
})
复制代码

4、Promise 核心实现

// 有三个状态 这是三个变量
const PENDING = 1;
const FULFILLED = 2;
const REJETED = 3;

class myPromise {
    constructor(excutor) {
        this.state = PENDING;                                                           // 初始化就是pending 状态
    
    // 这个resolver 经常放到异步函数里执行,也就是会延迟执行
    const resolver = (value) => {
            if(this.state === PENDING) {
                this.value = value;                                                 // resolve之后,把参数给到this.value
            this.state = FULFILLED;                                         // 执行resolver后 状态改变
        }
        // 在then里 Pending态的时候,数组里存进去了值,所以可以正常延迟执行这里
        for(let [onFulfilled, resolve] of this.fulfills) {
                        const x = onFulfilled(this.value);
            // 这里没有做完善处理,比如如果x如果也是个Promise,待完善
            // 注意:这个resolve是在循环里边的,当前fulfilles里是只有一个元素,并且始终也只会有一个,
            // 因为即使 使用.then().then().then()的写法,每次执行then里的resove才能继续项后.then,而在
            // .then的时候,就像现在,已经执行完了当前循环。
            resolve(x);
                }
    }
    
    const rejector = (value) => {
        
        }
    
    excutor(resolver, rejector);                // 传入的构造函数,第一时间就会执行,Promise执行机制
    
    // 为处理异步做准备
    this.fulfills = [];
    }
  
  then(onFulfilled) {                                               //原型上的方法 相当于 Promise.prototype.then
            return new myPromise((resolve, reject) => {                 // 返回一个新的Promsie
                    switch(this.state) {
            case FULFILLED: 
              const x = onFulfilled(this.value);    // 执行外部传入的onFulfilled方法,通过this.value 取值
              resolve(x);                                                   // 对then返回的Promise 执行resolve,并传入x,这个x是onFulfilled的返回值
              break;
            case PENDING:       // 如果处于pending态,说明excutor里有异步方法,使用存放操作
              this.fulfills.push([onFulfilled, resolve]);   // 执行到这里先存入数组
              break;
          }
            })
    }
}

new myPromise((resolve, reject) => {
    //测试异步
    // setTimeout(() => {
        //      resolve(200)
    // }, 1000)
    resolve(100);   // resovle的参数,会传给this.value
    return 'abc'    // 这个return的值 后面的then没有接收,
}).then(data => {   // 这个入参是 this.value
    console.log(data);      // 100 
    return 'sdf'    // then方法返回了个Promise实例,它接收的回调函数的返回值 会再传到这个Promise的resolve里
}).then(d => console.log(d))  // sdf
复制代码

5、Promise 主要功能实现

Promise A+规范要求

image.png

/*
* Promise 的实现 主要两个大块,一个是then,一个是resolvePromise
*
*/
const statusMap = {
    PENDING: 'pending',
    FULFULLED: 'fulfilled',
    REJECTED: 'rejected'
}

function fulfilledPromise(promise, value) {
    // 只能从pending状态转换为其他状态
    if (promise.status !== statusMap.PENDING) {
        return
    }
    promise.value = value;                                  // 改变值为 resolve传进来的值
    promise.status = statusMap.FULFILLED;                    // 改变状态
    runCbs(promise.fulfilledCbs, value);
}

function rejectedPromise(promise, reason) {
    // 只能从pending状态转换为其他状态
    if (this.status !== statusMap.PENDING) {
        return
    }
    promise.value = reason
    promise.status = statusMap.REJECTED;
    runCbs(promise.rejectedCbs, reason);
}

function runCbs(cbs, value) {
    cbs.forEach(cb => cb(value))
}

function isFunc(fn) {
    return (
        Object.prototype.toString.call(fn).toLowerCase() === '[object function]'
    );
}

function isPromise(p) {
    return p instanceof ourPromise;
}

function isObject(obj) {
    return (
        Object.prototype.toString.call(obj).toLowerCase() === '[object object]'
    );
}

// promise 的解析
function resolvePromise(promise, x) {
    // x和promise相同(会出现循环调用)
    if (promise === x) {
        rejectedPromise(promise, new TypeError('cant be the same'));
        return
    }
    // x 是promise
    if (isPromise(x)) {
        if (x.status === statusMap.FUlFILLED) {
            fulfilledPromise(promise, x.value);
            return
        }
        if (x.status === statusMap.REJECTED) {
            rejectedPromise(promise, x.reason);
            return;
        }
        if (x.status === statusMap.PENDING) {
            x.then(() => {
                fulfilledPromise(promise, x.value);
            }, () => {
                rejectedPromise(promise, x.reason);
            });
            return;
        }
    }
    // x 是对象或者函数
    if (isObject(x) || isFunc(x)) {
        let then;
        let called = false;
        try {
            then = x.then;
        } catch (errot) {
            rejectedPromise(promise, error);
            return
        }
        if (isFunc(then)) {
            // then 是 参数上的then,外部传进来的 不受控制,所以加try cahtch
            try {
                then.call(x, (y) => {
                    if (called) {
                        return
                    }
                    called = true;
                    resolvePromise(promise, y);
                }, (r) => {
                    if (called) {
                        return
                    }
                    called = true;
                    rejectedPromise(promise, r)
                });
            } catch (e) {
                if (called) {
                    return
                }
                called = true;
                rejectedPromise(promise, e)
            }
        } else {
            fulfilledPromise(promise, x);
            return;
        }
        // x 不是对象或者函数
    } else {
        fulfilledPromise(promise, x);
    }
}

class ourPromise {
    constructor(fn) {
        this.status = statusMap.PENDING; // 初始态的是pending
        this.value = undefined;         // 传参用的变量
        this.reason = undefined;        // 失败的拒因
        this.fulfilledCbs = [];
        this.rejectedCbs = [];
        fn((value) => {                             // 构造函数的执行
            fulfilledPromise(this, value);  // this 是指Promise实例,
        }, (reason) => {
            rejectedPromise(this, reason);
        });
    }

    then(onFulfilled, onRejected){
        const promise1 = this; // 保存一个当前的promise 实例
        const promise2 = new ourPromise(() => { }) // 将返回的新promise实例
        // Fulfilled 状态处理
        if (promise1.status === statusMap.FULFILLED) {
            // 异常判断,如果then的入参不是函数,就忽略,返回promise1
            if (!isFunc(onFulfilled)) {
                return promise1
            }
            // 模拟异步,同步任务执行完成后再执行
            setTimeout(() => {
                try {
                    const x = onFulfilled(promise1.value);
                    resolvePromise(promise2, x); // 决议promise2的状态
                } catch (e) {
                    rejectedPromise(promise2, e);
                }
            }, 0)
    }
    // Rejected 状态处理
    if (promise1.status === statusMap.REJECTED) {
        // 异常判断,如果then的入参不是函数,就忽略,返回promise1
        if (!isFunc(onRejected)) {
            return promise1
        }
        // 模拟异步,同步任务执行完成后再执行
        setTimeout(() => {
            try {
                const x = onRejected(promise1.value);
                resolvePromise(promise2, x); // 决议promise2的状态
            } catch (e) {
                rejectedPromise(promise2, e);
            }
        }, 0)
    }
    // Pending 状态处理
    if (promise1.status === statusMap.PENDING) {
        onFulfilled = isFunc(onFulfilled) ? onFulfilled : (value) => value;
        onRejected = isFunc(onRejected) ? onRejected : (err) => {throw err};
            promise1.fulfilledCbs.push(
                () => {
                    setTimeout(() => {
                        try {
                            const x = onFulfilled(promise1.value);
                            resolvePromise(promise2, x); // 决议promise2的状态
                        } catch (e) {
                            rejectedPromise(promise2, e);
                        }
                    }, 0)
                }
            );
            promise1.rejectedCbs.push(
                () => {
                    setTimeout(() => {
                        try {
                            const x = onRejected(promise1.reason);
                            resolvePromise(promise2, x); // 决议promise2的状态
                        } catch (e) {
                            rejectedPromise(promise2, e);
                        }
                    }, 0);
                }
            );
        }
        return promise2 // 返回一个新的promise实例
    }
}

// test
function wait (ms = 1000, data) {
    return new ourPromise ((resolve, rejected) => {
        setTimeout(() => {
            resolve(data)
        }, 0)
    })
}

const promise1 = new ourPromise((resolve, rejected) => {
    console.log('start')
    resolve(122);
}).then(data => {
    console.log(data)
    return wait(1000, '哈哈哈')
}).then(d => console.log(d, 'dddd'))

// promise-aplus 测试用例钩子

// ourPromise.deferred = function () {
//     const deferred = {};
//     deferred.promise = new ourPromise((resolve, rejected) => {
//         deferred.resolve = resolve;
//         deferred.rejected = rejected;
//     })
//     return deferred;
// }
// module.exports = ourPromise;
复制代码

6、小结

简单说,Promise 最主要的就是两大块

  • then的实现, then方法返回的是一个新的Promise实例
  • 决议状态resolvePromise
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享