前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JavaScript: 从 Event Loop 到 Promise (常见问题分析)

JavaScript: 从 Event Loop 到 Promise (常见问题分析)

作者头像
西南_张家辉
发布2021-02-02 10:19:53
6680
发布2021-02-02 10:19:53
举报
文章被收录于专栏:张家辉的树屋张家辉的树屋

写在最前面

  • promise 作为前端常用的工具,今天从底了解一下 promise 的使用和基础知识。
    • 其中有出入或者错误的地方希望朋友们指出。

导航

  • 一、同步和异步
  • 二、单线程和多线程
  • 三、evet loop
  • 四、实战,promise 题目分析

Promise

  • 什么是 promise?
    • 我们先明确:Promise 对象用于表示一个异步操作的最终完成 (或失败), 及其结果值.
  • 什么是 async 和 await
    • async/await 使得异步代码看起来像同步代码(实际是阻塞了代码),一句话总结,async 函数就是 Generator 函数的语法糖,返回了一个 promise.resolve() 的结果。阮一峰老师的 async 教程
  • 上面提到了一个异步的问题,我们前端er都知道 JavaScript - 是单线程的,如果存在多个任务的时候,就会有任务队列进行排队,然后一一执行任务。

不着急介绍 promise 的详情,首先我们从最开始的同步和异步讲起:

一、同步和异步

1.1 同步

简单的理解

  • 如果函数在返回结果的时候,调用者能够拿到预期的结果(即使会等待但是依然能拿到预期的结果),那么这个函数就是同步的。
代码语言:javascript
复制
console.log('synchronous'); //我们能立即得到 synchronous

1.2 异步

简单的理解

  • 如果函数返回的时候,不能立即得到预期的结果,而是通过一定的手段得到的(比如回调函数 callback()), 这就是异步,比如常用的 promise 和 ajax 操作等。

来看一个图

image
image

二、单线程和多线程

  • 简单的了解了同步和异步的概念后,我们看看什么是单线程和多线程?

2.1 浏览器常驻线程

一个浏览器通常由以下几个常驻的线程:

  1. 渲染引擎线程,负责页面的渲染
  2. js引擎线程,负责js的解析和执行
  3. 定时触发器线程,处理setInterval和setTimeout
  4. 事件触发线程,处理DOM事件
  5. 异步http请求线程,处理http请求
  • 要注意其中渲染引擎js引擎线程是不能同时进行的,渲染线程在执行任务的时候,js引擎线程会被挂起。因为若是在渲染页面的时候,js处理了DOM,浏览器就不知道该听谁的了

2.2 JS 引擎

  1. 渲染引擎:Chrome/Safari/Opera用的是Webkit引擎,IE用的是Trdent引擎,FireFox用的是Gecko引擎。不同的引擎对同一个样式的实现不一致,就导致浏览器的兼容性问题。
  2. JS引擎:js引擎可以说是js虚拟机,负责解析js代码的解析和执行。通常有以下步骤:
    • 词法解析:将源代码分解位有意义的分词
    • 语法分析:用语法分析器将分词解析成语法树
    • 代码生成:生成机器能运行的代码
    • 代码执行
  • 当然不同浏览器的JS引擎也是不同的:Chrome用的是V8,FireFox用的是SpiderMonkey,Safari用的是JavaScriptCore,IE用的是Chakra。

总结一点:JavaScript是单线程的,但是浏览器不是单线程的。一些I/O操作,定时器的计时和事件监听是由其他线程完成的。

三、消息队列和事件循环

开局一张图

image
image

导图要表达的内容用文字来表述的话: 1.同步和异步任务分别进入不同的执行"场所" 2.同步的进入主线程,异步的进入Event Table并注册回调函数到 Event Queue 中。 3.当主线程执行完毕以后,然后会去 Event Queue 查询,时候如果存在的函数,放进主线程中继续执行。 4.上述就是event loop的执行

说了这么多文字,不如直接一段代码更直白:

代码语言:javascript
复制
console.log('script start');

new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function cb() {
    console.log('promise2');
});

console.log('script end');

// script start
// promise1
// script end
// promise2

复制代码

分析这段代码:

代码语言:javascript
复制
首先执行,打印 script start

然后进入 promise 函数打印 promise1,执行 resolve()
在 then 执行的时候我们把异步回调放进了 event table 中注册相关的回调函数。
new promise 执行完毕,回调函数cb() 进入Event Queue。

执行 打印 script end;

主线程从Event Queue读取回调函数 cb 并执行。

3.1 宏任务和微任务

  • 记住一点,当同一个 event queue 中有 微任务 的时候,优先执行 微任务

macro-task(宏任务):包括整体代码script,setTimeout,setInterval micro-task(微任务):Promise,process.nextTick

image
image
  • 这里只是简单的介绍一下基本原理,https://juejin.im/post/6844903512845860872
看一个栗子

3.2 思考一下代码执行顺序

代码语言:javascript
复制
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');

// 思考上述代码打印结果
复制代码

注意几个点

代码语言:javascript
复制
1、js是单线程的。
2、promise被定义后是立即执行的,但是他的resolve是异步的。
3、promise的异步优先级高于setTimeout。
4、async会返回一个promise对象,await关键字会让出线程。
  • 分析
代码语言:javascript
复制
- 定义异步函数 async1, 异步函数 async2
1. console.log('script start'); 执行 (1)`script start`

2. setTimeout 执行,异步放入异步队列中,注意这是一个宏任务(我们标记为 macro1)

3. 执行 async1(), 打印 (2)`async1 start`, 执行 async1() 中的 await async2(): 打印 (3)`async2`;
遇到 await 后面的函数进入任务队列,这里又注册一个微任务(我们标记为 mico1);到这里 async1() 就执行完了

4. 执行 new Promise:打印 (4)`promise1`,执行 resolve();
然后在 then 中注册回调函数,console.log('promise2') 函数进入任务队列;
注册 event queue(我们标记为 mico2).这里 new Promise 就执行完了。

5. 执行 console.log('script end');, 打印 (5) `script end`;

6. 上面
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导航
  • Promise
    • 一、同步和异步
      • 1.1 同步
      • 1.2 异步
    • 二、单线程和多线程
      • 2.1 浏览器常驻线程
      • 2.2 JS 引擎
    • 三、消息队列和事件循环
      • 3.1 宏任务和微任务
      • 3.2 思考一下代码执行顺序
相关产品与服务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档