JS异步的执行顺序分析

  • 1.js的执行顺序,先同步后异步
  • 2.异步中任务队列的执行顺序: 先微任务microtask队列,再宏任务macrotask队列
  • 3.调用Promise 中的resolve,reject属于微任务队列,setTimeout属于宏任务队列

注意以上都是 队列,先进先出。

微任务包括 `process.nextTick` ,`promise` ,`MutationObserver`。

宏任务包括 `script` , `setTimeout` ,`setInterval` ,`setImmediate` ,`I/O` ,`UI rendering`。

在node环境下,process.nextTick的优先级高于Promise,也就是可以简单理解为:在宏任务结束后会先执行微任务队列中的nextTickQueue部分,然后才会执行微任务中的Promise部分。

javascript事件机制

题目1:

console.log('script start')
async function async1() {
  await async2()
  console.log('async1 end')
}
async function async2() {
  console.log('async2 end')
}
async1()

setTimeout(function() {
  console.log('setTimeout')
}, 0)

new Promise(resolve => {
  console.log('Promise')
  resolve()
})
.then(function() {
  console.log('promise1')
})
.then(function() {
  console.log('promise2')
})

console.log('script end')

执行结果?

分析:

首先执行 同步代码:

  • 1. 首先执行    console.log('script start')
  • 2. 执行 async1() 的时候,马上执行了 async2函数:console.log('async2 end')
  • 3. 顺序执行 new Promise()中的同步函数:console.log('Promise')
  • 4. 最后执行  console.log('script end')。

上面是同步执行的代码,然后看剩下的异步执行的代码:

首先,setTimeout是 宏观任务,排除到最后,剩下微观任务:

async function async1() {
  await async2()
  console.log('async1 end')
}
new Promise(resolve => {
  resolve()
})
.then(function() {
  console.log('promise1')
})
.then(function() {
  console.log('promise2')
})
  • 5. 然后根据先入先出的对列方式,先执行await async2() 后面阻碍的函数console.log('async1 end')
  • 6. 执行promise的resolve函数
new Promise(resolve => {
  resolve()
})

也就是接下来的两个then:console.log('promise1') ----console.log('promise2') ;

  • 7. 最后执行的是 setTimeout函数console.log('setTimeout') ;

综上所述,以上代码执行的顺序是:

1.script start >> 2.async2 end >> 3.Promise >> 4.script end >> 5.async1 end >> 6.promise1 >> 7.promise2 >> 8.setTimeout

题目2:

(function() {

    setTimeout(() => {
        console.log(0);
    });

    new Promise(resolve => {
        console.log(1);

        setTimeout(() => {
            resolve();
            Promise.resolve().then(() => console.log(2));
            console.log(3);
        });

        Promise.resolve().then(() => console.log(4));

    }).then(() => {
        console.log(5);
        Promise.resolve().then(() => console.log(8));
        setTimeout(() => console.log(6));
    });

    console.log(7);

})();
  • 1. 同样先执行同步代码,且先把setTimeout去掉:
new Promise(resolve => {
      console.log(1);
      Promise.resolve().then(() => console.log(4)); //微观任务
  }).then(() => {                  //then函数是执行对应的 resolve 的时候才执行的
      console.log(5);
      Promise.resolve().then(() => console.log(8));//微观任务
 }); console.log(7);

可以看出先执行:console.log(1);console.log(7);

  • 2. 执行微任务Promise.resolve().then(() => console.log(4));

代码变成了:

(function() {
  setTimeout(() => {
      console.log(0);
  });
  new Promise(resolve => {
      setTimeout(() => {
          resolve();
          Promise.resolve().then(() => console.log(2));
          console.log(3);
      });
  }).then(() => {
      console.log(5);
      Promise.resolve().then(() => console.log(8)); //这句是多加的
      setTimeout(() => console.log(6));
  });
})();

只剩下宏观任务(微观任务在宏观任务里,也就是宏观任务外面不在有微观任务了)

  • 3. 执行console.log(0);
  • 4.再执行 new Promise 中的 setTimeout,先执行里面的同步函数:console.log(3)
  • 5. 再执行上面的 resolve,对应的是下面的then函数:
