promise源码解析,及setTimeout、async执行顺序比较
-
javaScript是单线程,一个线程只有唯一的事件循环,每一个任务必须执行完才能进行下一个任务
-
同步任务
- 主线程上直接按顺序执行
-
异步任务
- 不在主线程中,而是在“任务队列”中
- 只有任务队列通知主线程,异步任务才能进入主线程执行
- 宏任务(macro-task):
-
script(整体代码) | setTimeout | setInterval | setImmediate | I/O | UIrendering
- script=> 最外层的宏任务被放入主线程立即执行,因为此时还没有微任务来竞争
- setTimeout:时间到期后执行的函数放在宏任务队列(会在所有的微任务执行完再考虑率)
- 第2个参数:0,事实不会有0,之前默认最小10ms/现在4ms
-
- 微任务(micro-task):
- process.nextTick | Promise | MutationObserver
- setTimeout()、new promise()、async 如果给的参数是表达式,会直接执行
- 宏任务(macro-task):
-
-
setTimeout,时间到期后,函数加到宏任务队列
- (需等到没有微任务、前面的宏任务执行完才能执行)
- 第二个时间参数只是函数等待执行的最短时间,0会自动转换成4,之前是10
- 新产生的promise会被放到微任务队列中(前面的微任务执行完就可以执行)
-
async、await
- async:后面接函数/函数表达式,函数的返回值作为 Promise.resolve() 的参数,产生一个promise对象
-
await:等,如果后面是普通表达式,直接执行通过 / 如果是promise对象相当于then,添加到微任务队列
- await后续的代码会作为下一个then中的代码等待await这一步的then执行完
-
问题:在 ES6 以前不支持 Promise 的环境下,通常只能靠 setTimeout 回退到传统的 Task 来模拟 Promise。但实际业务中,并没有感受到此类没有依赖微任务的 polyfill 有什么严重的可用性问题
- 问题解释:模拟的Promise (根据前文提示:promise产生微任务) 是通过ES5的setTimeout (到期后产生宏任务) 没有产生问题
- 那么接下来需要解决就是:原生的promise的执行顺序是否被模拟实现的promise都完成
- process.Nextick: 其产生的任务在所有微任务之前,故执行顺序慢的promise由宏任务(setTimeout)或微任务(原生Promise)都不影响 (!在座的各位都是辣鸡!)
- 同级别promise: 因为都是同级别,一起由微任务降为宏任务,相对顺序没有变化
- setTimeout
- 这个地方可能会有bug。比如前面也有setTimeout(fn,0),模拟promise不能先执行,会在后面执行
- 但是正常情况下,也不会出现setTimeout(fn,0)的代码
-
promise执行过程解析
- new Promise(fn(res,rej){执行体}) => fn直接执行
- 执行体没有:resolve() / rejected
- game over,后面的then中的函数不会执行
- p.then(console.log('????????')):仍然会输出
- then里面的代码仍然是通过 new promise(fn) fn执行
- fn如果返回then,可以继续.then/value则传给后面的then中的函数作为参数
- game over,后面的then中的函数不会执行
- 执行体有:resolve() / rejected
- state被改变,后续的then可以执行
class Promise {
constructor(executor) {
console.log(executor);
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
console.log('构造函数执行');
var that = this
let resolve = (value) => {
// console.log(value);
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach((fn) => {fn()});
}
};
let reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
}
};
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
// then肯定是前一个promise对象调用
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === 'function'
? onRejected
: (err) => {
throw err;
};
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
x instanceof Promise ? x.then(resolve, reject) : resolve(x);
console.log('resolve',that === this);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'rejected') {
setTimeout(() => {
try {
let x = onRejected(this.reason);
// resolvePromise(promise2, x, resolve, reject);
x instanceof Promise ? x.then(resolve, reject) : resolve(x);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// console.log(this.value,'thisvalue');
x instanceof Promise ? x.then(resolve, reject) : resolve(x);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
// resolvePromise(promise2, x, resolve, reject);
x instanceof Promise ? x.then(resolve, reject) : resolve(x);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
// console.log('this',this.state,this.onResolvedCallbacks);
return promise2;
}
catch(fn) {
return this.then(null, fn);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
(err) => {
if (called) return;
called = true;
reject(err);
}
);
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
//resolve方法
Promise.resolve = function(val) {
return new Promise((resolve, reject) => {
resolve(val);
});
};
//reject方法
Promise.reject = function(val) {
return new Promise((resolve, reject) => {
reject(val);
});
};
//race方法
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
};
//all方法(获取所有的promise,都执行then,把结果放到数组,一起返回)
Promise.all = function(promises) {
let arr = [];
let i = 0;
function processData(index, data, resolve) {
// index是为了保证多个promise执行产生的结果顺序与原promise一致
arr[index] = data;
i++; // 通过一个闭包,变量i记录是否所有promise已完成
if (i == promises.length) {
resolve(arr);
}
}
return new Promise((resolve, reject) => {
for (let i = 0; i < promises.length; i++) {
promises[i].then((data) => {
processData(i, data, resolve);
}, reject);
}
});
};