单线程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. 循环往复
目录
相关文章
|
2月前
|
前端开发 JavaScript UED
探索JavaScript的异步编程模式
【10月更文挑战第40天】在JavaScript的世界里,异步编程是一道不可或缺的风景线。它允许我们在等待慢速操作(如网络请求)完成时继续执行其他任务,极大地提高了程序的性能和用户体验。本文将深入浅出地探讨Promise、async/await等异步编程技术,通过生动的比喻和实际代码示例,带你领略JavaScript异步编程的魅力所在。
40 1
|
2月前
|
JavaScript 前端开发
利用事件循环提高 JavaScript 程序的性能
本文介绍了事件循环在JavaScript中的工作原理,以及如何通过合理利用事件循环来优化程序性能,包括异步操作、任务优先级和避免阻塞等技巧。
|
3月前
|
前端开发 JavaScript UED
探索JavaScript中的异步编程模式
【10月更文挑战第21天】在数字时代的浪潮中,JavaScript作为一门动态的、解释型的编程语言,以其卓越的灵活性和强大的功能在Web开发领域扮演着举足轻重的角色。本篇文章旨在深入探讨JavaScript中的异步编程模式,揭示其背后的原理和实践方法。通过分析回调函数、Promise对象以及async/await语法糖等关键技术点,我们将一同揭开JavaScript异步编程的神秘面纱,领略其带来的非阻塞I/O操作的魅力。让我们跟随代码的步伐,开启一场关于时间、性能与用户体验的奇妙之旅。
|
3月前
|
消息中间件 前端开发 JavaScript
探索JavaScript中的事件循环机制:异步编程的核心
【10月更文挑战第12天】探索JavaScript中的事件循环机制:异步编程的核心
51 1
|
6月前
|
消息中间件 前端开发 JavaScript
|
8月前
|
前端开发 JavaScript API
JavaScript中的异步编程技术及应用
【2月更文挑战第2天】传统的JavaScript编程方式在处理异步操作时存在诸多不足,为了解决这一问题,近年来涌现出了一系列异步编程技术,本文将深入探讨Promise、async/await等异步编程解决方案,并结合实际案例展示其在前端开发中的应用。
|
8月前
|
消息中间件 前端开发 JavaScript
JavaScript 线程:处理高并发任务的必备知识(下)
JavaScript 线程:处理高并发任务的必备知识(下)
JavaScript 线程:处理高并发任务的必备知识(下)
|
8月前
|
前端开发 JavaScript UED
JavaScript 线程:处理高并发任务的必备知识(上)
JavaScript 线程:处理高并发任务的必备知识(上)
JavaScript 线程:处理高并发任务的必备知识(上)
|
前端开发 JavaScript UED
JavaScript异步编程:提升性能与用户体验
JavaScript异步编程:提升性能与用户体验
91 1
|
8月前
|
前端开发 JavaScript
JavaScript基础知识:JavaScript 中的异步编程有哪些模式?
JavaScript基础知识:JavaScript 中的异步编程有哪些模式?
81 0