走进Promise

310 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

序言

Promise编写代码中很常见,我们不要常若知其然而不知其所以然。

当自己提到了Promise的时候面试官问下去,结果不懂了,就不好~哈哈哈

简介

Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。

一个Promise必然处于以下三种状态之一

  • 待定(pending):初始状态,即没有兑现,也没有被拒绝。
  • 已兑现(fulfilled):意味着操作成功
  • 已拒绝(rejected):意味操作失败

当pending转换成fulfilled或者rejected时,状态将不会变化。

解决问题:

  1. 回调地狱,代码难以维护
  2. 回调会受到控制反转的影响

实现Promise

语法:

new Promise(executor)

executor:是一个双参函数,参数为resolve和reject,Promise的实现会立即执行executor并且传入两个函数,成功调用resolve,状态变成fulfilled,失败调用reject,状态变为rejected。

设计:

  1. Promise应该是一个构造函数
  2. 传入一个参数
        function MyPromise(executor) {
            //1. 固定this,防止resolve和reject函数中this发生变化,或者直接使用箭头函数
            let self = this;
            //2. Promise的初始状态为pending
            self.state = "pending";
            //3. Promise的结果值
            self.value = undefined;
           
            //---7. 异步执行时then的注册存放的fulfilled状态数组
            self.onFulfilledArr = [];
            //---8. 异步执行时then的注册存放的rejected状态数组
            self.onRejectedArr = [];
            
            //4. executor第一个参数函数
            function resolve(res) {
                //4.1 判断状态是否为pending
                if (self.state !== "pending") return;
                //4.2 状态变成已兑现
                self.state = "fulfilled";
                //4.3 结果值为传入参数
                self.value = res;
                
                //---9. 调用then的数组,待定变成成功
                self.onFulfilledArr.forEach(item => item());
            }
            //5. executor第二个参数函数
            function reject(err) {
                //5.1 判断状态是否为pending
                if (self.state !== "pending") return;
                //5.2 状态变成已兑现
                self.state = "rejected";
                //5.3 结果值为传入参数
                self.value = err;
                
                //---10. 调用then的数组,待定变成失败
                self.onRejectedArr.forEach(item => item());
            }
            //6. 执行executor
            try {
                executor(resolve, reject);
            }catch(err) {
                reject(err);
            }
        }

实现Promise.prototype.then

then方法可以让Promise支持链式调用

语法:

p.then(onFulfilled[, onRejected]);

onFulfilled和onRejected都为可选

注意:

  1. then方法返回一个Promise对象
  2. 当promise的状态变为成功时调用onfulfilled,其中参数为resolve传入的参数
  3. 当promise的状态变为失败时调用onfulfilled,其中参数为reject传入的参数
  4. then方法可以多次调用
  5. onFulfilled不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数
  6. onRejected不是函数,则会在内部被替换为一个 "Thrower" 函数。
        let test2 = new Promise((resolve, reject) => {
            resolve("hehe");
        });
        console.log(test2.then());

then方法无参数.png

        let test2 = new Promise((resolve, reject) => {
            reject("hehe");
        });
        console.log(test2.then());

then方法无参数1.png