then(() => {
      console.log(5);
      Promise.resolve().then(() => console.log(8)); //这句是多加的
      setTimeout(() => console.log(6));
 }

所以先执行console.log(5);

剩下的都是微观任务和宏观任务,先看微观任务:

new Promise(resolve => {
     resolve();
     Promise.resolve().then(() => console.log(2));
 }).then(() => {
     Promise.resolve().then(() => console.log(8));
     setTimeout(() => console.log(6));
 });

所以根据队列中的微观任务顺序先执行:console.log(2),在执行then中的console.log(8);

最后再执行 console.log(6)

综上所述,结果为

1/7/4/0/3/5/2/8/6

题目3:

(function() {
    setTimeout(() => {
        console.log(0);
    });

    new Promise(resolve => {

        console.log(1);

        setTimeout(() => {
            resolve();
            Promise.resolve().then(() => {
                console.log(2);
                setTimeout(() => console.log(3));
                Promise.resolve().then(() => console.log(4));
            });
        });

        Promise.resolve().then(() => console.log(5));

    }).then(() => {

        console.log(6);
        Promise.resolve().then(() => console.log(7));
        setTimeout(() => console.log(8));

    });

    console.log(9);
})();

解释如下:【同步>异步;微任务>宏任务】第一步:打印出1、9;如图

图a

由图a中的任务队列可知:
第二步: 执行微任务3,打印出5;
第三步:执行宏任务1,打印出0,
第四步:开始执行宏任务2;如图:

图b

第五步:由图b中的任务队列可知, 执行微任务4,打印出6,如图:

图c

第六步:由图c中的任务队列可知, 执行微任务5,打印出2;如图

图d

由图d的任务队列可知,
第七步:执行微任务6,打印出7;
第八步:执行微任务9,打印出4;
第九步:执行宏任务7,打印出8;
第十步:执行宏任务8,打印出3;

即答案是:

1-9-5-0-6-2-7-4-8-3

到此这篇关于JS异步执行顺序的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • JS多个异步请求 按顺序执行next实现解析

    在js里面,偶尔会遇见需要多个异步按照顺序执行请求,又不想多层嵌套,,这里和promise.all的区别在于,promise或者Jquery里面的$.when 是同时发送多个请求,一起返回,发出去的顺序是一起:这里是按照顺序发请求 首先创建一个迭代器,接收任意多个函数参数 function nextRegister(){ var args = arguments; var count = 0; var comm = {}; function nextTime(){ count++; if(cou

  • js 异步操作回调函数如何控制执行顺序

    需求: fun A() { asyn(parm1, parm2, onsuccess(){ }) ;} fun B() {asyn(paem1, parm2, onsuccess(){}) ;} 函数B要求执行在函数A之后 异步执行 如果直接使用 A(); B(); 是不能够满足执行条件的. 考虑将B作为回调函数传递给A,然后A再执行的onsucess中执行B函数 A(B); 即可实现功能需求. js是单线程的. 1.调用函数时,如果参数多于定义时的个数,则多余的参数将会被忽略,如果少于定义时的

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

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

  • Javascript异步执行不按顺序解决方案

    案例分析: 比如执行懒加载时候,onscroll 事件触发多次事件时候会调用多次 ajax 回调事件,由于每个事件返回先后次序并不能保证和触发前一致,所以在数据响应返回后所添加的数据顺序就很在 push 到数组上顺序不一致. 例子1: var res = []; function response(data) { res.push( data ); } // ajax(..)是某个库中提供的某个Ajax函数 ajax( "http://some.url.1", response );

  • JS异步的执行顺序分析

    1.js的执行顺序,先同步后异步 2.异步中任务队列的执行顺序: 先微任务microtask队列,再宏任务macrotask队列 3.调用Promise 中的resolve,reject属于微任务队列,setTimeout属于宏任务队列 注意以上都是 队列,先进先出. 微任务包括 `process.nextTick` ,`promise` ,`MutationObserver`. 宏任务包括 `script` , `setTimeout` ,`setInterval` ,`setImmediat

  • JS异步的执行原理和回调详解

    一.JS异步的执行原理   我们知道JavaScript是单线程的,而浏览器是多线程的.单线程执行任务需要一个个排队进行,假如一个任务需要很长时间执行(像ajax需要较长时间),会直接导致无响应,后面的任务一直在等待执行.这时候就需要用到异步.   想了解异步,首先我们要知道浏览器有最基本的三个常驻线程: JS引擎线程,事件触发线程,GUI渲染线程.   其中JS引擎线程和事件触发线程共同构成了一种事件循环机制,而GUI渲染线程与JS引擎是互斥的,当JS引擎执行时GUI线程会被挂起,GUI更新保

  • sql和MySQL的语句执行顺序分析

    今天遇到一个问题就是mysql中insert into 和update以及delete语句中能使用as别名吗?目前还在查看,但是在查阅资料时发现了一些有益的知识,给大家分享一下,就是关于sql以及MySQL语句执行顺序: sql和mysql执行顺序,发现内部机制是一样的.最大区别是在别名的引用上. 一.sql执行顺序 (1)from (2) on (3) join (4) where (5)group by(开始使用select中的别名,后面的语句中都可以使用) (6) avg,sum....

  • Android代码块执行顺序分析总结

    本文介绍了Android代码块执行顺序分析总结,分享给大家,具体如下: 子类.父类变量,代码块,以及构造方法的加载顺序,是我们在程序开发中时不时遇到的一个问题,也是比较容易混淆的. 基础准备: 变量: 成员变量(叫类变量.实例变量)和局部变量 方法: 成员方法和构造方法 代码块:普通代码块.构造代码块.静态代码块.同步代码块 测试的父类: public class ParentClass { public static String name = "爸爸"; public int ag

  • Shell 管道及执行顺序分析

    1.基本概念 a.I/O重定向通常与 FD有关,shell的FD通常为10个,即 0-9: b.常用FD有3个,为0(stdin,标准输入).1(stdout,标准输出).2(stderr,标准错误输出),默认与keyboard.monitor.monitor有关: c.用 < 来改变读进的数据信道(stdin),使之从指定的档案读进: d.用 > 来改变送出的数据信道(stdout, stderr),使之输出到指定的档案: e.0 是 < 的默认值,因此 < 与 0<是一样

  • 数据库中的SELECT语句逻辑执行顺序分析

    引言 这不是一个什么多深的技术问题,多么牛叉的编程能力.这跟一个人的开发能力也没有非常必然的直接关系,但是知道这些会对你的SQL编写,排忧及优化上会有很大的帮助.它不是一个复杂的知识点,但是一个非常基础的SQL根基.不了解这些,你一直用普通水泥盖房子:掌握这些,你是在用高等水泥盖房子. 然而,就是这么一个小小的知识点,大家可以去调查一下周围的同事朋友,没准你会得到一个"惊喜". 由于这篇文章是突然有感而写,下面随手编写的SQL语句没有经过测试. 看下面的几段SQL语句: 复制代码 代码

  • Shell 命令执行顺序分析[图]

    Shell 从标准输入或脚本中读取的每一行称为管道(pipeline);它包含了一个或多个命令(command),这些命令被一个或多个管道字符(|)隔开. 事实上还有很多特殊符号可用来分隔单个的命令:分号(;).管道(|).&.逻辑AND (&&),还有逻辑OR (||).对于每一个读取的管道,Shell都回将命令分割,为管道设置I/O,并且对每一个命令依次执行下面的操作: 整个步骤顺序如上图所示,看起来有些复杂.当命令行被处理时,每一个步骤都是在Shell的内存里发生的;Shel

  • Html中JS脚本执行顺序简单举例说明

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv=&qu

  • 页面中js执行顺序

    下面是测试的代码: 复制代码 代码如下: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <head runat="server"> <title>测试js的执行顺序</title> <script language="javascript" type="text/javascri

  • Js中async/await的执行顺序详解

    前言 虽然大家知道async/await,但是很多人对这个方法中内部怎么执行的还不是很了解,本文是我看了一遍技术博客理解 JavaScript 的 async/await(如果对async/await不熟悉可以先看下这篇文章)后拓展了一下,我理了一下await之后js的执行顺序,希望可以给别人解疑答惑,先简单介绍一下async/await. async/await 是一种编写异步代码的新方法.之前异步代码的方案是回调和 promise. async/await 是建立在 promise 的基础上

随机推荐