https://juejin.cn/post/6844903999506923528
then里面return或者promise里面return,都相当于resolve功能,不管return的是什么!!!! throw Error后就直接走到catch!!!!
console.log(1)
setTimeout(() => {
console.log(2)
})
new Promise((resolve, reject) => {
console.log(3)
resolve(4)
})
.then((data) => {
console.log(data)
return 5
})
.then((data) => {
console.log(data)
throw Error('------')
})
.catch((data) => {
console.log('catch', data)
})
console.log(7)
1、3、7、4、5、catch Error: ------、2
浏览器中promise后面会有.catch和.then,这个也需要考虑
const promise = new Promise((resolve, reject) => {
console.log(2)
reject(3)
console.log(4)
})
promise
.then(() => console.log(5))
.catch(() => console.log(6))
.then(() => console.log(7))
.catch(() => console.log(8))
.then(() => console.log(9))
// 结果:2、4、6、7、9
reject的话,就是走catch,然后还会继续往下走then,then里面如果有错,才继续走catch,没错后续的catch就不走了
const promise = new Promise((resolve, reject) => {
console.log(2)
reject(3)
console.log(4)
})
promise
.then(() => console.log(5))
.catch(() => console.log(6))
.then(() => {throw Error('111')})
.then(() => console.log(7))
.catch(() => console.log(8))
.then(() => console.log(9))
// 结果是 2、4、6、8、9,因为有错,直接跳过了他的下一个then,然后直接到了catch,执行完了catch才继续执行的
浏览器中
宏任务和微任务是指异步后,如何将异步函数划分到哪个队列中执行。
正常方法执行,会先从上到下顺序执行方法,这些都属于同步的方法(不包含下面的宏任务和微任务方法的分类。)
setTimeout(_ => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
// 这里执行同步的任务为,空的setTimeout方法,之后异步函数塞到宏队列里
// 执行new Promise到then之前的所有方法,把then塞到微队列里
// 在执行console.log(2)
执行顺序: 同步 > 微任务 > 宏任务
每执行一个新的宏任务之前会先去执行微任务队列的信息,直至都清空后,才会执行下一个宏任务(一般应用在宏任务与微任务回调函数中互相又有相应调用的存在时发生)!!!
宏任务分类
微任务队列
Promise这一段是同步的任务,同理async与Promise相同也是同步任务。只有.then()、catch()、finally()、和await后面的调用才是微任务,(ps:await同行的调用属于同步调用范围,下面的一行才是then函数中的)
详尽举例说明
下面例子中定时器setTimeout的定时都是0,若不是0的话,多个宏任务之前的执行顺序就会有改变,当时间特别短,比如说10ms、20ms等,没办法确定谁先执行,谨记哦!!!
1、在主线程上添加宏任务与微任务
console.log('-------start--------');
setTimeout(() => {
console.log('setTimeout');
}, 0);
new Promise((resolve, reject) => {
console.log('resolve执行前')
resolve()
console.log('resolve执行后,reject执行前')
reject();
console.log('reject执行后')
}).then(()=>{
console.log('Promise实例成功回调执行');
})
console.log('-------e')
从上到下,按步骤走,转换为各队列中执行的方法(队列:先进先出),不是宏任务和微任务的直接放在同步队列里,是宏任务的,把回调函数放到宏队列里,是微任务的,把回调函数放到微任务里
是宏任务的,把回调函数放到宏队列里,是微任务的,把回调函数放到微任务里
// 同步队列
tongbu = [
console.log('-------start--------'),
setTimeout, // 空的,只是一个函数,它的回调函数被放置到了宏队列里,
// 执行下面的Promise方法,因为当前这段为同步的,不是微任务,后面的then内容放到微队列里
new Promise((resolve, reject) => {
// 内部也属于同步数据,从上到下执行(也可自行转换为同步队列)
console.log('resolve执行前')
resolve()
console.log('resolve执行后,reject执行前')
reject();
console.log('reject执行后')
}),
console.log('-------e')
]
// 微队列
wei = [
console.log('Promise实例成功回调执行')
]
// 宏队列
hong = [
console.log('setTimeout')
]
先执行同步队列,再微队列,最后在执行宏队列,所以得到的结果是
-------start--------
resolve执行前
resolve执行后,reject执行前
reject执行后
-------e
Promise实例成功回调执行
setTimeout
在微任务中创建微任务
后续空的方法就不写了,直接写需要执行的方法
setTimeout(_ => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
Promise.resolve().then(_ => {
console.log('before timeout')
}).then(_ => {
Promise.resolve().then(_ => {
console.log('also before timeout')
})
})
})
console.log(2)
第一步转换,转换为以下的队列
tongbu = [
resolve => { // promise
resolve()
console.log(1)
},
console.log(2)
]
wei = [
_ => {
console.log(3)
Promise.resolve().then(_ => {
console.log('before timeout')
}).then(_ => {
Promise.resolve().then(_ => {
console.log('also before timeout')
})
})
}
]
hong = [
_ => console.log(4)
]
在同步队列中获取到结果:1,2
微队列中继续进行转换,由上面已经转换的微队列里进行转换,现在就是转换成同步的执行队列了
// 由上述微队列转换为当前执行的同步队列
tongbu = [
console.log(3),
]
wei = [
_ => {
console.log('before timeout')
}).then(_ => {
Promise.resolve().then(_ => {
console.log('also before timeout')
})
}
]
得出同步队列的结果:3
微队列还需要继续转化
// 由上述微队列转换为当前执行的同步队列
tongbu = [
console.log('before timeout')
]
wei = [
_ => {
console.log('also before timeout')
}
]
最后得到的结果:
1
2
3
before timeout
also before timeout
4
async、await使用例子
setTimeout(_ => console.log(1))
async function async1() {
console.log('async1 start')
await async2();
console.log('async1 end')
}
async function async2() {
console.log('async2 -1')
await aa();
console.log('async2 -2')
await bb();
}
async function aa () {
console.log('aa 1')
}
async function bb () {
console.log('bb1')
}
console.log('async1执行前')
async1();
console.log(6)
转化为以下
tongbu = [
console.log('async1执行前'),
() => {
console.log('async1 start'),
() => {
await aa();
console.log('async2')
await bb();
}
},
console.log(6)
]
wei = [
console.log('async1 end')
]
hong = [
_ => console.log(1)
]
首先能拿到一部分的同步结果,
举一个,两个微任务中创建微任务的详细例子
setTimeout(_ => console.log(1))
new Promise(resolve => {
resolve()
console.log('Promise 1')
}).then(_ => {
console.log('Promise 1 then')
Promise.resolve().then(_ => {
console.log('Promise 2 then')
}).then(_ => {
Promise.resolve().then(_ => {
console.log('Promise 3 then')
})
})
})
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2() {
console.log('async2')
}
async1();
console.log(6)
// async1执行前 async1 start async2 -1 aa 1 6 async2 -2 bb1 async1 end 1
宏任务里创建微任务
setTimeout(() => 微任务方法),ps:函数里返回微任务方法
setTimeout(() => new Promise(resolve => {
console.log('setTimeout1 start')
resolve();
console.log(4)
}).then(_ => {
console.log(5)
}))
setTimeout(() => new Promise(resolve => {
console.log('setTimeout2 start')
resolve();
console.log(24)
}).then(_ => {
console.log(25)
}))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
// 结果值:1 2 3 setTimeout1 start 4 5 setTimeout2 start 24 25
当多个宏任务时,会先将每个宏任务中的数值都处理完后,才会去做下一个宏任务处理,不管里面是普通的同步任务还是微任务,都要完全处理完一个宏任务,才能处理下一个
setTimeout(微任务方法)
这个时候,相当于setTimeout没有相应的宏任务回调方法!!!! 因为在setTimeout(() => 操作)中,后面的操作才属于宏任务方法,前面的方法属于普通方法,如果前面是微任务方法,那就按微任务方法执行,若前面是同步方法,那就按同步方法逻辑执行
setTimeout(new Promise(resolve => {
console.log('setTimeout1 start')
resolve();
console.log(4)
}).then(_ => {
console.log(5)
}))
setTimeout(new Promise(resolve => {
console.log('setTimeout2 start')
resolve();
console.log(24)
}).then(_ => {
console.log(25)
}))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
// 结果值:setTimeout1 start 4 setTimeout2 start 24 1 2 5 25 3
因为setTimeout中方法不是()=> 操作信息,这样的返回值,并且内部的方法是微任务方法,所以此时,setTimeout中的方法按照本身方法类型处理,现在他是promise微任务,自上而下顺序里,优先推入微任务队列里,一共有3个微任务,微任务.then之前是同步的,所以直接同步处理,得到上面结果
微任务中添加宏任务
setTimeout(_ => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
Promise.resolve().then(_ => {
console.log('before timeout')
}).then(_ => {
setTimeout(() => {
console.log('微任务中的宏任务1')
})
})
})
new Promise(resolve => {
resolve()
console.log(21)
}).then(_ => {
console.log(23)
Promise.resolve().then(_ => {
console.log('before timeout2')
}).then(_ => {
setTimeout(() => {
console.log('微任务中的宏任务2')
})
})
})
console.log(2)
// 结果值:
// 1 21 2 3 23 before timeout before timeout2 4 微任务中的宏任务1 微任务中的宏任务2
按顺序推入微任务队列和宏任务队列中,在前面的会优先处理,因为微任务中的宏任务是后被推入进队列中的,那么就后处理
如果在微任务中的有需要宏任务处理后才能拿到的数据,则先处理当下的宏任务,处理完了,在处理微任务!!!!相当于重新搞了一波写法,就是异步放在setTimeout中执行了!!!
微任务中有宏任务,并且then中的信息需要依赖宏任务处理后才能拿到值,即resolve/reject放在了setTimeout中
setTimeout(() => {
new Promise((resolve, reject) => {
console.log(8)
resolve(9)
}).then(r => {
console.log(r)
})
})
new Promise((resolve, reject) => {
console.log(1);
setTimeout(() => {
console.log(2);
new Promise((resolve, reject) => {
console.log(18)
resolve(19)
}).then(r => {
console.log(r)
})
resolve(3);
}, 0)
console.log(4)
}).then(r => {
new Promise((re, rj) => {
setTimeout(() => {
console.log(5);
})
console.log(6);
})
console.log(r)
});
console.log(7);
setTimeout(() => {
console.log(10)
})
// 1,4,7,8,9,2,18,19,6,3,10,5
先执行同步任务打印出来1、4、7,然后将宏任务、微任务都推入各自的数组中去
hong = [
// 第一个
() => {
new Promise((resolve, reject) => {
console.log(8)
resolve(9)
}).then(r => {
console.log(r)
})
}
// 第二个(微任务的同步模块中的setTimeout)
() => {
console.log(2);
new Promise((resolve, reject) => {
console.log(18)
resolve(19)
}).then(r => {
console.log(r)
})
// 相当于在这重新做了一个then的转换!!!!!!!!!!!!!
new Promise((resolve, reject) => {
resolve(3);
}).then(r => {
new Promise((re, rj) => {
setTimeout(() => {
console.log(5);
})
console.log(6);
})
console.log(r)
})
// 第三个
() => {
console.log(10)
}
]
wei = [
]
如果Promise.then中的值依赖于setTimeout中的执行结果,那就直接把then方法放在setTimeout中执行,最简化这个数据
参见上面第二个宏任务信息,直接将之前的Promise中的then方法,做一个转换放置在resolve(3)的那个位置上,直接这样得出信息值
node中
宏任务处理不是等前一个宏任务处理完才执行,microtask 会在事件循环的各个阶段之间执行,也就是一个阶段执行完毕,就会去执行 microtask 队列的任务
setTimeout(()=>{
console.log('timer1')
Promise.resolve().then(function() {
console.log('promise1')
})
}, 0)
setTimeout(()=>{
console.log('timer2')
Promise.resolve().then(function() {
console.log('promise2')
})
}, 0)
// 结果为: timer1=>timer2=>promise1=>promise2