一.Promise与then
Promise是解决异步的一种手段但其本身不是异步的,then是异步调用的,简而言之catch方法也是异步的。
let promise = new Promise((resolve,reject)=>{
console.log('exactor')
resolve('实现承诺')
})
promise.then((res)=>{
console.log(res)
return new Promise((resolve,reject)=>{ // then里面还可以返回Promise
console.log('3')
resolve('成功')
})
},(err)=>{
console.log(err)
}).then((res)=>{
console.log(res)
})
console.log('1')
console.log('2')
复制代码
首先由于Promise本身是同步的所以 console.log(‘exactor’)属于同步代码,但是resolve的结果被then接收,then是异步执行的,所以then这个方法会等所有同步的代码执行完毕后再执行。
二.Promise(A+)与浏览器中Promise的差异
直观的解释在于:在Promise.resolve()这步操作的时候,浏览器运行的Promise比Promise(A+)这个库直接运行的时候多了一个微任务即将Promise.resolve()压入到微任务队列中。这也就是Promise/A+实现和Promise浏览器实现的本质区别
Promise.resolve().then(() => {
console.log(0);
// return Promise.resolve(4);
return new Promise((resolve,reject)=>{
resolve(4)
})
}).then((res) => {
console.log(res)
})
Promise.resolve().then(() => {
console.log(1);
}).then((res) => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() =>{
console.log(6);
})
// 0 1 2 3 4 5 6
复制代码
首先执行两个Promise.resolve()并注册两个then
执行第一个注册的then并输出0 并且将new Promise中resolve的结果放到微任务队列中
此时微任务队列的对头是第二个then 所以执行第二 输出1 并注册第三个then即将其放入微任务队列中
此时微任务队列的对头是第一个then中resolve的结果 并注册then 发现没有then 则return结束
此时微任务对头是第三个then 所以执行第三个注册的then输出2 并注册第四个then
然后注册上述reuturn结束后的第五个then
此时微任务队列的对头是第四个then 所以输出3 并注册第六个then
此时微任务队列的对头的是第五个then 所以输出4 并注册第七个then 依次进行下去
new Promise((resolve, reject) => {
console.log('then->1');
resolve();
})
.then(() => {
console.log('then->2');
new Promise((resolve, reject) => {
console.log('then->3');
resolve();
})
.then(() => {
console.log('then->4');
return Promise.resolve();
})
.then(() => {
console.log('then->5');
})
})
.then(() => {
console.log('then->6');
})
.then(() => {
console.log('then->7');
})
.then(()=>{
console.log('then->8')
})
复制代码
首先执行then->1输出then->1 并注册then->2
此时微任务对头是then->2 输出then->2 且执行同步代码 输出then->3
注册then->4以及then->6
此时微任务的对头是then->4 执行then->4 输出then->4 并且将Promise.resolve输出的结果压入微任务队列
此时的微任务对头是then->6 输出then->6 并注册then->7
此时微任务的对头是resolve的结果 并注册then 但发现没有 则return返回的结果
**此时微任务的对头是then->7 输出then->7 并注册then->8 **
**注册then->5 **
此时微任务还剩then->8 then->5 所以依次执行
所以输出的结果是 1 2 3 4 6 7 8 5
三.Promise.resolve源码实现
Promise.resolve = function(value){
if(value instanceof Promise){
return value
}
return new Promise((resolve)=>{
resolve(value)
})
}
复制代码
四.Promise.all源码实现
all方法的原理是所有传入的Promise都必须是fulfilled状态并将其一并返回出去,如果有一个是rejected状态则将这个结果reject出去
function promiseAll(promiseArr){
if(!Array.isArray(promiseArr)){
return
}
let index=0,result = [];
return new Promise((resolve,reject)=>{
promiseArr.forEach((p)=>{
p.then((value)=>{
index++;
result.push(value)
if(index === promiseArr.length){
resolve(result)
}
},err=>{
reject(err)
})
})
})
}
复制代码
五.Promise.any源码实现
any方法的原理是只要传入的Promise有一个是fullfilled状态则立即resolve出去否则将所有reject结果收集起来并返回AggregateError
Promise.all = function(promiseArr){
if(!Array.isArray(promiseArr)){
return
}
let index = 0;
return new Promise((resolve,reject)=>{
promiseArr.forEach((p,i)=>{
p.then(value=>{
resolve(value)
},err=>{
index++;
if(index === promiseArr.length){
reject(new AggregateError('All promises were rejected'))
}
})
})
})
}
复制代码
六.Promise.race源码实现
race总是返回第一个fullfilled或者rejected的结果
Promise.race = function(promiseArr){
return new Promise((resolve,reject)=>{
promiseArr.forEach(p=>{
Promise.resolve(p).then(val=>{
resolve(val)
},err=>{
reject(err)
})
})
})
}
复制代码
七.Promise.allSettled源码实现
allSettled返回的是返回所有传入的Promise的结果即将fullfilled和rejected的结果合并起来返回
Promise.allSettled = function(promiseArr){
let result = []
return new Promise((resolve,reject)=>{
promiseArr.forEach((p,i)=>{
p.then(val=>{
result.push({
status:'fulfilled',
value:val,
})
if(result.length === promiseArr.length){
resolve(result)
}
},err=>{
result.push({
status:'rejected',
value:val,
})
if(result.length === promiseArr.length){
resolve(result)
}
})
})
})
}
复制代码
八.async await
async await是建立在promise机制之上的,并不能取代其地位!!!
8.1 async
async定义的函数是异步的且返回一个Promise对象
async function fn(){
return 'promise'
}
console.log(fn())
复制代码
因为返回的是Promise对象,所以必然是可以调用then方法的。
需要注意的是async关键字定义函数后表示函数内部有异步操作,但是函数本身是同步的。
async function fn(){
console.log('promise')
}
fn()
console.log('123')
复制代码
这段代码的结果是先输出promise在输出123所以可以看出fn是同步的。这可以与Promise的执行器进行类比,我们知道在执行器内的代码也是同步的,但是执行器执行完毕后返回的是一个Promise对象,这就如同async是同步的,但是执行完毕后返回的也是Promise对象
8.2 await
await的主要作用是用来等待Promise对象的状态变为fullfilled。所以从await的原理上就可以看出await是异步的,它会让当前async函数内部代码运行到await时停止执行(函数暂停执行),因为它需要等待Promise的解决,然后恢复async函数的执行。这样一来就可以达到同步的效果,因为你必须要等待上一个await执行完毕后才能执行下一个异步函数。
async function async1(){
console.log('async1 start')
await async2();
console.log('async1 end')
}
async function async2(){
console.log('async2')
}
async1()
console.log('script start')
setTimeout(()=>{
console.log('setTimeout') // 宏任务
},0)
new Promise((resolve,reject)=>{
console.log('promise1')
resolve()
}).then(()=>{ // 微任务
console.log('promise2')
})
console.log('script end')
复制代码
首先我们找到同步代码:async1() console.log(“script start”) console.log(“promise1”) console.log(“script end”) 依次执行输出
当运行async1()的时候 输出内部的async1 start 以及 async2()的结果async2
由于await的存在 我们需要等待async2()返回的Promise的状态变为fullfilled或rejected所以会暂停执行后续的代码(将其放入微任务队列中),这就是异步的体现。
然后运行setTimeout将其放入宏任务队列中。
然后运行then方法将其放入微任务队列中。
最后先运行完微任务队列中的代码在执行宏任务队列中的代码,得到输出结果为: