JavaScript 事件循环,我的理解

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/

JavaScript 单线程

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。

JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。

事件循环

Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。

宏任务&&微任务

Javascript单线程任务被分为同步任务和异步任务,同步任务会在调用栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将注册的回调函数放入任务队列中等待主线程空闲的时候,被读取到栈内等待主线程的执行。

宏任务->同步任务:执行代码、setTimeout、setInterval等
微任务->异步任务:Promise等

【Tasks】 are scheduled so the browser can get from its internals into JavaScript/DOM land and ensures these actions happen sequentially. Between tasks, the browser may render updates. Getting from a mouse click to an event callback requires scheduling a task, as does parsing HTML, and in the above example, setTimeout.

setTimeout waits for a given delay then schedules a new task for its callback. This is why setTimeout is logged after script end, as logging script end is part of the first task, and setTimeout is logged in a separate task. Right, we're almost through this, but I need you to stay strong for this next bit…

【Microtasks】 are usually scheduled for things that should happen straight after the currently executing script, such as reacting to a batch of actions, or to make something async without taking the penalty of a whole new task. The microtask queue is processed after callbacks as long as no other JavaScript is mid-execution, and at the end of each task. Any additional microtasks queued during microtasks are added to the end of the queue and also processed. Microtasks include mutation observer callbacks, and as in the above example, promise callbacks.

运行流程

JavaScript代码运行时,首先整体代码作为一个宏任务加入到同步任务队列中首先运行,如果遇到上面定义的宏任务将其加入到同步任务队列中,遇到微任务将其加入到异步任务中,如果宏任务里面包含了微任务,将作为该宏任务的子集进行运行

例子


console.log('script start');

setTimeout(function () {console.log('setTimeout');

Promise.resolve()
  .then(function () {
    console.log('promise3');
  })
  .then(function () {
    console.log('promise4');
  });
}, 0);

function a (){
Promise.resolve()
  .then(function () {
    console.log('promise5');
  })
  .then(function () {
    console.log('promise6');
  });
	console.log('b')
	return true
}
if(a()){
	console.log('a')
}

Promise.resolve()
  .then(function () {
    console.log('promise1');
  })
  .then(function () {
    console.log('promise2');
  });

console.log('script end');

运行结果解析:

第一次清理宏任务:
整体为宏任务Task1
log出script start
然后遇到setTimeout将其作为宏任务加入到同步任务队列Task2
遇到函数,等待调用
遇到代码块执行函数,函数里面有Promise将其加入到位任务 Microtasks1
执行代码输出b 然后是a
继续执行代码遇到Promise将其加入到微任务 Microtasks2
log出script end

第一次宏任务结束输出结果为:
script start
b
a
script end

第一次清理微任务:
宏任务结束将清理微任务,现在有哪些呢Microtasks1,Microtasks2
先执行Microtasks1,输出promise5,然后遇到then加入到微任务Microtasks3,
执行Microtasks2,输出promise1,然后遇到then加入到微任务Microtasks4,
执行完查看微任务还有Microtasks3,Microtasks4
先执行Microtasks3,输出promise6,
执行Microtasks4,输出promise1,

第一次清理Task1下的微任务结果:
promise5
promise1
promise6
promise2

检测现在还有宏任务Task2,
输出setTimeout,遇到Promise添加到微任务Microtasks
Task2执行完毕,还有一个微任务Microtasks
执行完毕输出
promise3
promise4

所以整体结果为:

##Start Task1
script start
b
a
script end
##End Task1

##Start 清理Task1下为微任务
promise5
promise1
promise6
promise2
##End 清理Task1下为微任务

##Start Task2
setTimeout
##EndTask2

##Start 清理Task下为微任务
promise3
promise4
##End 清理Task下为微任务
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老虎爱代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值