单线程JavaScript为何如此高效

简介: 什么是js执行机制 JavaScript 的执行机制指的是 JavaScript 代码在运行时的工作方式和顺序

原文合集地址如下,有需要的朋友可以关注

本文地址

合集地址

什么是js执行机制

JavaScript 的执行机制指的是 JavaScript 代码在运行时的工作方式和顺序。它涉及以下几个关键概念:

  1. 单线程:JavaScript 是一门单线程的编程语言,意味着它只有一个主线程用于执行代码。这意味着 JavaScript 中的代码是按顺序执行的,一次只能执行一个任务。

  2. 任务队列:JavaScript 通过任务队列来管理要执行的任务。任务队列中存放着各种类型的任务,包括同步任务和异步任务。

  3. 事件循环:JavaScript 的事件循环是一个持续运行的过程,它负责监视任务队列并选择下一个要执行的任务。事件循环不断地从任务队列中获取任务并将其交给主线程执行。

  4. 同步任务和异步任务:同步任务是按照顺序在主线程上执行的任务,执行一个任务时会阻塞后续任务的执行。异步任务是在主线程上注册并在将来某个时间点执行的任务,执行异步任务时不会阻塞后续任务的执行。

  5. 微任务和宏任务:JavaScript 中的任务可以分为微任务和宏任务。微任务是在当前任务执行完毕后立即执行的任务,它们使用微任务队列进行管理。而宏任务是在事件循环的下一轮中执行的任务,它们使用任务队列进行管理。

JavaScript 的执行顺序:

  1. 执行同步任务,将函数调用和变量分配到调用栈中按顺序执行。

  2. 遇到异步任务,如定时器、事件监听等,将其注册到任务队列中,并继续执行后续的同步代码。

  3. 当同步代码执行完毕后,主线程会检查微任务队列,依次执行队列中的微任务。

  4. 执行完微任务后,主线程会从任务队列中取出一个宏任务执行。

  5. 循环执行步骤 3 和步骤 4,直至任务队列和微任务队列都为空。

需要注意的是,JavaScript 中的异步任务通常是通过回调函数、Promise、async/await 等机制来处理。通过合理使用异步任务和任务队列,可以实现非阻塞的代码执行,提高代码的性能和响应能力。JavaScript 的执行机制主要涉及以下几个概念:调用栈、事件循环和任务队列。文字有点单调,看看下面的图理解理解
在这里插入图片描述
让我们通过一个例子来解释这些概念。假设我们有以下代码:

console.log("Script start");

setTimeout(function() {
   
   
  console.log("setTimeout");
}, 0);

Promise.resolve().then(function() {
   
   
  console.log("Promise");
});

console.log("Script end");

这段代码的执行机制如下:

  1. 首先,开始执行代码,遇到第一行 console.log("Script start"),它会立即打印 "Script start"。

  2. 接下来,遇到 setTimeout,它是一个异步函数,会被放入任务队列中,并设置一个定时器。由于定时器时间为 0,所以不会立即执行。

  3. 然后,遇到 Promise.resolve().then(),它会创建一个 Promise 对象,并将 .then() 中的回调函数放入微任务队列中。

  4. 继续执行下一行,打印 "Script end"。

  5. 此时,主线程上的同步代码执行完毕,开始执行微任务队列中的任务。首先执行 Promise 的回调函数,打印 "Promise"。

  6. 接着,主线程开始执行任务队列中的任务。由于定时器时间到达,setTimeout 的回调函数被放入任务队列中。

  7. 最后,主线程执行任务队列中的任务,打印 "setTimeout"。

综上所述,JavaScript 的执行机制遵循以下步骤:

  1. 执行同步代码,将函数调用和变量分配到调用栈中按顺序执行。

  2. 遇到异步操作,如定时器、事件监听等,将其注册到任务队列中,并继续执行后续的同步代码。

  3. 同步代码执行完毕后,主线程会检查微任务队列,依次执行队列中的微任务(Promise 回调函数)。

  4. 执行完微任务后,主线程会从任务队列中取出任务执行,执行完一个任务后再检查微任务队列,如此循环,直至任务队列为空。

需要注意的是,微任务优先级高于任务队列中的任务,所以在执行任务队列中的任务之前,会先执行完所有的微任务。

现学现用,再看一个例子:

    async function async1() {
   
   
      console.log("async1 start");
      await async2();
      console.log("async1 end");
    }
    async function async2() {
   
   
        console.log("async2");
    }
    console.log("js start");
    setTimeout(function () {
   
   
      console.log("timeout");
    }, 0);
    async1();
    new Promise(function (resolve) {
   
   
        console.log("promise");
        resolve();
    }).then(function () {
   
   
        console.log("then");
    });
    console.log("js end");

