1.同步和异步
同步与异步是指访问数据的机制,同步一般指主动请求并等待IO操作完成的方式。
异步则指主动请求数据后便可以继续处理其它任务,随后等待IO操作完毕的通知。
同步和异步最大的区别就在于:同步需要等待,异步不需要等待。
同步请求存在着两个明显的缺陷:
① 请求发出后必须要等待响应
比如当遇到请求阻塞,网络延迟等情况时,用户需要进行等待,这样会导致用户体验效果差。
② 每次请求都需要重新加载整个页面
比如在访问某个页面时,有的时候用户可能只需要请求获取页面某一部分内容的响应,但是当用户发送请求后,整个页面的所有内容都需要重新加载后再响应给用户,这样同样会导致用户的体验较差。
2.宏任务与微任务
在当前的微任务没有执行完成时,是不会执行下一个宏任务的。
setTimeout(_ => console.log(4),0)
new Promise(resolve => {
resolve()
console.log(1)
}).then(_ => {
console.log(3)
})
console.log(2)
setTimeout
就是作为宏任务来存在的,而Promise.then
则是具有代表性的微任务
所有会进入的异步都是指的事件回调中的那部分代码
也就是说new Promise
在实例化的过程中所执行的代码都是同步进行的,而then
中注册的回调才是异步执行的。
在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,
而微任务又会在宏任务之前执行(因为微任务实际上是宏任务的其中一个步骤).
所以就得到了上述的输出结论1、2、3、4
。
+部分表示同步执行的代码
+setTimeout(_ => {
- console.log(4)
+})
+new Promise(resolve => {
+ resolve()
+ console.log(1)
+}).then(_ => {
- console.log(3)
+})
+console.log(2)
本来setTimeout
已经先设置了定时器(相当于取号),然后在当前进程中又添加了一些Promise
的处理(临时添加业务)。
所以进阶的,即便我们继续在Promise
中实例化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)
实际情况下很少会有简单的这么调用
Promise
的,一般都会在里边有其他的异步操作,比如fetch
、fs.readFile
之类的操作。
而这些其实就相当于注册了一个宏任务,而非是微任务。
async/await函数
async/await
本质上还是基于Promise
的一些封装,而Promise
是属于微任务的一种。所以在使用
await
关键字与Promise.then
效果类似:
setTimeout(_ => console.log(4))
async function main() {
console.log(1)
await Promise.resolve()
console.log(3)
}
main()
console.log(2)
async函数在await之前的代码都是同步执行的,可以理解为await之前的代码属于new Promise
时传入的代码,await之后的所有代码都是在Promise.then
中的回调
宏任务
# | 浏览器 | Node |
---|---|---|
I/O | ✅ | ✅ |
setTimeout | ✅ | ✅ |
setInterval | ✅ | ✅ |
setImmediate | ❌ | ✅ |
requestAnimationFrame | ✅ | ❌ |
微任务
# | 浏览器 | Node |
---|---|---|
process.nextTick | ❌ | ✅ |
MutationObserver | ✅ | ❌ |
Promise.then catch finally | ✅ | ✅ |
相关面试题
JS执行机制是从上到下执行,同步代码优先异步代码,微任务优先宏任务执行
async function async1() { console.log('async1 start') await async2() console.log('async1 end') // 相当于promise.then的异步回调 } async function async2() { console.log('async2') } console.log('script start') setTimeout(function () { // 定时器作为宏任务的存在 console.log('setTimeout') }, 0) async1() new Promise(function (resolve) { console.log('promise1') resolve() }).then(function () { console.log('promise2') }) console.log('script end') // 'async1 start' // 'script start' // 'async2' // 'promise1' // 'script end' // 'async1 end' // 'promise2' // 'setTimeout'