js sleep函数_[JS基础] 6 - 执行机制, 同步异步, Event Loop, 宏任务, 微任务

cef341539a340eb89ae72fe226625c4c.png
# 事件循环 Event Loop
本质是: 
1. 作为单线程js对于异步事件的处理机制 

2. 或者可以说是 只有一个主线程js的处理逻辑

3. 如何保证主线程, 有序并高效 或非阻塞 的处理呢? => 事件循环机制 Event Loop

4. 异步任务也是有优先级的,分为 宏任务 MacroTask, 微任务 MicroTask

你也可能会碰到以下问题:

- js如何处理 同步 和 异步? 
- 什么是事件循环机制?  
- 异步的宏任务和微任务区别? 
- 执行流程优先级又是什么?

1- 单线程 js 按照语句出现顺序执行

一道题看懵你, 这个输出结果并不是按照语句顺序阿~

setTimeout

结果:

  • 马上执行for循环啦
  • 代码执行结束
  • 执行then函数啦
  • 定时器开始啦

2- 事件循环 Event Loop

  • js是单线程, 那么相当于只有一个柜台窗口的银行, 要一个个顺序的处理业务。前面一个任务是要存款1000w 办理时间长, 后面存款10w的就要等着。
  • 怎么能更高效的处理同步和异步的任务呢?
  • 那么问题是: 如果浏览器加载一张图片非常的慢需要10s, 难道要等着其下载完,才能执行点击 或 其他操作吗?
  • 事件循环机制: 本质上是js对异步处理机制。

任务:

  1. 同步任务
  2. 异步任务

e82026da6ef84963eaaa5acc966fe58f.png
  • 同步和异步的任务分别进入不同的执行场所。
  • 同步直接在主线程执行,异步的回调 则去小黑屋,等待着,时机到了才会被运行。
  • 当同步任务在主线程中全部执行完毕后,再去事件队列中执行 异步回调的函数,并进入主线程执行。
  • 上述过程不断重复。叫作 事件循环机制

2.1- 例子1

axios
  • axios 请求
  • 异步回调函数 放入异步队列中
  • 执行console.log(2) 主线程空 则执行异步队列中的函数
  • console.log(1) 被执行

2.2- 例子2 setTimeout

你会发现console.log('延时3秒'); 输出的不是3s, 是5s, 超过3s.

<
  • setTimeout执行, 3s后, 将 回调函数 放到 异步队列中 [3s => '延时3秒']
  • 执行sleep函数, 停止5s
    当sleep函数执行到3s的时候, 异步函数返回值可执行, 但是因为sleep占用主线程, 只能等待
  • 5s后, 主线程空了, 执行输出 '延时3秒'
  • 所以,此时延迟是大于5s

3- 宏任务 和 微任务

  • 宏任务 macro task: script代码, setTimeout, setInterval
  • 微任务 micro task: Promise.then, process.nextTick

异步的事件队列 还分是去 宏任务 还是去 微任务 !

  • 同步
  • 微任务异步队列(Micro Event Queue)
  • 宏任务异步队列(Macro Event Queue)
<script>
setTimeout(() => {
    console.log('setTimeout 宏任务: 异步队列')
})

console.log('宏任务: 同步队列 = 1')

new Promise(resolve => {
    resolve('666')
    console.log('promise 任务先执行, then才是微任务处理')
}).then(data => {
    console.log('promise.then 微任务执行', data)
})

console.log('宏任务: 同步队列 = 2')
</script>

- 宏任务: 同步队列 = 1
- promise 任务先执行, then才是微任务处理
- 宏任务: 同步队列 = 2
- promise.then 微任务执行 666
- setTimeout 宏任务: 异步队列
  1. setTimeout 先执行, 将回调函数放到 异步队列中, 等待执行 MacroQueue = [0s=> 'setTimeout 宏任务: 异步队列']
  2. 输出 => '宏任务: 同步队列 = 1'
  3. new Promise立即被执行
  4. 输出 => 'promise 任务先执行, then才是微任务处理'
  5. then 放入 MicroQueue = [then=> 'promise.then 微任务执行' + data ]
  6. 输出 => '宏任务: 同步队列 = 2'
  7. 主线程空了,可以执行异步的事情。
  8. 先去执行 MicroQueue, 再去执行MacroQueue
  9. 输出 => promise.then 微任务执行 666
  10. 输出 => setTimeout 宏任务: 异步队列

4- 宏任务 和 微任务 执行顺序?

宏任务 macro task: script代码, setTimeout, setInterval
微任务 micro task: Promise.then, process.nextTick
  • 同步任务线进入主线程执行
  • 异步处理还分为: macro宏任务, micro 微任务
  • micro 微任务优先级优于macro宏任务
  • 优先级: 同步任务 > micro 微任务 > macro宏任务

ea240cb5237526295be89cf21cd8ad58.png
// 同步, 异步宏任务macro, 异步微任务micro

步骤分析

1. 输出 => 1
2. 放入宏任务 异步队列中 MacroEventQueue = [setTimeout1]
3. 放入微任务 异步队列中 MicroEventQueue = [process1]
4. promise先执行
   输出 => 7
   将promise.then 放入微任务 异步队列中 MicroEventQueue = [process1, promise.then]
