深入理解JS执行机制

简介: 深入理解JS执行机制

前言            

JavaScript是一门单线程的非阻塞脚本语言,同一时刻只允许一个代码段执行。在单线程的机制下,执行异步任务时,在等待结果返回的这个时间段,后面的代码就无法执行了。


JS在执行代码时,遇到异步任务之后还有同步任务的场景时,它并不会等待异步任务执行完,而是先执行同步任务,那么JS是如何做到这一点的呢?


本篇文章将详细讲解上述问题,欢迎各位感兴趣的开发者阅读本文。


事件循环


单线程


讲事件循环之前,我们先来理解下为什么JS不设计成多线程的。


我们做个假设,如果JS是多线程的,因为JS有DOM API可以操作DOM,此时如果有两个线程在操作同一个DOM,线程1删除了这个dom节点,线程2要操作这个dom,就会产生矛盾,到底以哪个线程为主。


为了避免这种情况的出现,JS就被设计成了单线程


宏任务与微任务


JS引擎把所有任务分为两类:宏任务、微任务。


宏任务有:


  • script整体代码
  • setTimeout、setInterval
  • I/O
  • UI渲染
  • postMessage
  • MessageChannel
  • requestAnimationFrame
  • setImmediate(Node.js 环境)


微任务有:


  • new Promise.then()
  • MutaionObserver
  • process.nextTick(Node.js 环境)


执行规则


文章一开头我们了解到了单线程的弊端,JS是通过事件循环机制(EventLoop)来解决这一弊端的,接下来我们来看下EventLoop的执行规则:


  • 所有代码作为宏任务进入主线程执行栈,开始执行
  • 执行过程中,同步代码会立即执行,宏任务进入宏任务队列,微任务进入微任务队列
  • 当前宏任务执行完成出队,读取微任务队列,有则执行,直至全部执行完毕
  • 执行浏览器ui进程渲染
  • 检查是否有webworker任务,有则执行
  • 本轮宏任务执行完成,回到第2步,继续执行,直至宏任务与微任务队列全部清空


举例说明


我们了解完它的执行规则后,接下来我们举个例子来说明下,如下所示:


console.log("1"); // 1 同步代码:立即执行 [1]
setTimeout(function() {
  console.log("2"); // 3 同步代码执行执行 输出2
  process.nextTick(function() {
    console.log("3"); // 4 进入微任务队列 [3]
  });
  new Promise(function(resolve) {
    console.log("4"); // 3 同步代码执行执行 输出4
    resolve();
  }).then(function() {
    console.log("5"); // 4 进入微任务队列 [3, 5]
  });
});
process.nextTick(function() {
  console.log("6"); // 2 进入微任务队列 [6]
});
new Promise(function(resolve) {
  console.log("7"); // 1 宏任务:立即执行 [1, 7]
  resolve();
}).then(function() {
  console.log("8"); // 2 进入微任务队列 [6, 8]
});
setTimeout(function() {
  console.log("9"); // 5 宏任务:立即执行 [9]
  process.nextTick(function() {
    console.log("10"); // 6 进入微任务队列 [10]
  });
  new Promise(function(resolve) {
    console.log("11"); // 5 宏任务:立即执行 [9, 11]
    resolve();
  }).then(function() {
    console.log("12"); // 6 进入微任务队列 [10, 12]
  });
});
// 执行顺序:1 7 6 8 2 4 3 5 9 11 10 12


process.nextTick()为node中的方法,你可以把它理解为与promise一样的微任务,promise的executor函数中的同步代码会立即执行。


我们来分析下上述代码的执行顺序,如下图所示:

640.png

                                      image.png


运行结果如下所示:

640.png

                                            image.png


当你把上述示例代码啃透后,那么你也就理解js的事件循环机制了。

当然,你可能没有那么快就啃透这个例子,这种概念性的东西,掌握它最好的办法就是:将示例代码放到编辑器里,对照着事件循环的执行规则,一行一行的去读代码,大脑过一遍,猜测运行结果,然后再去执行代码判断执行结果是否与你猜的一致。

最后,举一反三,去网上找一些事件循环的面试题多加练习,慢慢的你就把这个知识点啃透了,Good Luck!


代码地址


本文为《JS原理学习》系列的第5篇文章,本系列的完整路线请移步:JS原理学习 (1) 》学习路线规划


本系列文章的所有示例代码,请移步:js-learning


写在最后


至此,文章就分享完毕了。


我是神奇的程序员,一位前端开发工程师。


如果你对我感兴趣,请移步我的个人网站(www.kaisir.cn),进一步了解。


  • 公众号无法外链,如果文中有链接,可点击下方阅读原文查看😊
相关文章
|
4月前
|
存储 JavaScript 前端开发
深入理解JavaScript中的事件循环(Event Loop):机制与实现
【10月更文挑战第12天】深入理解JavaScript中的事件循环(Event Loop):机制与实现
170 3
|
3月前
|
Web App开发 JSON JavaScript
Node.js 中的中间件机制与 Express 应用
Node.js 中的中间件机制与 Express 应用
|
5月前
|
JavaScript 安全 前端开发
乾坤js隔离机制
乾坤js隔离机制
|
3月前
|
JavaScript 安全 中间件
深入浅出Node.js中间件机制
【10月更文挑战第36天】在探索Node.js的奥秘之旅中,中间件的概念如同魔法一般,它让复杂的请求处理变得优雅而高效。本文将带你领略这一机制的魅力,从概念到实践,一步步揭示如何利用中间件简化和增强你的应用。
|
3月前
|
消息中间件 JavaScript 中间件
深入浅出Node.js中间件机制
【10月更文挑战第24天】在Node.js的世界里,中间件如同厨房中的调料,为后端服务增添风味。本文将带你走进Node.js的中间件机制,从基础概念到实际应用,一探究竟。通过生动的比喻和直观的代码示例,我们将一起解锁中间件的奥秘,让你轻松成为后端料理高手。
57 1
|
4月前
|
移动开发 JavaScript 前端开发
【JavaScript】JS执行机制--同步与异步
【JavaScript】JS执行机制--同步与异步
39 1
|
4月前
|
JSON JavaScript 中间件
深入浅出Node.js中间件机制
本文将带你探索Node.js中一个核心概念——中间件机制。我们将通过浅显的语言和生动的比喻,揭示中间件如何作为请求和响应之间的“交通枢纽”,在应用程序中起到至关重要的作用。从基础原理到实际应用,你将了解到中间件不仅简化了代码结构,还提高了开发效率,是Node.js开发不可或缺的一部分。
72 1
|
4月前
|
JavaScript 前端开发 开发者
原型链深入解析:JavaScript中的核心机制
【10月更文挑战第13天】原型链深入解析:JavaScript中的核心机制
52 0
|
4月前
|
JavaScript 安全 中间件
深入浅出Node.js中间件机制
【10月更文挑战第4天】在探索Node.js的海洋中,中间件机制犹如一座灯塔,为开发者指引方向。本文将带你一探究竟,从浅入深地理解这一核心概念。我们将通过生动的比喻和实际代码示例,揭示中间件如何在请求和响应之间搭建桥梁,实现功能的扩展与定制。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
76 0
|
5月前
|
缓存 JavaScript 前端开发
常见的 JavaScript 隔离机制
常见的 JavaScript 隔离机制

热门文章

最新文章