(1) JS是单线程语言
(2) JS的Event Loop是JS的执行机制。深入了解JS的执行,就等于深入了解JS里的event loop
1.灵魂三问 : JS为什么是单线程的? 为什么需要异步? 单线程又是如何实现异步的呢?
技术的出现,都跟现实世界里的应用场景密切相关的。
同样的,我们就结合现实场景,来回答这三个问题
(1) JS为什么是单线程的?
JS最初被设计用在浏览器中,那么想象一下,如果浏览器中的JS是多线程的。
场景描述:
那么现在有2个线程,process1 process2,由于是多线程的JS,所以他们对同一个dom,同时进行操作
process1 删除了该dom,而process2 编辑了该dom,同时下达2个矛盾的命令,浏览器究竟该如何执行呢?
这样想,JS为什么被设计成单线程应该就容易理解了吧。
(2) JS为什么需要异步?
场景描述:
如果JS中不存在异步,只能自上而下执行,如果上一行解析时间很长,那么下面的代码就会被阻塞。
对于用户而言,阻塞就意味着"卡死",这样就导致了很差的用户体验
所以,JS中存在异步执行。
(3) JS单线程又是如何实现异步的呢?
既然JS是单线程的,只能在一条线程上执行,又是如何实现的异步呢?
是通过的事件循环(event loop),理解了event loop机制,就理解了JS的执行机制
2.JS中的event loop
js 当执行异步代码 会把任务放到任务栈中,不同的任务会分配到不同的任务栈中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask) Event Loop执行顺序如下:
当执行完所有同步代码后,执行栈为空,查询是否有异步代码需要执行
然后开始下一轮Event Loop,执行宏任务中的异步代码,也就是setTimeout中的回调函数
微任务包括:
promise.then 或者 promise.resolve 里的内容
宏任务:
new Promise(fn) 中的fn 举个经典例子
这里首先要明白async和await写法对于promise的关系 async仅相当于定义时宣布此函数里有异步操作。await相当于暂停,await后面的代码相当于放到promise的then当中。await 里函数的代码相当于放到创建promise的new函数之中 接下来解析上面代码 首先执行第一轮宏任务
console.log('script start') 同步任务直接执行
遇到async2() 将await后的函数放入至微服务之中,同时执行async2()
console.log('async2 end')
遇到settimeout 放到宏任务等待下一轮执行
new 对象创建一个promise 创建的过程是非异步的,直接console.log('Promise') 同时将两个then函数放入微服务队列中等待执行
console.log('script end')
检测该论循环中微服务队列,首先打印console.log('async1 end')
然后按顺序打印两个then console.log('promise1') console.log('promise2')
打印console.log('setTimeout')
node中的事件循环和浏览器中的事件循环大体相似,不过整体上分了多个阶段这里不展开描述 参考文章: 10分钟理解JS引擎的执行机制