【JS】Promise.race( )方法例子流程详解

568 阅读5分钟

在理清Promise.all()中每个流程的时候实在是头大,理了半天,做此记录以便回顾

promise部分源码如下,只摘取用到的部分

function Promise(excutor) {
        const self = this
        self.status = 'pending' //给promise对象添加status属性,初始值为pending
        self.data = undefined //给promise对象指定data属性,用于储存结果数据
        self.callbacks = [] //每个元素的结构:{ onResolved() {} ,  onRejected() {} }
        function resolve(value) {
            //如果当前状态不是pending,直接结束
            if (self.status !== 'pending') {
                return
            }

            //将状态改为resolved
            self.status = 'resolved'
            //保存value数据
            self.data = value
            //如果有待执行的callback函数,立即异步执行onResolved
            if (self.callbacks.length > 0) {
                setTimeout(() => {//放入队列中执行所有成功的回调
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onResolved(value)
                    });
                });
            }

        }
        function reject(reason) {
            //如果当前状态不是pending,直接结束
            if (self.status !== 'pending') {
                return
            }
            //将状态改为rejected
            self.status = 'rejected'
            //保存value数据
            self.data = reason
            //如果有待执行的callback函数,立即异步执行onRejected
            if (self.callbacks.length > 0) {
                setTimeout(() => {//放入队列中执行所有成功的回调
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onRejected(reason)
                    });
                });
            }
        }

        //立即同步执行excutor
        try {
            excutor(resolve, reject)

        } catch (error) {//如果执行器抛出异常,则失败
            reject(error)
        }
    }

Promise.prototype.then = function (onResolved, onRejected) {
        const self = this

        return new Promise((resolve, reject) => {

            if (self.status === 'pending') {
                //假设当前状态时pending状态
                //此时的下一行的this,是调用then方法的promise,
                //因为这是处于新promise的excutor'中,
                this.callbacks.push({
                    onResolved: function () {
                        try {
                            //判断返回的是什么
                            //返回的是promise
                            const result = onResolved(self.data)
                            if (result instanceof Promise) {
                                result.then(
                                    value => resolve(value),
                                    reason => reject(reason)
                                )
                            } else {
                                //返回的是值,多次循环最终都是值,再包装成promise向上传递
                                //有点类似递归
                                resolve(result)
                            }
                        } catch (error) {
                            reject(error)
                        }
                    },
                    onRejected: function () {
                        try {
                            //判断返回的是什么
                            //返回的是promise
                            const result = onRejected(self.data)
                            if (result instanceof Promise) {
                                result.then(
                                    value => resolve(value),
                                    reason => reject(reason)
                                )
                            } else {
                                //返回的是值,多次循环最终都是值,再包装成promise向上传递
                                //有点类似递归
                                resolve(result)
                            }
                        } catch (error) {
                            reject(error)
                        }
                    }
                })
			}
		}
    /*
    Promise函数对象的race()方法 
    返回一个promise,其结果由第一个完成的promise的状态
     */
    Promise.race = function (promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    resolve(v)
                }, r => {
                    reject(r)
                })
            }
        })
    }

用作测试例子代码如下,promise结果均异步输出,excutor用settimeout

        let p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('1')
            }, 1000);
        })
        let p2 = new Promise((resolve, reject) => {
            // resolve('2')
            setTimeout(() => {
                resolve('2')
            }, 1000);

        })
        let p3 = new Promise((resolve, reject) => {
            // resolve('3')
            setTimeout(() => {
                resolve('3')
            }, 1000);

        })
        p1.aaa='我是标志'

        let result1 = Promise.race([p1,p2, p3])
        console.log(result1);

具体流程文字如下:

1. 首先p1,p2,p3三个实例对象被创建,但是其中的excutor没有执行,暂时进入异步队列等待同步任务完成;

2. 进入Promise.race内部: 首先会创建一个新的Promise,为了方便叙述, 命名为newP,该对象即是测试html中的result,最后输出的内容

    Promise.race = function (promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    resolve(v)
                }, r => {
                    reject(r)
                })
            }
        })
    }

3. 进入构造newP对象的构造函数代码中, 此时newP的状态为pending,data为undefined 然后进入newP的excutor,即进入for循环 在这里插入图片描述 4. 会进入promises数组中第一个promise的then方法,循环后续都是一样的,只描述第一个循环的流程即可,

进入后会先构造一个新的Promise对象,记为insideP,进入构造函数内部的代码后,

insideP状态为pending,data为undefined

然后进入excutor,即下图里面,进行if判断 因为p1p2p3都处于pending,(此时的循环针对p1)所以会push一个对象{onResolved, onRejected}给p1的callbacks数组 在这里插入图片描述 5. 结束第一个循环,后续循环同理,直至同步代码全部完成,此时控制台打印了result但是newP的状态是pending,(后续会自动改变) 此时异步队列开始运行,p1p2p3依次运行, 此时各个对象状态如下,全是pending 在这里插入图片描述 在这里插入图片描述

6. p1的excutor里面的resolve(1)开始运行 首先改变p1pending为resolved,data为1, 因为callbacks数组在第4步被push进了一个对象,所以length不为0, 此时由与setTimeout,所以会将其放入异步队列,然后进入p2的resolve(2),同理p3的resolve(3)分别改变p2和p3的pending和data,但是不进入下一步操作,因为是异步的 同步都完了,进入异步操作,此时还处于p1的resolve里的if语句,会执行下面的异步操作 进入并执行回调函数onResolved() 在这里插入图片描述 7. 跳转到then方法里面的onResolved方法处, 在这里插入图片描述 然后再因为onResolved是then的参数,跳转到调用then方法时的参数处,即循环的地方 在这里插入图片描述 此时可以看见,调用的是resolve()方法,但要明确是谁在调用该方法,本文的上一篇文章记录了这个问题,

此时的resolve是处于图中第二行new Promise对象下调用的,所以this指向该promise,即上文记录的newP对象,而不是调用then的p1对象,

强调:此时newP状态为pending,data为undefined; p1状态为resolved,data为1

8. 进入newP的resolve方法,改变pending为resolved,data为1,因为newP就是result 其实此时result结果就已经确定了,因为已经由结果了 在这里插入图片描述 9. 回到p1的then方法中进行后续任务,判断onResolved返回的数据是什么类型,此处不为promise类型,会进入else里面 resolve(result),这里的result不是newP,是onResolved的结果 在这里插入图片描述 10. 执行resolve方法,问题是此时是谁在调用该方法,可以在上图里看到,reslove是出于then方法中new 的Promise对象里的excutor的参数,this也被self暂存了,所以当此方法被调用时,并不是外部调用then方法的对象p1,而是这个新的promise对象,即上述记作insideP的对象, 强调:此时insideP为pending和undefined, 执行resolve后,insideP改变为resolved和1,

11.

接着第一次的onResolved循环结束,开始第二和第三次的循环,因为p2p3的异步onResolved都已经排在队列里了,后续都一样, 最终出来的result是在第8步就出了的结果。 在这里插入图片描述