JavaScript事件循环同步任务与异步任务

目录
  • 前言
  • 执行栈与任务队列
    • 执行栈
    • 任务队列
  • 同步任务与异步任务
    • 同步任务
    • 异步任务
  • js的执行机制
  • 结语

前言

首先,在学习js中同步异步的问题前,需要明白,js是单线程的,为什么它得是单线程的呢?这得从它的使用场景来看了,它主要是用来让用户与页面进行交互的吧。那么假设js是多线程的,在这个线程里面,用户点击某个按钮会增加一个DOM节点,在另一个线程里面,用户点击这个按钮又会删除一个DOM节点,那么此时js就不知道该听谁的了。那同步异步的出现又是为了什么呢?假设没有异步,那么我们在向服务器请求数据时,可能会因为网络不好,卡了半天,这时候因为是同步的,所以网页必须等待数据请求回来才能继续和用户交互,这样会导致整个网页很奇怪的卡住了,用户体验很不好。

执行栈与任务队列

执行栈

  • 姑且先不说执行栈是什么,先说栈是什么吧。栈就好似一个桶,最先放入的东西肯定是最后拿出来的,就是大家常说的先进后出。

 那么执行栈就是把图中的内容块变成代码任务,光说肯定说不明白,还是得上代码:

function fn (count) {
            if (count <= 0) return
            fn(count - 1)
            console.log(count)
        }
fn(3)

这是一段很简单的递归代码,这里我们直接上图解释(这里其实画的不严谨,栈底应该是全局执行上下文):

js中所有的任务都会在主线程上执行然后形成一个执行栈(请记住这一点!!!)

任务队列

那么队列和栈则是相反的,队列是先进先出的。其实很好理解,和我们平时排队是一个道理,先进入队伍的人肯定先出来。那么任务队列通俗理解就是用来放置异步任务的回调函数的(也请记住这一点!!!)

同步任务与异步任务

先上一点概念性的东西,打个基础:

同步任务

很多人在理解同步任务的时候会被它的语义搞混,其实同步任务不是同步一起执行的。它是要等待上一个执行任务结束才可以执行下一个任务,这里说起来也并不晦涩难懂,但是还是写段简单的代码解释一下:

console.log(1)
console.log(2)
console.log(3)

代码很简单吧,很明显输出结果是1,2,3,这就是同步代码,那么我们就可以总结了,同步任务就是在主线程上面排队,然后一个一个进入执行栈执行,直到执行栈为空。

异步任务

还是直接举个栗子:

console.log(1)
setTimeout(() => {
    console.log(2)
}, 1000)
console.log(3)

这段代码的输出和上面同步代码的输出不一样,它的输出顺序是1,3,2,这就是异步代码,它并不会按照执行顺序去执行,

