精华内容
下载资源
问答
  • js事件循环机制(Event Loop)
    2022-02-11 09:50:06

    javascript从诞生之日起就是一门  单线程的  非阻塞的  脚本语言,单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来处理所有的任务,非阻塞靠的就是 event loop(事件循环),本文就讲解下事件循环。

    event loop它最主要是分三部分:主线程、宏队列(macrotask)、微队列(microtask)

    js的任务队列分为同步任务和异步任务,所有的同步任务都是在主线程里执行的,异步任务可能会在macrotask或者microtask里面

    主线程

    就是访问到的script标签里面包含的内容,或者是直接访问某一个js文件的时候,里面的可以在当前作用域直接执行的所有内容(执行的方法,new出来的对象等

    宏队列(macrotask)

    setTimeout、setInterval、setImmediate、I/O、UI rendering

    微队列(microtask)

    promise.then、process.nextTick

    执行顺序

    1、先执行主线程

    2、遇到宏队列(macrotask)放到宏队列(macrotask)

    3、遇到微队列(microtask)放到微队列(microtask)

    4、主线程执行完毕

    5、执行微队列(microtask),微队列(microtask)执行完毕

    6、执行一次宏队列(macrotask)中的一个任务,执行完毕

    7、执行微队列(microtask),执行完毕

    8、依次循环。。。

     看下面代码练习练习

    console.log(1)
    process.nextTick(() => {
      console.log(8)
      setTimeout(() => {
        console.log(9)
      })
    })
    setTimeout(() => {
      console.log(2)
      new Promise(() => {
        console.log(11)
      })
    })
    requestIdleCallback(() => {
      console.log(7)
    })
    // 特殊说明: new Promise()属于主线程任务
    let promise = new Promise((resolve,reject) => {
      setTimeout(() => {
        console.log(10)
      })
      resolve()
      // 这个console也属于主线程任务
      console.log(4)
    })
    fn()
    console.log(3)
    promise.then(() => {
      console.log(12)
    })
    function fn(){
      console.log(6)
    }

    结果是1、4、6、3、12、8、2、11、10、9、7

    这个写法可以囊括80%以上的event loop循环机制的场景了,下面开始梳理具体的运行机制。

    js是从上到下执行的,所以上来先打印的是 1 ,继续往下走;

    遇见了process.nextTick,因为它属于微队列(microtask),并且当前主线程的代码还没有执行完毕,所以它被展示扔到了微队列里,暂时不打印;

    这个时候又遇到了setTimeout,setTimeout是属于宏队列(macrotask);

    requestIdleCallback,这里也是不立即执行的,它也不属于任何队列,这里不做详细解释;

    promise在实例化的时候,这里的setTimeout继续被丢到了宏队列(macrotask)中,并执行了成功的方法,在有promise.then的调用的时候就会去出发,但这里不做打印,接着发现了console,这里直接打印 4 );

    fn函数直接调用,直接打印 6 ;

    console,直接打印 3 ;

    promise.then因为它属于微队列,但是它在promise实例化的时候被调用了,所以它会在微队列的最前面执行;

    到这里主线程里面就没有任何可以执行到东西了,下面开始走微队列(microtask):

    由于promise.then被提前调用了,所以它会先执行,打印 12 ;

    微队列(microtask)里面还有一个,就是上面的process.nextTick,执行它,打印 8 ,这个时候发现它有一个setTimeout,放到宏队列(macrotask);

    到这里微队列就走完了,下面开始走宏队列(macrotask):

    最外面的setTimeout在一开始的时候被放了进去,所以先执行它,打印 2 ,发现它里面有promise被实例化,直接执行,打印 11 ;

    下一个要走的就是promise里面的setTimeout,打印 10 ;

    还剩最后一个setTimeout,就是process.nextTick里面的,打印 9 ;

    到这里主线程、宏队列(macrotask)、微队列(microtask)就全都跑完了,在全部跑完的时候,requestIdleCallback才会执行,打印 7 ;

    requesIdleCallback会在当前浏览器空闲时期去依次执行,在整个过程当中你可能添加了多个requestIdleCallback,但是都不会执行,只会在空闲时期,去依次根据调用的顺序就执行。

    更多相关内容
  • JavaScript事件循环

    千次阅读 2022-03-13 17:33:37
    1.浏览器内核有多种线程在工作: GUI渲染线程: ...和js引擎线程是互斥的,当JS引擎在工作时,GUI线程会被挂起,GUI更新被放在JS任务队列中,等待JS引擎线程空闲继续执行 ...2.javaScript事件循环机制 分为

    1.浏览器内核有多种线程在工作:

    1. GUI渲染线程:
      负责渲染页面,解析html,css构成DOM树等
      和js引擎线程是互斥的,当JS引擎在工作时,GUI线程会被挂起,GUI更新被放在JS任务队列中,等待JS引擎线程空闲继续执行
    2. js引擎线程:
      单线程工作,负责解析JavaScrip脚本
      和GUI线程互斥,JS运行时间过长会导致页面阻塞。
      js引擎是单线程。每次只能执行一个任务,其他任务需要按照顺序排队等待被执行,只有当前任务执行完成之后才会往下执行下一个任务。

    2.javaScript事件循环机制

    分为两种:1.浏览器事件循环 2.Node事件循环

    1. 浏览器Event Loop是HTML中定义的规范;Node Event Loop是由libuv库实现的。
      浏览器部分:

    2. JavaScript有一个main thread 主线程和call-stack调用栈(执行栈),所有的任务都会被放到调用栈等主线程执行。

    3. JS调用栈:
      JS调用栈是后进先出的数据结构。当函数被调用时,会把函数加入到栈顶,执行完成之后就从栈顶溢出该函数,直到栈内被清空。

    4. 同步任务、异步任务
      JavaScript单线程中的任务分为同步和异步。

      1. 同步任务会在调用栈中按照顺序等待主线程执行。
      2. 异步任务则会在异步有了结果后将注册的回调函数添加到任务队列等待主线程空闲的时候,也就是栈内被清空的时候,被读取到栈中等待主线程执行。任务队列是先进先出的数据结构。

    Event Loopl 事件循环:

    调用栈中的同步任务都执行完毕,栈内被清空了,就代表主线程空闲了,就会去任务队列中按照顺序读取一个任务放入栈中。每次栈被清空,都会区读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,形成了事件循环。

    3.定时器setTimeout

    定时器会开启一个定时器触发线程来触发计时,定时器会在等待了指定时间后,把事件放入任务队列中等待读取到主线程里执行。

    1. 意义:
      定时器指定的演示毫秒数其实并不准确,因为计时器只是在到了指定的时间时将事件放入到任务队列中,必须要等到同步的任务和现有的任务队列中事件全部执行完成以后,才回去读取定时器的事件到主线程中,中间可能会存在耗时比较久的任务,所以不能保证在指定的时间执行。
    2. setTimeout 0的作用:
      浏览器会在执行完当前任务队列中的任务,再执行setTimeout队列中积累的任务。
      通过设置任务在0毫秒后执行,能够改变任务执行的先后顺序,延迟该任务发生,使之异步执行。

    4.宏任务、微任务

    ES6中microtask称为jobs,macrotask称为task
    宏任务是由宿主发起的,微任务是JS自身发起。
    ES5之后,JS引入了Promise,这样,不需要浏览器,JS殷勤自身也能够发起异步任务了。
    JavaScript单线程中的任务可以细分为宏任务和微任务。

    1. macro-task:
      script(整体代码)、setTimeout、setInterval、setImmedate、I/O、UI rendering
    2. micro-task:
      process.nextTick、Promise的回调、Object.Observe、MutationObserver的回调

    5.进一步说Promise:

    1. Promise构造函数是同步执行的,then方法时异步执行的。
    2. 构建Promise对象的时候,需要传入一个executor函数;
    3. Promise构造函数执行时立即调用executor函数,resolve和reject两个函数作为参数传递给executor,resolve和reject函数被调用时,状态发生变化。
    4. 所以在executor函数中调用resolve函数后,会触发promise.then设置的回调函数,而调用reject函数后,会触发promise.catch设置的回调函数。
    new Promise(resolve=>{
          console.log(1);
          resolve(3);
      }).then(num=>{
          console.log(num);
      });
      console.log(2);
    //输出顺序:1 2 3 
    
    
    let a1=new Promise(()=>{
        setTimeout(()=>{
            console.log(1);
        },1000)
        console.log(2);
    })
    console.log(3);
    //输出顺序:2 3 1
    
    let a=new Promise((resolve,reject)=>{
        console.log(1);
        resolve("张三");
        console.log(2);
    })
    a.then(res=>{
        console.log("成功"+res);
    },reason=>{
        console.log("失败"+reason);
    })
    console.log(3);
    // 1 2 3 成功张三 
    // 先进行一个整段代码宏任务,遇到resolve()、then()放入微任务
    // 输出1 2 3 resolve会触发then(),输出 成功 张三
    

    6.promise和async/await的执行顺序:

    1. async/await
      async/await是一种编写异步代码的新方法,之前的异步方案是回调和promise。
      async/await是建立在promise基础上的。
      async/await像promise一样,也是非阻塞的。
      async/await让异步代码看起来、表现起来更显同步代码。

    很多人以为await是等右边的表达式 执行完之后才会继续执行后面的代码,实际上await是一个让出线程的标志。

    1. await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面的js栈的代码。
    2. 等本轮事件循环执行完毕之后又会跳回async函数等待await后面表达式的返回值,如果返回值为非promise则继续执行async函数后面的代码,否则将promise放入promise队列。
      顺序解析:
    function testSometing() {
        console.log("执行testSometing");
        return "testSometing";
    }
    
    async function testAsync() {
        console.log("执行testAsync");
        return Promise.resolve("hello async");
    }
    
    async function test() {
        console.log("test start...");
        const v1 = await testSometing();//关键点1
        console.log(v1);
        const v2 = await testAsync();
        console.log(v2);
        console.log(v1, v2);
    }
    
    test();
    
    var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//关键点2
    promise.then((val)=> console.log(val));
    
    console.log("test end...")
    
    test start 
    执行testSometing
    promise start...
    test end...
    testSometing
    执行testAsync
    promise
    hello async
    testSomething hello async
    

    分析:

    1. 执行到const v1 = await testSomting();的时候,会先将await后面的函数执行一遍,打印出“执行testSometing”的字符串,之后跳出整个async函数执行后面的;
    2. promise表达式是同步的,继续执行就可以,打印出“promise start …”;
    3. 遇到promise.then()方法,是异步的,加入到promise队列;
    4. 继续执行输出“test end…”;至此第一次事件循环结束。
    5. 跳回async函数中,const v1 = await testSomting();函数右边的返回值是非promise的,可以继续执行async函数中的代码,输出“testSomething”;
    6. 遇到const v2 = await testAsync();的时候,会先将await后面的函数执行一遍,输出“执行testAsync”,跳出函数,向下执行。
    7. 事件循环到了promise队列,执行then语句,输出promise;
    8. 回到test函数,继续执行。

    将testSometing()改为异步函数:

    async function testSometing() {
        console.log("执行testSometing");
        return "testSometing";
    }
    
    async function testAsync() {
        console.log("执行testAsync");
        return Promise.resolve("hello async");
    }
    
    async function test() {
        console.log("test start...");
        const v1 = await testSometing();
        console.log(v1);
        const v2 = await testAsync();
        console.log(v2);
        console.log(v1, v2);
    }
    
    test();
    
    var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//3
    promise.then((val)=> console.log(val));
    
    console.log("test end...")
    
    test start...
    执行testSometing
    promise start...
    test end
    promise
    testSometing
    执行testAsync
    hello async
    testSometing hello async
    

    分析:
    promise的then方法比consolelog(v1)先执行:因为testSometing函数加了async,返回的是一个promise对象,需要等它的resolve,所以将当前promise推入队列,之后跳出test函数执行后续代码。

    之后就开始执行promise的任务队列了,因为then()这个promise对象鲜卑推入队列,所以先执行。

    3:

    async function async1(){
        console.log('async1 start')
        await async2()
        console.log('async1 end')
    }
    async function async2(){
        console.log('async2')
    }
    console.log('script start')
    setTimeout(function(){
        console.log('setTimeout') 
    },0)  
    async1();
    new Promise(function(resolve){
        console.log('promise1')
        resolve();
    }).then(function(){
        console.log('promise2')
    })
    console.log('script end')
    
    script start  //代码从上到下执行,先打印,再调用async1()
    async1 start
    async2
    promise1
    script end
    promise2
    async1 end
    setTimeout
    

    分析:

    1. console.log(‘script start’),打印,之后执行async1()
    2. 执行async1(),console.log(‘async1 start’),打印
    3. await async2(),先将await后面的函数执行一遍,console.log(‘async2’),打印之后跳出async1(),向下执行
    4. 执行promise(),console.log(‘promise1’),then()推入promise队列,
    5. console.log(‘script end’),打印,第一次事件循环结束
    6. 跳入async1(),await async2(),async2返回的是一个promise对象,需要等它的resolve,所以将当前promise推入队列,之后跳出async1()执行后续代码。
    7. 执行promise的.then(),console.log(‘promise2’)
    8. 跳入async1(),await async2(),async2返回的是一个promise对象,被它resolve之后,返回的是resolve的值,不再是promise,继续向下执行console.log(‘async1 end’)
    9. 执行定时器事件

    7.执行顺序:

    第一次事件循环(读取任务对列-执行)中,JavaScript引擎会把整个script代码当作一个宏任务执行,执行之后,再检测本次循环中是否存在微任务,存在的话就依次从微任务的队伍队列中读取执行完所有的微任务,再读取宏任务的任务队列中的任务执行,再执行所有的微任务,如此循环。JS的执行顺序就是每次事件循环中的宏任务-微任务。

    分析执行顺序1:
    console.log(1);
    setTimeout(function() {
        console.log(2);
    })
    var promise = new Promise(function(resolve, reject) {
        console.log(3);
        resolve();
    })
    promise.then(function() {
        console.log(4);
    })
    console.log(5);
    

    setTimeout和Promise被称为任务源,来自不同的任务源注册的回调函数会被放入不同的任务队列中。

    1. 第一次事件循环,整段代码作为宏任务进入主线程执行。console.log(1)
    2. 遇到了setTimeout,等过了指定时间,放入宏任务的任务队列,等待同步任务和现有的任务队列中的事件全部执行完,才读取计时器中的事件到主线程。
    3. 遇到了Promise,将then函数放入到微任务的任务队列中。
    4. 整个事件循环以后,检测微任务中的任务队列中是否存在任务,存在就执行。

    第一次的循环结果:1.3.5.4

    1. 接着再到宏任务的任务队列中按顺序取出一个宏任务到栈中让主线程执行,那么在这次循环中的宏任务就是 setTimeout 注册的回调函数,执行完这个回调函数,发现在这次循环中并不存在微任务,就准备进行下一次事件循环。
    2. 检测到宏任务队列中已经没有了要执行的任务,那么就结束事件循环。
      最终的结果就是 1,3,5,4,2。
    展开全文
  • 众所周知,JavaScript 是一门单线程语言,虽然在 html5 中提出了 Web-Worker ,但这并未改变 JavaScript 是单线程这一核心。可看HTML规范中的这段话: To coordinate events, user interaction, scripts, rendering...
  • 理解JS事件循环

    2020-11-22 14:56:01
    在这篇文章中,我将解释一些JavaScript并发模型的核心概念,包括其事件循环和消息队列,希望能够提升你对一种语言的理解,这种语言你可能已经在使用但也许并不完全理解。 这篇文章是写给谁的? 这篇文章是针对在...
  • 尽管JavaScript是单线程的,但通过尽可能将操作放到系统内核执行,事件循环允许Node.js执行非阻塞I/O操作。 由于现代大多数内核都是多线程的,因此它们可以处理在后台执行的多个操作。 当其中一个操作完成时,内核会...
  • js事件循环机制

    2021-06-17 16:54:35
    JavaScript 事件循环机制 所有的任务队列可以分为同步任务和异步任务。同步任务会进入主线程中执行;异步任务回通过任务队列(Event Queue)的机制进行协调执行 同步和异步分别进入不同的执行环境。同步的进入...

    JavaScript 事件循环机制

    所有的任务队列可以分为同步任务和异步任务。同步任务会进入主线程中执行;异步任务回通过任务队列(Event Queue)的机制进行协调执行

    1. 同步和异步分别进入不同的执行环境。同步的进入主线程,即主行栈,异步的进入到 Event Queue。主线程内的执行完毕后,会去Event Queue 读取对应的任务,推入主线程执行。上述过程的不断重复就是 Event Loop(事件循环)。
      在这里插入图片描述
    2. 在事件循环中,每进行一次循环操作称为 tick,其关键步骤可以总结如下

    在这里插入图片描述

    • 在此次 tick 中选择最先进入队列的任务 ( oldest task ),如果有则执行(一次)
    • 检查是否存在 Microtasks,如果存在则不停地执行,直至清空 Microtask Queue
    • 更新 render
    • 主线程重复执行上述步骤
    ① task 分为两大类:分别是 Macro Task(宏任务)和 Micro Task(微任务),并且每个宏任务结束之后,都要清空所有的微任务,Macro Task 也就是常说的 Task
    
    ② Macro Task 主要包括:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、setImmediate(Node环境)
    
    ③ Micro Task 主要包括:Promise、MutaionObserver、process.nextTick(Node环境)
    
    ④ setTimeout / Promise 等API便是任务源,而进入任务队列的是由他们指定的具体执行任务。来自不同任务源的任务会进入不同的任务队列。其中 setTimeout 和 setInterval 是同源的。
    
    1. 代码示例
    console.log('script start');
    
    setTimeout(()=>{
        console.log('timeout')
    }, 0);
    
    Promise.resolve().then(()=>{
        console.log('promise1')
    }).then(()=>{
        console.log('promise2')
    });
    
    console.log('script end');
    

    ① 整体 script 作为第一个宏任务进入主线程,遇到 console.log,输出 script start
    ② 遇到 setTimeout, 其回调函数被分发到宏任务 Event Queue 中
    ③ 遇到 pormise,其 then 函数被分到微任务 Event Queue 中,记为 then1,之后又遇到 then 函数,将其分到微任务 Event Queue中,记为 then2
    ④ 遇到 console.log,输出 script end

    1. 总结

    从规范上来看,Microtask 优先于 task 执行,所以如果有需要优先执行的逻辑,放入 Microtask队列会比 Macro Task 更早的执行

    javascript 是一门单线程语言,异步操作都是放在了事件循环队列里面,等待主线程来执行,并没有专门的异步执行线程

    展开全文
  • 主要介绍了深入理解Node.js 事件循环和回调函数,详细的介绍Node.js 事件循环和Node.js回调函数,需要学习的可以参考一下。
  • 主要介绍了JS事件循环机制event loop宏任务微任务原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • 学习js必不可少的知识点插入

    javascript是单线程执行的程序,也就是它只有一条主线,所有的程序都是逐行“排队”执行,在这种情况下可能存在一些问题,比如说setTimeout、ajax等待执行的时间较长,就会阻塞后续代码的执行,使得整个程序执行的耗时非常久,那么为了应对这样一个问题,javascript代码在执行的时候,是有几个“通道”的。

    首先是调用栈,执行耗时较短的操作,耗时较长的操作先放置到任务队列中,任务队列又分为宏任务(macro-task)和微任务(micro-task),微任务中队列中放置的是 promise.then、aysnc、await 这样操作,宏任务队列中放置的是 setTimeout、ajax、onClick事件,等调用栈的任务执行完成再轮询微任务队列,微任务队列中任务执行完成之后再执行宏任务。

    这里提到了栈和队列,简单说一下这两种数据结构,栈是一种后进先出的结构,只能从尾部进入,从尾部删除,拿生活中的场景来打比方,就好像自助餐的餐盘,最先放的盘子在最底下,最后放的盘子在最上面,需要把最上面的盘子一个个拿走,才能拿到最下面的盘子。

    而队列,是一种先进先出的结构,从尾部进入,从头部删除,就像我们去排队买东西,先去的同学可以先买到。

    再回到事件循环机制(event loop),不阻塞主进程的程序放入调用栈中,压入栈底,执行完了就会弹出,如果是函数,那么执行完函数里所有的内容才会弹出,而阻塞主进程的程序放入任务队列中,他们需要“排队”依次执行。

    上面如此吧啦吧啦吧啦吧啦吧,可以听一耳朵。上案例

    首先来个简单的例子,判断以下程序的执行顺序

    new Promise(resolve => {
      console.log('promise');
      resolve(5);
    }).then(value=>{
      console.log('then回调', value)
    })
     
    function func1() {
      console.log('func1');
    }
     
    setTimeout(() => {
      console.log('setTimeout');
    });
     
    func1();

    创建一个promise的实例就是开启了一个异步任务,传入的回调函数,也叫做excutor 函数,会立刻执行,所以输入promise,使用resolve返回一个成功的执行结果,then函数里的执行会推入到微任务队列中等待调用栈执行完成才依次执行。

    向下执行发现定义了一个func1的函数,函数此时没有被调用,则不会推入调用栈中执行。程序继续往下,发现调用setTimeout函数,将打印的setTimeout推入宏任务队列,再往下执行调用函数func1,将func1推入调用栈中,执行func1函数,此时输出fun1。

    调用栈里所有的内容都执行完成,开始轮询微任务队列,输入then回调5,最后执行宏任务队列,输入setTimeout

    再来看一个复杂的例子

    setTimeout(function () {
      console.log("set1");
      new Promise(function (resolve) {
        resolve();
      }).then(function () {
        new Promise(function (resolve) {
          resolve();
        }).then(function () {
          console.log("then4");
        });
        console.log("then2");
      });
    });
     
    new Promise(function (resolve) {
      console.log("pr1");
      resolve();
    }).then(function () {
      console.log("then1");
    });
     
    setTimeout(function () {
      console.log("set2");
    });
     
    console.log(2);
     
    queueMicrotask(() => {
      console.log("queueMicrotask1")
    });
     
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then3");
    });
    
    
    
    结果
    
    pr1
    2
    then1
    queueMicrotask1
    then3
    set1
    then2
    then4
    set2

    setTimeout执行的回调函数("set1")直接被放置到宏任务队列中等待,Promise的excutor函数立刻执行,首先输入 pr1,Promise.then函数("then1")放入微任务队列中等待,下面的setTimeout执行的回调函数("set2")也被放置到宏任务队列中,排在("set1")后面,接下来调用栈中输出2,queueMicrotask表示开启一个微任务,与Promise.then函数效果一致,("queueMicrotask1")放入微任务队列中,再往下执行,new Promise的excutor函数立刻执行,then函数("then3")放到微任务队列中等待,此时调用栈出已依次输入pr1,2。

    创建一个promise的实例就是开启了一个异步任务,传入的回调函数,也叫做excutor 函数,会立刻执行,所以输入promise,使用resolve返回一个成功的执行结果,then函数里的执行会推入到微任务队列中等待调用栈执行完成才依次执行。

    向下执行发现定义了一个func1的函数,函数此时没有被调用,则不会推入调用栈中执行。程序继续往下,发现调用setTimeout函数,将打印的setTimeout推入宏任务队列,再往下执行调用函数func1,将func1推入调用栈中,执行func1函数,此时输出fun1。

    调用栈里所有的内容都执行完成,开始轮询微任务队列,输入then回调5,最后执行宏任务队列,输入setTimeout

    简单图示如下

    最后一道题,加上了 async、await

    先来一个结论,通过async定义的函数在调用栈中执行,await 将异步程序变成同步,所以await后面执行的程序需要等到await定义的函数执行完成才执行,需要在微任务队列中等待

    async function async1 () {
      console.log('async1 start')
      await async2();
      console.log('async1 end')
    }
     
    async function async2 () {
      console.log('async2')
    }
     
    console.log('script start')
     
    setTimeout(function () {
      console.log('setTimeout')
    }, 0)
     
    async1();
     
    new Promise (function (resolve) {
      console.log('promise1')
      resolve();
    }).then (function () {
      console.log('promise2')
    })
     
    console.log('script end')
    
    
    结果
    script start
    async1 start
    async2
    promise1
    script end
    async1 end
    promise2
    setTimeout

    函数只有调用的时候才会推入调用栈中,所以最先执行的是 console.log,即输出 script start,然后setTimeout函数("setTimeout")放入宏任务队列中等待,调用async1函数,输出 async1 start,执行async2函数,输出async2,("async1 end")放入微任务队列中等待,继续向下执行Promise函数,输出 promise1,then函数中的("promise2")放入微任务队列中等待,输出 script end。

    调用栈的程序都已执行完毕,此时开始执行微任务队列中的程序,依次输出 async1 end、promise2。

    微任务队列中的程序也已执行完成,开始执行宏任务中的程序,输出setTimeout。

    简单图示如下

    题做错了不要紧,记住下面三句话,做题不再出错

    判断执行顺序可以记住以下几个重点

    1、promise中的回调函数立刻执行,then中的回调函数会推入微任务队列中,等待调用栈所有任务执行完才执行

    2、async函数里的内容是放入调用栈执行的,await的下一行内容是放入微任务执行的

    3、调用栈执行完成后,会不断的轮询微任务队列,即使先将宏任务推入队列,也会先执行微任务

    展开全文
  • Node.js 是单进程单线程应用程序,但是通过事件和回...Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数. 事件驱动模型
  • 详解node.js 事件循环

    2020-10-15 02:10:21
    主要介绍了node.js 事件循环的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
  • JavaScript 是浏览器的脚本语言。其主要作用是与客户端进行交互。最开始设计之初它就是单线程。因为它主要操作 DOM。如果设计成多线程,假设一个线程在操作某个 DOM 节点,一个线程又在删除这个 DOM 节点。这时候...
  • node和浏览器都是js运行的环境,二者都给js提供了一个很强大的功能,事件循环。那么什么是事件循环呢,简单讲就是在单线程中为了实现程序的高效运行而设定的事件执行机制 ...
  • 1.JavaScript事件循环 (1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。 (2)主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中...
  • js事件循环原理

    千次阅读 2020-08-09 21:35:02
    事件循环一、执行栈二、异步函数 一、执行栈 JS运行的环境称之为宿主环境。 执行栈:call stack,一个数据结构,用于存放各种函数的执行环境,每一个函数执行之前,它的相关信息会加入到执行栈。函数调用之前,创建...
  • JS事件循环机制图解

    2021-06-12 16:49:54
    1、什么是事件循环: 众所周知JS是单线程、解释性语言(解析一行执行一行)。这就意味着假如遇到耗时任务,比如setTimeout,那么整个程序势必会阻塞等待setTime
  • JS事件循环(Event Loop)

    千次阅读 2021-10-20 23:03:37
    为什么JavaScript是单线程? JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定...
  • JavaScript事件循环机制

    热门讨论 2021-07-25 14:59:10
    文章目录JavaScript事件循环机制线程和进程的概念浏览器执行线程浏览器内核的多种线程JavaScript 事件循环机制 JavaScript事件循环机制 JavaScript 是一门 单线程 的编程语言,这就意味着它一次只能完成一件事情,...
  • Node.js 事件循环详解及实例 Node.js 是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。 Node.js 的每一个 API 都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。 Node...
  • 本文通过实例给大家详细分析了JS事件循环机制的原理和用法,以下是全部内容: var start = new Date() setTimeout(function () { var end = new Date console.log('Time elapsed:', end - start, 'ms') }, 500)...
  • javascript 事件循环、任务执行顺序

    千次阅读 2018-05-18 01:22:25
    javascript 事件循环 可以先来看这样的一段代码, 可以思考下会输出什么结果: console.log('event start') setTimeout(function () { console.log('setTimeout'); }); new Promise(function(resolve,reject){ ...
  • 本文实例讲述了javascript事件循环event loop的简单模型解释与应用.分享给大家供大家参考,具体如下: js是单线程的,但是event loop的出现,使得js拥有可以处理高并发的性能。那么怎么理解event loop呢?网上百度一...
  • 事件循环(event loop) JS是一门单线程语言,意味着代码要一行一行的执行。所有任务都要排队,前一个任务结束,才会执行后一个任务。 但平时大家开发时常用到的ajax,setTimeOut,promise之类的并没有阻
  • 驯服野兽的任务是JavaScript事件循环。 安装 npm install going-loopy --global 用法 going-loopy 为什么? 在一次采访中,我被问过太多次以解释事件循环。 之后,我总是有点担心我错过了一部分,或者没有足够的...
  • 简单理解事件循环(Event Loop),同步任务和异步任务,宏任务与微任务
  • JS事件循环机制(Event Loop)总结 引言 javascript从诞生之日起就是一门单线程的非阻塞的脚本语言。这是由其最初的用途来决定的:与浏览器交互。 单线程意味着,javascript代码在执行的任何时候,都只有一个主线程来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 514,397
精华内容 205,758
关键字:

js事件循环

友情链接: 模式识别.zip