设计:

        MyPromise.prototype.then = function (onFulfilled, onRejected) {
            //1. 固定this
            let self = this;
            //2. 判断onFulfilled是否是函数
            if (typeof onFulfilled !== "function") {
                onFulfilled = res => res;
            }
            //3. 判断onRejected是否为函数
            if (typeof onRejected !== "function") {
                onRejected = err => {
                    throw err;
                };
            }
            //4. 当进入then的时候promise的状态为fulfilled状态
            if (self.state === "fulfilled") {
                //4.1 返回新的promise对象
                return new MyPromise((resolve, reject) => {
                    try {
                        //4.2 执行成功态的函数
                        let x = onFulfilled(self.value);
                        //4.3 判断返回结果是否是promise
                        if(x instanceof MyPromise) {
                            //4.3.1 返回的Promise函数调用then方法作为结果
                            x.then(res=>resolve(res), err=>reject(err));
                            return;
                        }
                        //4.3.2 返回值直接进入resolve
                        resolve(x);
                    } catch (err) {
                        //4.4 捕获错误
                        reject(err);
                    }
                });
            }
            //5. 当进入then的时候promise的为拒绝状态
            if (self.state === "rejected") {
                return new MyPromise((resolve, reject) => {
                    try {
                        //5.1 执行拒绝态函数
                        let x = onRejected(self.value);
                        if(x instanceof MyPromise) {
                            x.then(res=>resolve(res), err=>reject(err));
                            return;
                        }
                        reject(x);
                    } catch (err) {
                        reject(err);
                    }
                });
            }
            //6. 当进入then的时候promise的为待定状态
            if (self.state === "pending") {
                return new MyPromise((resolve, reject) => {
                //6.1 因为不清楚到底到底执行成功态还是失败态,需要存入两个数组Promise里面的(7,8),待到状态敲定进行执行,
                    self.onFulfilledArr.push(() => {
                        try {
                            let x = onFulfilled(self.value);
                            resolve(x);
                        } catch (err) {
                            reject(err);
                        }
                    });
                    self.onRejectedArr.push(() => {
                        try {
                            let x = onRejected(self.value);
                            reject(x);
                        } catch (err) {
                            reject(err);
                        }
                    });
                });
            }
        }

实现Promise.prototype.catch

catch方法用于promise组合中的错误处理。

它就是then方法的第二个参数函数

示例:

        let temp = new Promise((resolve,reject)=>{
            reject("temp");
        });
        temp.then(val=>console.log(val)).then(()=>console.log("2")).catch(err=>console.log(err));

输出:temp

设计:

        MyPromise.prototype.catch = function(onRejected) {
            return this.then(undefined, onRejected);
        }

实现Promise.resolve

示例:在resolve方法里面传入Promise实例,返回它本身

设计:

        let temp = new Promise((resolve,reject)=>{
            resolve("temp");
        });
        console.log(Promise.resolve(temp));

resolve示例1.png

在resolve方法里里面传入非Promise实例,返回新Promise值,并且状态为成功态

        let temp = 1;
        console.log(Promise.resolve(temp));

resolve示例2.png

设计:

    MyPromise.resolve = function(res) {
        if(res instanceof MyPromise) {
            return res;
        }
        return new MyPromise((resolve,reject)=>resolve(res));
    }

实现Promise.reject

返回一个带有拒绝原因的Promise

设计:

        MyPromise.reject = function(err) {
            return new MyPromise((resolve,reject)=>reject(err));
        }

实现Promise.all

返回一个Promise,其中迭代器中一个Promise拒绝就拒绝

有多个Promise组合时,且都是完成状态那么Promise.all返回的Promise异步变为完成,如果其中有一个拒绝,那么返回的Promise直接调用失败Promise的回调函数

语法:

Promise.all(iterable);

iterable:为一个可迭代对象

设计:

        MyPromise.all = function(mpArr) {
            //所有成功态的存储结果
            const res = [];
            return new MyPromise((resolve, reject) => {
                mpArr.forEach((item, index) => {
                    MyPromise.resolve(item).then(val=>{
                        res.push(val);
                        //所有Promise成功
                        if(index + 1 == mpArr.length) {
                            resolve(res);
                        }
                    }, err => {
                        //一个失败即失败
                        reject(err);
                    });
                });
            });
        }

实现Promise.race

返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

就是迭代器里面的Promise谁先执行完就执行谁

语法:

Promise.race(iterable);

设计:

        MyPromise.race = function(mpArr) {
            return new MyPromise((resolve, reject) => {
                mpArr.forEach(item=>{
                    MyPromise.resolve(item).then(val=>{
                        resolve(val);
                    }, err => {
                        reject(err);
                    });
                });
            });
        }

结语

Promise在我所遇到的笔试题当中较少,不过在面试的时候问得很多很多。知识嘛积累积累,也不嫌多

参考: MDN|Promise