同样我们用官方话语总结一下:异步任务指的是,不进入主线程、而进入"任务队列"(Event queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行 如果不理解没有关系,后面说到了事件循环就会醍醐灌顶了。

js的执行机制

先上比较晦涩难懂的概念:

  • 1. 同步任务由JavaScript 主线程按顺序执行。
  • 2. 异步任务委托给宿主环境执行。
  • 3. 异步任务完成后,对应的回调函数会被加入到任务队列中等待执行,任务队列又被分为宏任务队列和微任务队列,优先执行微任务队列,常见的微任务有new Promise().then,常见的宏任务有定时器
  • 4. JavaScript 主线程的执行栈被清空后,会读取任务队列中的回调函数,次序执行。
  • 5. JavaScript 主线程不断重复上面的第4 步,在执行回调函数时又会按照上面的四步去执行。

js一直从任务队列中取回调函数,然后放入主线程中执行,这是一个循环不断的过程,所以把它叫做事件循环。

这个还是要简单粗暴的来段代码会更直观一点:

const promise = new Promise((resolve, reject) => {
      console.log(1);
      setTimeout(() => {
          console.log("timerStart");
          resolve("success");
          console.log("timerEnd");
       }, 0);
      console.log(2);
  });
  promise.then((res) => {
      console.log(res);
  });
  console.log(4);

现在我们根据上面的规则一步一步分析这段代码,如果不懂Promise也没有关系,我保证这并不影响你对事件循环的理解。现在你就把自己当成js代码的检察官,要正确把它们放在合适的“位置”

  • 检察官的第一步就是判断哪些是同步代码,哪些是异步代码,OK,首先从上往下看,Promise本身是同步的,所以它应该在主线程上排队,然后继续看pomise.then是个异步任务,并且是属于微任务的,它的回调函数应该在微任务队列中(此时还不在),最后一句输出语句是同步代码,应该在主线程上排队。
  • 第二步,执行主线程上的同步代码,首先有Promise排着队呢,所以先输出1,随后有个定时器,所以应该把它挂起执行,由于它没有时间延迟,所以回调函数直接被放入宏任务队列,继续执行代码,遇到打印,直接输出2。现在主线程还有其他的同步代码不?是不是还有一个输出语句,所以输出4,现在主线程上的同步代码执行完了
  • 第三步读取任务队列,由于微任务队列上没有东西(Promise的状态并没有改变,不会执行promise.then()),所以读取宏任务队列上的回调函数,回调函数进入主线程执行,首先输出timerStart,然后promise状态发生改变,然后又遇到一个输出语句,输出timerEnd。现在主线程上又没有东西了,又得去看任务队列上有没有东西了。
  • 第四步,由于promise状态发生改变了,所以微任务队列上有回调函数了,执行输出语句,res为success,输出success

结语

到此这篇关于JavaScript事件循环同步任务与异步任务的文章就介绍到这了,更多相关JS事件循环 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一文详解JS中的事件循环机制

    目录 前言 1.JavaScript是单线程的 2.同步和异步 3.事件循环 前言 我们知道JavaScript 是单线程的编程语言,只能同一时间内做一件事,按顺序来处理事件,但是在遇到异步事件的时候,js线程并没有阻塞,还会继续执行,这又是为什么呢?本文来总结一下js 的事件循环机制. 1.JavaScript是单线程的 JavaScript 是一种单线程的编程语言,只有一个调用栈,决定了它在同一时间只能做一件事.在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行.在

  • 如何优雅地取消 JavaScript 异步任务

    在程序中处理异步任务通常比较麻烦,尤其是那些不支持取消异步任务的编程语言.所幸的是,JavaScript 提供了一种非常方便的机制来取消异步任务. 中断信号 自从 ES2015 引入了  Promise ,开发者有了取消异步任务的需求,随后推出的一些 Web API 也开始支持异步方案,比如 Fetch API.TC39 委员会(就是制定 ECMAScript 标准的组织)最初尝试定义一套通用的解决方案,以便后续作为 ECMAScript 标准.但是后来讨论不出什么结果来,这个问题也就搁置了.鉴

  • Node.js 如何利用异步提升任务处理速度

    今天在做一个小任务,需要调用阿里云的图像识别接口,对 62662 张照片进行场景识别,并将结果写到本地的 csv 文件中. 因为任务很简单,没想很多就开始码.自从有了 async/await 之后,已经很久不写 callback 了,所以上手就写成这样: 本文所有代码均有简化,只保留关键过程 async fetchSceneTags(imagePath) { try { const result = await callAliyunAPI(imagePath); return result.er

  • 浅谈关于JS下大批量异步任务按顺序执行解决方案一点思考

    前言 最近需要做一个浏览器的, 支持大体积文件上传且要支持断点续传的上传组件, 本来以为很容易的事情, 结果碰到了一个有意思的问题: 循环执行连续的异步任务, 且后一个任务需要等待前一个任务的执行状态 这么说可能有点空泛, 以我做的组件举例: 这个组件本意是为了上传大体积视频, 和支持断点续传, 因为动辄几个G的视频不可能直接把文件读进内存, 只能分片发送(考虑到实际网络状态, 每次发送大小定在了4MB), 而且这么做也符合断点续传的思路. 组件工作流程如下: 选定上传文件后, 从H5原生upl

  • 一篇文章让你搞清楚JavaScript事件循环

    目录 前言 宏任务 微任务 事件循环 宏任务与微任务 总结 参考资料 前言 异步函数也是有执行顺序的.本质上来说,JavaScript是单线程语言,不管是在浏览器中还是nodejs环境下.浏览器在执行js代码和渲染DOM节点都是在同一个线程中,执行js代码就无法渲染DOM,渲染DOM的时候就无法执行js代码.如果按照这种同步方式执行,页面的渲染将会出现白屏甚至是报错,特别是遇到一些耗时比较长的网络请求或者js代码,因此在实际开发中一般是通过异步的方式解决. 什么是异步?js是一步一步执行代码的,

  • Javascript单线程和事件循环

    目录 一.单线程 二.事件循环 三.事件循环的应用 四.使用代码来说明 五.setTimeout() 六.思考:劣质的优化 一.单线程 Javascript 是单线程的,意味着不会有其他线程来竞争.为什么是单线程呢? 假设 Javascript 是多线程的,有两个线程,分别对同一个元素进行操作: function changeValue() { const e = document.getElementById("ele1"); if (e) { e.value = "VAL

  • 详解JS事件循环及宏任务微任务的原理

    目录 宏任务 微任务 事件循环 宏任务与微任务 微任务中创建宏任务 宏任务中创建微任务 宏任务中创建宏任务 微任务中创建微任务 总结 本质上来说,JavaScript是同步的.阻塞的.单线程语言,不管是在浏览器中还是nodejs环境下.浏览器在执行js代码和渲染DOM节点都是在同一个线程中,执行js代码就无法渲染DOM,渲染DOM的时候就无法执行js代码.如果按照这种同步方式执行,页面的渲染将会出现白屏甚至是报错,特别是遇到一些耗时比较长的网络请求或者js代码,因此在实际开发中一般是通过异步的方

  • 如何在现代JavaScript中编写异步任务

    前言 在本文中,我们将探讨过去异步执行的 JavaScript 的演变,以及它是怎样改变我们编写代码的方式的.我们将从最早的 Web 开发开始,一直到现代异步模式. 作为编程语言, JavaScript 有两个主要特征,这两个特征对于理解我们的代码如何工作非常重要.首先是它的同步特性,这意味着代码将逐行运行,其次是单线程,任何时候都仅执行一个命令. 随着语言的发展,允许异步执行的新工件出现在场景中.开发人员在解决更复杂的算法和数据流时尝试了不同的方法,从而导致新的接口和模式出现. 同步执行和观察

  • js使用generator函数同步执行ajax任务

    本文实例为大家分享了js使用generator函数同步执行ajax任务的具体代码,供大家参考,具体内容如下 function request(url, callback) { fetch(url, {mode: 'cors', credentials: 'include', headers: new Headers({ 'X-Requested-With': 'XMLHttpRequest' })}) .then(response => response.text()) .then(text =

  • JavaScript事件循环同步任务与异步任务

    目录 前言 执行栈与任务队列 执行栈 任务队列 同步任务与异步任务 同步任务 异步任务 js的执行机制 结语 前言 首先,在学习js中同步异步的问题前,需要明白,js是单线程的,为什么它得是单线程的呢?这得从它的使用场景来看了,它主要是用来让用户与页面进行交互的吧.那么假设js是多线程的,在这个线程里面,用户点击某个按钮会增加一个DOM节点,在另一个线程里面,用户点击这个按钮又会删除一个DOM节点,那么此时js就不知道该听谁的了.那同步异步的出现又是为了什么呢?假设没有异步,那么我们在向服务器请

  • javascript事件循环event loop的简单模型解释与应用分析

    本文实例讲述了javascript事件循环event loop的简单模型解释与应用.分享给大家供大家参考,具体如下: js是单线程的,但是event loop的出现,使得js拥有可以处理高并发的性能.那么怎么理解event loop呢?网上百度一堆文章,什么heap,stack,micro queue,macro queue,让初学者直接懵掉.这里采用很通俗的理解方式介绍下event loop. event loop顾名思义是事件循环,既然是循环,那循环的是什么呢? 对于一个js文件, 1,执行

  • 深入分析JavaScript 事件循环(Event Loop)

    事件循环(Event Loop),是每个JS开发者都会接触到的概念,但是刚接触时可能会存在各种疑惑. 众所周知,JS是单线程的,即同一时间只能运行一个任务.一般情况下这不会引发问题,但是如果我们有一个耗时较多的任务,我们必须等该任务执行完毕才能进入下一个任务,然而等待的这段时间常常让我们无法忍受,因为我们这段时间什么都不能做,包括页面也是锁死状态. 好在,时代在进步,浏览器向我们提供了JS引擎不具备的特性:Web API.Web API包括DOM API.定时器.HTTP请求等特性,可以帮助我们

  • JavaScript事件循环剖析宏任务与微任务

    目录 前言 引言 为什么会有事件循环? JS是单线程的 同步任务和异步任务 JS事件循环 宏任务与微任务 常见的宏任务有哪些? 常见的微任务有哪些? 执行过程总结(重点) 同步任务 —> 微任务 —> 宏任务... 案例挑战 案例1: 案例2: 案例3: 前言 相信对于刚学习JavaScript的新手来说,去理解JS中的事件循环原理以及异步执行过程比较困难,但是这是JS必须要会的基础知识,逃避不能解决问题,笔者曾经也被这个知识点困扰过,现根据以往的经验编写此文章,旨在帮助大家彻底搞懂它们以及自

  • 在实例中重学JavaScript事件循环

    单线程的JS 众所周知js是一门单线程语言,即同一时间只能做一件事.为什么js是单线程的呢,主要与它的用途有关. 作为浏览器脚本语言,js的主要用途是和用户互动&操作DOM,我们并不想并行的操作DOM.如果不是单线程的话,我们一个线程在给DOM节点上添加内容,另一个线程却删除了这个节点,到底该以哪个为准呢? 所以为了避免复杂性,从一诞生,JavaScript 就是单线程. 事件循环(event loop) JS是一门单线程语言,意味着代码要一行一行的执行.所有任务都要排队,前一个任务结束,才会执

  • 详解JavaScript事件循环机制

    众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心.可看HTML规范中的这段话: To coordinate events, user interaction, scripts, rendering, networking, and so forth, user agents must use event loops as described in this section. There a

  • JavaScript事件循环及宏任务微任务原理解析

    首先看一段代码: 打印顺序是什么? 正确答案:script start, script end, promise1, promise2, setTimeout 其中涉及到事件循环(event loop),宏任务(macrotask),微任务(microtask) 一.事件循环 Event Loop 程序中设置两个线程:一个负责程序本身的运行,称为"主线程":另一个负责主线程与其他进程(主要是各种I/O操作)的通信,被称为"Event Loop线程"(可以译为&quo

  • JavaScript 关于事件循环机制的刨析

    目录 前言: 一.事件循环和任务队列产生的原因: 二.事件循环机制: 三.任务队列: 3.1 任务队列的类型: 3.2 两者区别: 3.3 更细致的事件循环过程 四.强大的异步专家 process.nextTick() 4.1 process.nextTick()在何时调用? 前言: 这次主要整理一下自己对 Js事件循环机制,同步,异步任务,宏任务,微任务的理解,大概率暂时还有些偏差或者错误.如果有,十分欢迎各位纠正我的错误! 一.事件循环和任务队列产生的原因: 首先,JS是单线程,这样设计也是

  • 简单聊聊JavaScript的事件循环机制

    目录 前言 概念 举个栗子 TIP 再次举个栗子 总结 前言 JavaScript是一门单线程的弱类型语言,但是我们在开发中,经常会遇到一些需要异步或者等待的处理操作. 类似ajax,亦或者ES6中新增的promise操作用于处理一些回调函数等. 概念 在JavaScript代码执行过程中,可以分为同步队列和异步队列. 同步任务类似我们常说的立即执行函数,不需要等待可以直接进行,可以直接进入到主线程中去执行,类似正常的函数调用等. 异步队列则是异步执行函数,类似ajax请求,我们在发起的过程中,

随机推荐