JS执行机制(事件循环)

JS执行机制

一、运行机制
  1. JS分为同步任务和异步任务。
  2. 所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
  3. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  4. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  5. 主线程不断重复上面的第三步。
二、宏任务、微任务
  1. macro-task(宏任务):包括执行整体的js代码,事件回调,XHR回调,定时器(setTimeout/setInterval/setImmediate),IO操作,UI render。
  2. micro-task(微任务):包括promise回调,MutationObserver,process.nextTick,Object.observe。
三、事件循环
  1. 检查macrotask队列是否为空,非空则到2,为空则到3
  2. 执行macrotask中的一个任务
  3. 继续检查microtask队列是否为空,若有则到4,否则到5
  4. 取出microtask中的任务执行,执行完成返回到步骤3
  5. 执行视图更新
四、练习
console.log('start');

setTimeout(()=>{
  console.log('settimemout')
},0)

new Promise((resolve)=>{
  console.log('promise')
  resolve()
  new Promise((resolve)=>{
    setTimeout(resolve,0)
  }).then(()=>{
    console.log('promise1')
  })
}).then(()=>{
  console.log('promise2')
}).then(()=>{
  console.log('promise3')
})

console.log('end')
// start	promise		end		promise2	promise3	settimeout	promise1

首先,全局代码压入调用栈执行,打印start;

接下来setTimeout放入macrotask队列,promise压入调用栈执行打印,外层promise.then回调放入microtask队列,setTimeout(resolve,0)放入macrotask队列,最后end被压入调用栈执行打印;

至此,调用栈中的代码被执行完成,回顾macrotask的定义,我们知道全局代码属于macrotask,macrotask执行完,那接下来就是执行microtask队列的任务了,执行外层promise.then回调打印promise2;

promise回调函数默认返回undefined,promise状态变为fullfill触发接下来的then回调,继续压入microtask队列,event loop会把当前的microtask队列一直执行完,此时执行外层第二个promise.then回调打印出promise3;

这时microtask队列已经为空,从上面的流程图可以知道,接下来主线程会去做一些UI渲染工作(不一定会做),然后开始下一轮event loop,执行setTimeout的回调,打印出setTimeout,执行setTimeout(resolve,0)回调,将内层promise回调放入microtask队列;

至此,macrotask队列已经为空,接下来是microtask队列的任务,将执行内层promise回调,打印promise1

这个过程会不断重复,也就是所谓的事件循环。

button.addEventListener('click', function( ev){
   Promise.resolve().then(()=>{console.log('microTask 1')});
   console.log('你点了一下');
}, true);
button.addEventListener('click', function(ev){
   Promise.resolve().then(()=>{console.log('microTask 2')})
   console.log('你又点了一下');
}, true);
  1. 对于以上代码,用户点击button按钮与使用JS触发button按钮的执行顺序并不相同。
    当用户点击button按钮时,其执行结果为:
// 你点了一下
// microTask 1
// 你又点了一下
// microTask 2

当用户点击按钮时,首先将第一个事件监听压入调用栈,promise.then回调放入microtask队列。然后主栈执行,打印“你点了一下”,主栈清空,microtask队列执行,打印“microtask 1"。
第二个事件监听同理。

  1. 当使用Js触发button按钮点击时,其执行结果为:
button.click();
// 你点了一下
// 你又点了一下
// microTask 1
// microTask 2

当JS触发button点击时,主栈压入click()事件,click开始执行调度第一个事件监听,此时打印“你点了一下”,“microtask 1"放入微任务队列,接着click执行第二个事件监听,此时打印“你又点了一下”,“microtask 2"放入微任务队列。此时两个事件监听执行完毕,主栈清空,开始执行微任务队列,依次打印“microtask 1”、“microtask 2”。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值