5. 放入宏任务 异步队列中 MacroEventQueue = [setTimeout1, setTimeout2]
6. 此时同步已经执行完了, 主线程空闲, 先执行MicroEventQueue, 再执行MacroEventQueue
7. 先执行MicroEventQueue = [process1, promise.then]
8. 输出 => 6
9. 输出 => 8
10. MicroEventQueue已空, 执行MacroEventQueue
11. MacroEventQueue = [setTimeout1, setTimeout2]
12. 输出 => 2
    MicroEventQueue = [process2]
    Promise立刻执行
    输出 => 4
    Promise.then放到 MicroEventQueue = [process2, promise.then__setTimeout1]
13. 此时剩下 MacroEventQueue = [setTimeout2] MicroEventQueue = [process2, promise.then__setTimeout1]
    MicroEventQueue不为空, 先执行
    输出 => 3
    输出 => 5
    此时剩下 MacroEventQueue = [setTimeout2] MicroEventQueue 空

14. MacroEventQueue = [setTimeout2]
    输出 => 9
    MicroEventQueue = [process3]
    Promise立刻执行
    输出 => 11
    MicroEventQueue = [process3, promise.then__setTimeout2]

15. 此时 MacroEventQueue 空, MicroEventQueue = [process3, promise.then__setTimeout2]
    输出 => 10
    输出 => 12

5- Recap

  • js单线程,同步阻塞
  • 同步和异步。同步优于异步在主线程中执行, 只有主线程空闲, 异步才能被执行
  • 事件循环机制,异步的解决方案 / 机制
  • 事件循环机制 => macro 宏任务 和 micro任务
  • 最后: 优先级 同步 > micro任务 > macro 宏任务

6- 整体总结

js是单线程, 也就是说只有一个 主线程执行

不恰当例子有助于理解:
银行就一个柜台, 好多人去排队。
每个人的业务不同, 有人就是交水电费, 办理存款业务的人花费时间多些
如何提高银行的办事儿效率?

规定, 我们暂定按照处理时间来算优先级
1. 交水电费优先级更高些 (花费10ms)
2. 办理存款业务的人低优先级 (花费1s)
   - 存款10w (花费10s) 
   - 存款1个亿 (花费100s)

按照花费的时间算优先级
- 交水电费 (同步) 直接在主线程运行
- 办理存款业务 另外开个小窗口, 毕竟是VIP大客户, 处理存款
- 存款10w 放到 Micro Event Queue 微任务队列中
- 存款1个亿 放到 Macro Event Queue 宏任务队列中

优先级: 同步任务 > Micro Event Queue 异步微任务队列 > Macro Event Queue 异步宏任务队列

事件循环: 一旦发现优先级比自己高的, 要去执行高的, 让出主线程, 等前一个优先级任务空了, 再执行后面的。

如何管理 同步和异步 在主线程的处理逻辑?

- 同步: 优先级更高在主线程处理掉, 异步只能等同步处理完, 再处理.

Event Loop 事件循环
- 异步: 也分369等, 宏任务和微任务之分.
  微任务: promise.then, process.nextTick
  宏任务: setTimeout, setInterval, axios回调, 正常js逻辑等

- 优先级: 同步 > 异步(微任务) > 异步(宏任务)

7 - 题巩固一下

7.1 - 题1

console
  • 输出 => script start
  • setTimeout放到macro queue 等到主线程空运行
  • Promise.resolve()里的立刻执行,then后的都放到micro queue 等待运行
  • 输出 => script end
  • micro queue 优先 macro queue
  • 输出 => promise1
  • 输出 => promise2
  • 输出 => setTimeout

7.1 - 题2

注意async, await 的用法 和 promise的关系

console
  • 输出 => script start
  • async1() 立即执行
  • await async2() 立即执行, 后面的code, 相当于放到promise.then(...)
// 重点
  • 输出 => script start
  • 输出 => async2 end await async2() = new Promise(xxx) 一样会立刻执行
  • console.log('async1 end') 被放到micro queue中 = await下一行 相当于 promise.then后内容
  • setTimeout 放到 macro queque中
  • 输出 => Promise, 两个then的内容放到micro queue中
  • 输出 => script end
  • 执行 micro queue
  • 输出 => async1 end
  • 输出 => promise1
  • 输出 => promise2
  • 执行 macro queue
  • 输出 => setTimeout

7.3 - 题3

console
  • 输出 => start
  • setTimeout 进入 marco queue
  • setTimeout 进入 marco queue
  • Promise.resolve()立即执行,then放到 micro queue
  • 输出 => end
  • 先执行 micro queue
  • 输出 => promise3
  • marco queue执行
  • 输出 => timer1
  • Promise.resolve()立即执行,then放到 micro queue
  • 因为micro queue 优先级 > marco queue
  • 输出 => promise1 此时micro queue已清空
  • marco queue执行
  • 输出 => timer2
  • 输出 => promise2
  • 如果你用浏览器去执行,下面即使答案。同步 > micro任务 > macro 宏任务
  • 如果你用Node11+版本,和浏览器行为一致。同步 > micro任务 > macro 宏任务
  • 如果你是Node10以下版本,输出为: 当macro为空才去执行micro。
start
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值