首页 > 编程语言 >单线程JavaScript为何如此高效

单线程JavaScript为何如此高效

时间:2023-07-05 13:57:29浏览次数:56  
标签:异步 高效 单线程 代码 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,队列,任务,执行
From: https://www.cnblogs.com/chaojilaji/p/17528298.html

相关文章

  • JavaScript发展历史(JS)
    JavaScript发展历史1994年,网景公司(Netscape)发布了Navigator浏览器0.9版,这是世界上第一款比较成熟的网络浏览器,轰动一时。但是这是一款名副其实的浏览器--只能浏览页面,浏览器无法与用户互动,当时解决这个问题有两个办法,一个是采用现有的语言,许他们直接嵌入网页。另一个是发明一......
  • 常用的前端JavaScript方法封装
     1、输入一个值,返回其数据类型**functiontype(para){returnObject.prototype.toString.call(para)} 2、数组去重functionunique1(arr){return[...newSet(arr)]}functionunique2(arr){varobj={};returnarr.filter(ele=>{if......
  • 【10.0】前端基础之JavaScript进阶
    【10.0】前端基础之JavaScript进阶【一】自定义对象可以看成Python中的字典,但是在JS中的自定义对象要比Python里面的字典操作起来更方便【1】创建自定义对象方式一vard={"键":"值",};操作方法vardict={"name":"dream","age":18};vardict={"name":"dream&......
  • JavaScript 数组的 reduce 方法有哪些应用
    JavaScript数组的reduce方法有哪些应用JavaScript中的reduce()方法可以用于将数组元素汇总为单个值,它接受一个回调函数作为参数,并在每个数组元素上调用该函数,以便将其累加到一个累加器变量中。下面是一些实际应用:数组求和:使用reduce()方法将数组元素相加,从而计算数组的总......
  • 【8.0】前端基础之JavaScript引入
    【8.0】前端基础之JavaScript引入【一】什么是JavaScriptjs也是一门编程语言,他可以写后端代码JavaScript想一统天下,前后端都写于是node.js支持JS代码跑在后端服务器上但是并不能完美的实现JavaScript和Java一毛钱关系都没有,纯粹是为了蹭Java的热度【二】JavaScrip......
  • 【9.0】前端基础之JavaScript初识
    【9.0】前端基础之JavaScript初识js也是一门面向对象的编程语言,一切皆对象【一】变量命名规范变量名只能是数字/字母/下划线/$变量名命名规范(js中推荐驼峰式命名法)变量民不能用关键字作为变量名【二】JS代码的书写位置可以单独开设JS文件书写还可以直接在浏览......
  • 汽车虚拟仿真如何让汽车自动驾驶测试更高效?
    自动驾驶汽车一直是驾驶者和汽车工程师的梦想,从汽车诞生以来,不少专家就在预言自动驾驶的真正落地实现的那一天,他们普遍认为制约自动驾驶汽车发展的主要因素是低成本和强大的计算能力,但这两个问题目前在很大程度上其实已经得到解决,但现在完全的自动驾驶仍然难以实现。因为自动驾驶......
  • javascript现代编程系列教程之X——javascript人工智能
    JavaScript在人工智能(AI)领域的应用主要体现在以下几个方面:浏览器端的机器学习:TensorFlow.js是一个在浏览器中运行的JavaScript机器学习库,它允许开发者训练和部署机器学习模型。这使得开发者可以在浏览器端进行实时的机器学习任务,无需将数据传输到服务器端,从而提高了用户的隐......
  • 【四】JavaScript之类型转换
    【四】JavaScript之类型转换【1】类型转换javascript是弱类型的编程语言所以本身不仅提供了数据类型的转换甚至在数据使用运算符的时候,javascript的解释器也会出现默认隐式转换数据类型的情况。【2】字符串字符串转换成布尔值除了空字符串("")被转为false,其他的任......
  • 【三】JavaScript之数据类型
    【三】JavaScript之数据类型【0】数据类型展示javascript中变量的值有不同的作用或者功能。按不同的功能,值也可以区分不同的类型。类型名称描述Number数值型整数,浮点数。。。。String字符串文本,一般使用"双引号",'单引号'或者反引号圈起来的都是文本。Bo......