最近又碰到了event loop问题,之前研究的实在是浅显(https://www.cnblogs.com/zx0423/p/12641637.html)所以今天主要讲述promise的链式调用,async/await,requestAnimationFrame以及MutationObserver()。

1、Promise链式调用

    new Promise((resolve,reject)=>{
console.log("promise1");
resolve();
}).then(()=>{
//callback1
console.log("then11");
new Promise((resolve,reject)=>{
console.log("promise2");
resolve();
}).then(()=>{
// callback2
console.log("then21");
}).then(()=>{
// callback4
console.log("then23");
})
}).then(()=>{
// callback3
console.log("then12");
})

/*
1、new promsie是同步代码,立即执行
2、外部promise第一个then需要等外部promise被resolve后才执行,外部promise立即被resolve,于是执行注册的 then回调。此时外部第二then并未执行,因为他等待的是外部第一个then返回的promise
3、进入外部第一个then,回调里面是一个promise,执行内部promise时,同样两个then链式调用,内部第一个then执 行后,内部promise算执行完,返回一个新的promise给内部第二then用
4、外部第一个then执行完且有返回值,进入外部第二then
5、之后执行内部第二then
*/

解释:

// 行2 ,执行同步的executor函数
栈【 promise 】
宏任务队列【】
微任务队列【 callback1 】
执行结果:promise1
// 行7
栈【 callback1 】
宏任务队列【】
微任务队列【 callback2,callback3 】
执行结果:promise1 , then11 , promise2
//
栈【 callback2,callback3 】
宏任务队列【】
微任务队列【 callback4 】
执行结果:promise1 , then11 , promise2 , then21 , then12 ,
// 行16
栈【 callback4 】
宏任务队列【】
微任务队列【 】
执行结果:promise1 , then11 , promise2 , then21 , then12 , then23

️ 当行8添加 return 语句的时候,答案就截然不同了,大家可以自行体会一下。

2、async/await

  • async函数

  • 返回一个 Promise 对象

     async function test() {
    return 1; // async的函数 在这里隐式 使用 Promise.resolve(1)
    }

    //===>等价于
    new Promise(function(resolve, reject) {
    resolve(1);
    })
  • await

    每次我们使用 await, 解释器都创建一个 promise 对象,然后把剩下的 async 函数中的操作放到 then 回调函数中。async/await 的实现,离不开 Promise。

    1-await后面不是Promise对象,即是一些直接量 / 数值之类的
    • await会阻塞后面的代码,

      • 从右到左执行,

      • 再执行async外面的同步代码,

      • 同步代码执行完,再回到async内部,

      • 把这个非promise的东西,作为 await表达式的结果。

    2-await后面是Promise对象
    • await 它会“阻塞”后面的代码,

      • 从右到左执行,

      • 再执行async外面的同步代码,

      • 【期间不管宏任务微任务,就一直执行,直到...】

      • 直到 Promise 对象 resolved(也就是要等到了结果),即把 resolve 的 参数/值 作为 await 表达式的运算结果。

    理清上述执行顺序,对下面这道题就可以迎刃而解了。

 // async/await 与 then链式调用
async function f1(){
console.log("1");
await 'await的结果'
console.log("3")
} f1(); new Promise(function(resolve){
console.log("2")
resolve();
}).then(function(result){
new Promise( r => r()).then(() =>{
console.log(4)
}).then(()=>{
console.log(5);
})
}) 结果: 1,2,3,4,5

3、requestAnimationFrame & MutationObserver()

基本概念: Window.requestAnimationFrame(callback):告诉浏览器——希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画;
      MutationObserver():会在指定的DOM发生变化时被调用。【微任务,很好理解,按照正常的执行顺序执行即可】

大家先来看一段代码吧,思考一下他的执行结果是什么?然后在刷新看看,结果还是不是一样的了?

<div id="testElement"></div>
 setTimeout(() => {
console.log(performance.now(), 'settimeout');
}, 0) requestAnimationFrame(() => {
   console.log(performance.now(),'requestAnimationFrame');
}) const testElement = document.getElementById('testElement'); var observer = new MutationObserver(() => {
console.log('MutationObserver');
}); observer.observe(testElement, {
childList: true
})
//添加子节点,触发MutationObserver()
const div = document.createElement('div');
testElement.appendChild(div); new Promise(resolve => {
console.log('promise');
resolve();
}).then(() => console.log('then')) console.log(performance.now(), 'global');

如图:

可以看到,requestAnimationFrame的执行顺序是不一致的,

  起初,我将requestAnimationFrame归到宏任务中,原因是它绝大多数都会在setTimeout回调执行之后才执行。并将这个结果解释为是由于浏览器在执行渲染的时候,每次执行的时间会有差异,所以导致requestAnimationFrame和setTimeout被压入调用栈的时机不一致,也就导致了回调的时间不一致。

但是,可以看到宏任务与raf任务有明显的差异:
  执行时机不同;
  raf任务队列被执行时,会将其此刻队列中所有任务都执行完,既不属于宏任务/微任务,同时还排在微任务之后。

而且,在一个loop中,可能并不会执行这一步,只要浏览器任务不需要执行渲染,就会跳过。所以会出现requestAnimationFrame顺序不一致的状况。

EventLoop-浏览器篇2的更多相关文章

  1. 前端面试总结——http、html和浏览器篇

    1.http和https https的SSL加密是在传输层实现的. (1)http和https的基本概念 http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和 ...

  2. 浏览器事件循环 & nodejs事件循环

    第1篇:如何理解EventLoop——宏任务和微任务篇 宏任务(MacroTask)引入 在 JS 中,大部分的任务都是在主线程上执行,常见的任务有: 渲染事件 用户交互事件 js脚本执行 网络请求. ...

  3. 如何理解EventLoop--浏览器篇

    前言 最近在准备春招,刷到了JS中的主要运行机制--Event Loop,觉得它的实现思路有必要整理一下,以防忘记.关于它在浏览器上的实现,我结合了自己的理解以及示例代码,想用最通俗的语言表达出来.如 ...

  4. 浏览器如何执行JS

    作为JS系列的第一篇,内容当然是浏览器如何执行一段JS啦. 首先通过浏览器篇我们可以得知,JS是在渲染进程里的JS引擎线程执行的.在此之后还要了解几个概念,编译器(Compiler).解释器(Inte ...

  5. Event Loop

    Event Loop 是 JavaScript 异步编程的核心思想,也是前端进阶必须跨越的一关.同时,它又是面试的必考点,特别是在 Promise 出现之后,各种各样的面试题层出不穷,花样百出.这篇文 ...

  6. 总结:JavaScript异步、事件循环与消息队列、微任务与宏任务

    本人正在努力学习前端,内容仅供参考.由于各种原因(不喜欢博客园的UI),大家可以移步我的github阅读体验更佳:传送门,喜欢就点个star咯,或者我的博客:https://blog.tangzhen ...

  7. (转)总结:JavaScript异步、事件循环与消息队列、微任务与宏任务

    前言 Philip Roberts 在演讲 great talk at JSConf on the event loop 中说:要是用一句话来形容 JavaScript,我可能会这样: “JavaSc ...

  8. html5手机常见问题与工具分享

    mobileTech A useful tools or tips list for mobile web application developing 这个项目收集移动端开发所需要的一些资源与小技巧 ...

  9. mobileTech

    A useful tools or tips list for mobile web application developing 这个项目收集移动端开发所需要的一些资源与小技巧 工具类网站 HTML ...

  10. TGL站长关于常见问题的回复

    问题地址: http://www.thegrouplet.com/thread-112923-1-1.html 问题: 网站配有太多的模板是否影响网站加载速度 月光答复: wp不需要删除其他的模板,不 ...

随机推荐

  1. python小题目汇总

    1.编程计算两个日期之间的天数与周数 Python时间处理---dateutil模块: dateutil模块主要有两个函数,parser和rrule. 其中parser是根据字符串解析成datetim ...

  2. python 变量的命名规则和注意事项

    命名规则 变量名只能包含字母.数字和下划线.变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为message_1,但不能将其命名为1_message 变量名不能包含空格,但可使用下划线 ...

  3. java进阶(2)--抽象类

    一.抽象类集刺虎: 1.概念 类与类之前有共同特征,将这些共同特征提取出来,行为抽象类   2.抽象类的数据类型: 引用数据类型   3.语法 [修饰符列表]abstract Class 类型{类体} ...

  4. 11-Arrays工具类的使用

    1.理解:① 定义在java.util包下.② Arrays:提供了很多操作数组的方法. 2.使用: //1.boolean equals(int[] a,int[] b):判断两个数组是否相等. i ...

  5. c++日志工具spdLog

    c++日志工具spdLog简单使用示例代码 spdlog直接引用头文件就可以使用,这一点还是比较方便的,也是刚入门使用,下面是在源码的示例代码基础上修改测试的代码: #include <cstd ...

  6. Springboot+swagger2.7集成开发

    Springboot+swagger2.7集成开发 本篇文章是介绍最新的springboot和swagger2.7集成开发和2.0稍微有一些出入: Springboot集成环境配置 Swagger2. ...

  7. CentOS7安装MinIO教程,并在C#客户端WPF中实现监控上传进度

    MinIO的详细介绍可以参考官网(https://min.io/product/overview). 简单来说它是一个实现了AWS S3标准的100%开源的,可商用的( Apache V2 licen ...

  8. C#LeetCode刷题之#788-旋转数字(Rotated Digits)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3967 访问. 我们称一个数 X 为好数, 如果它的每位数字逐个地 ...

  9. Vue 大量data及rules的data选项结构组织

    如果Vue文件需要很多的data成员及表单验证,建议使用类似结构 export default{ data(){ const model = { username: 'suzhen', passwor ...

  10. .net Core 下使用 X509Certificate2 给报文加签

    起因 项目开发中途出现需求需要对接其他公司接口,使用证书进行认证传输,之前在.Net下搞过但是都是对方给我证书 这次需要我生成公钥/私钥,公钥给他这样操作. 生成私钥/公钥(这里是RSA算法,长度规定 ...