这段代码的打印顺序如下:

  1. "js start":立即打印,表示 JavaScript 代码的开始执行。
  2. "async1 start":由于 async1 函数被调用,所以会打印 "async1 start"。
  3. "async2":async1 函数中调用了 async2 函数,因此会打印 "async2"。
  4. "promise":new Promise 的回调函数立即执行,所以会打印 "promise"。
  5. "js end":立即打印,表示 JavaScript 代码的执行结束。
  6. "async1 end":由于 async2 函数是一个异步函数,await async2() 表达式会等待 async2 函数执行完毕,然后继续执行下面的代码,所以会打印 "async1 end"。
  7. "then":Promisethen 方法是异步执行的,所以会在下一个事件循环中执行,因此会打印 "then"。
  8. "timeout":由于 setTimeout 的延迟时间为 0,所以会在下一个事件循环中执行,因此会打印 "timeout"。
    代码的执行顺序是按照同步代码的顺序执行,异步代码则根据事件循环的机制来执行。async/await 会暂停同步代码的执行,并等待异步操作完成后再继续执行后续的代码。

总结

JS 代码的执行顺序主要为:

  1. 同步代码
    同步代码(sync code)直接进入执行栈执行。执行顺序按代码书写顺序。
  2. 异步任务回调
    异步任务(如 setTimeout)进入任务队列。
  3. 事件循环
    事件循环周期性地从任务队列取出任务,推入执行栈执行。当执行栈为空时,才会取出队列中的任务。
  4. 执行栈先进后出
    执行栈采用先进后出的方式执行函数。在函数执行完毕后才会执行上层函数。
    这保证了函数的正确嵌套调用。
  5. 微任务优先级高于宏任务
  • 宏任务(macrotask):出于任务队列的任务。比如 setTimeout、setInterval。
  • 微任务(microtask):比如 Promise .then、MutationObserver 。
    微任务的优先级高于宏任务。
    所以整个执行顺序可以描述为:
  1. 同步代码按顺序进入执行栈执行
  2. 异步宏任务进入任务队列
  3. 当执行栈清空时,执行微任务
  4. 接着执行宏任务
  5. 循环往复
目录
相关文章
|
JavaScript 前端开发
js单线程、同步、异步
什么是单线程?同步、异步的产生?
119 0
|
存储 JavaScript 前端开发
人人都能看懂的JavaScript单线程的那点事
人人都能看懂的JavaScript单线程的那点事
176 0
|
存储 JavaScript 前端开发
单线程的 【JavaScript】 是如何管理任务的
单线程的 【JavaScript】 是如何管理任务的
83 0
单线程的 【JavaScript】 是如何管理任务的
|
前端开发 JavaScript API
🍉如何理解单线程的JavaScript及其工作原理|8月更文挑战
🍉如何理解单线程的JavaScript及其工作原理|8月更文挑战
200 7
🍉如何理解单线程的JavaScript及其工作原理|8月更文挑战
|
消息中间件 JavaScript 前端开发
深入理解Javascript单线程谈Event Loop
深入理解Javascript单线程谈Event Loop
181 5
|
消息中间件 Web App开发 存储
浅谈浏览器架构、单线程js、事件循环、消息队列、宏任务和微任务
关键词:多进程、单线程、事件循环、消息队列、宏任务、微任务
浅谈浏览器架构、单线程js、事件循环、消息队列、宏任务和微任务
|
消息中间件 Web App开发 移动开发
JS是单线程,你了解其运行机制吗?
JS是单线程,你了解其运行机制吗?
184 0
JS是单线程,你了解其运行机制吗?
|
Web App开发 JavaScript 前端开发
Javascript定时器(一)——单线程
可以从下面的代码中看到,第一个用setTimeout中的代码是死循环,由于是单线程,下面的两个定时器就没机会执行了。
Javascript定时器(一)——单线程
|
JavaScript 前端开发 程序员
好程序员web前端培训分享如何理解JS的单线程
好程序员web前端培训分享如何理解JS单线程,JS本质是单线程的。也就是说,它并不能像JAVA语言那样,两个线程并发执行。 但我们平时看到的JS,分明是可以同时运作很多任务的,这又是怎么回事呢? 首先,JS的代码,大致分为两类,同步代码和异步代码。
886 0
|
Web App开发 并行计算 JavaScript
诡异的JS异步单线程是如何工作的
对于通常的developer(特别是那些具备并行计算/多线程背景知识的developer)来讲,js的异步处理着实称得上诡异。而这个诡异从结果上讲,是由js的“单线程”这个特性所导致的。 我曾尝试用“先定义后展开”的教科书方式去讲解这一块的内容,但发现极其痛苦。
1531 0