在理清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步就出了的结果。