JavaScript异步编程

 同步与异步

#先看 2 段代码
<span style="background-color:#282c34"><span style="color:#2c3e50"><span style="color:#cccccc"><code><span style="color:#999999">//代码1</span>
<span style="color:#cc99cd">const</span> <span style="color:#f08d49">test</span> <span style="color:#67cdcc">=</span> <span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  <span style="color:#cc99cd">let</span> t <span style="color:#67cdcc">=</span> <span style="color:#67cdcc">+</span><span style="color:#cc99cd">new</span> <span style="color:#f8c555">Date</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
  <span style="color:#cc99cd">while</span> <span style="color:#cccccc">(</span><span style="color:#f08d49">true</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
    <span style="color:#cc99cd">if</span> <span style="color:#cccccc">(</span><span style="color:#67cdcc">+</span><span style="color:#cc99cd">new</span> <span style="color:#f8c555">Date</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">-</span> t <span style="color:#67cdcc">>=</span> <span style="color:#f08d49">2000</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
      <span style="color:#cc99cd">break</span>
    <span style="color:#cccccc">}</span>
  <span style="color:#cccccc">}</span>
<span style="color:#cccccc">}</span>
console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">1</span><span style="color:#cccccc">)</span>
<span style="color:#f08d49">test</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">2</span><span style="color:#cccccc">)</span>
console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">3</span><span style="color:#cccccc">)</span>
<span style="color:#999999">// 执行结果 1 2 3</span>

<span style="color:#999999">// 代码2</span>
console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">1</span><span style="color:#cccccc">)</span>
<span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">2</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">,</span> <span style="color:#f08d49">2000</span><span style="color:#cccccc">)</span>
console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">3</span><span style="color:#cccccc">)</span>

<span style="color:#999999">// 执行结果 1 3 2</span>
</code></span></span></span>

代码 1 都是同步任务,代码 2 有异步任务 setTimeout;所有执行结果不同

同步:主线程上排队执行的任务,只有前面的任务执行完,才能执行后面的任务

异步:是指不进入主线程,而是进入任务队列的任务,只有任务队列通知主线程,某个 任务可以执行了,该任务才会进入主线程执行

#单线程的 js 怎么实现异步?

如果按照 js 是单线程的,上面的代码 2 应该是 123 才符合单线程的表现;现在为什么是 132 呢,那异步怎么实现的呢?

#学习异步之前先了解一下什么是进程?什么是线程?

打个比方:假如 cpu 是一个工厂,进程就是一个车间;线程就是工人,一个进程有多个线程,它们之间资源共享,也就内存空间共享。

linux 下 查看进程:

ps (process status) 列出系统中当前运行进程的快照

top (table of processes) 动态实时查看进程

kill 9 进程 pid 杀死进程

回答单线程的 js 怎么实现异步?

通过浏览器的内核多线程实现异步

3.1.2 javaScript 单线程

 浏览器是一个多进程的架构

我们打开一个浏览器就会启动以下进程,我们所要关心的是渲染进程,渲染进程是浏览器的核心进程

渲染进程下的多线程

GUI 线程:负责渲染页面,解析 html、css;构建 DOM 树和渲染树

js 引擎线程: js 引擎线程负责解析和执行 js 程序,我们经常听到的 chrome 的 v8 引擎就是跑在 js 引擎线程上的,js 引擎线程只有一个,所有说 js 的单线程语言的原因,那其实语言没有单线程多线程之说,因为解释这个语言的是 的线程是单线程;js 引擎线程与 gui 线程互斥,当浏览器执行 javaScript 程序的时候,GUI 渲染线层会保存在一个队列当中;直到 js 程序执行完成,才会接着执行;如果 js 的执行时间过长,会影响页面的渲染不连贯,所有我们要尽量控制 js 的大小

定时触发线程:为什么 setTimeout 不阻塞后面程序的运行,那其实 setTimeout 不是由 js 引擎线程完成的,是由定时器触发线程完成的,所以它们可以是同时进行的,那么定时器触发线程在这定时任务完成之后会通知事件触发线程往任务队列里添加事件

事件触发线程:将满足触发条件的事件放入任务队列,一些异步的事件会放到异步队列中

异步 HTTP 请求线程:用与处理 ajax 请求的,当请求完成时如果有回调函数就通知事件触发线程往任务队列中添加任务

#异步场景
  1. 定时器
  2. 网络请求
  3. 事件绑定
  4. ES6 Promise

#3.1.3 定时器

#定时器的执行过程

代码在执行栈中执行,然后 1=>2=>3=>4

定时器示例

执行过程解释

  1. console.log(1)先入栈执行,执行完出栈
  2. 遇到setTimeout 调用 setTimeout 这个 webapi,通知定时触发线程定时 2 秒钟
  3. console.log(3)入栈执行,执行完出栈
  4. 栈中已经空了,去检查任务队列,此时还为到 2 秒钟,任务队列中还没有任务;这是一个循环检查的过程,等到 2 秒钟后 事件触发线程往任务队列中添加了定时器的事件,这时候再去检查的时候已经有了定时器的异步任务,我们取出这个任务放到执行栈中执行,这时候打印出了 2
#定时器会带来的问题
  1. 定时任务可能不能按时执行
<span style="background-color:#282c34"><span style="color:#2c3e50"><span style="color:#cccccc"><code><span style="color:#cc99cd">const</span> <span style="color:#f08d49">test</span> <span style="color:#67cdcc">=</span> <span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  <span style="color:#cc99cd">let</span> t <span style="color:#67cdcc">=</span> <span style="color:#67cdcc">+</span><span style="color:#cc99cd">new</span> <span style="color:#f8c555">Date</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
  <span style="color:#cc99cd">while</span> <span style="color:#cccccc">(</span><span style="color:#f08d49">true</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
    <span style="color:#cc99cd">if</span> <span style="color:#cccccc">(</span><span style="color:#67cdcc">+</span><span style="color:#cc99cd">new</span> <span style="color:#f8c555">Date</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">-</span> t <span style="color:#67cdcc">>=</span> <span style="color:#f08d49">5000</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
      <span style="color:#cc99cd">break</span>
    <span style="color:#cccccc">}</span>
  <span style="color:#cccccc">}</span>
<span style="color:#cccccc">}</span>
<span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">2</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">,</span> <span style="color:#f08d49">2000</span><span style="color:#cccccc">)</span>
<span style="color:#f08d49">test</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
<span style="color:#999999">// 等到5秒钟后才打印出了2</span>
</code></span></span></span>

为什么呢?

因为 test 是会耗时 5 秒钟的同步任务,异步任务只能等待同步任务执行完之后才能执行,也就是说只能等 5 秒钟后才能检查的任务队列里的任务。

  1. 定时器嵌套 5 次之后最小间隔不能低于 4ms
#定时器的应用场景
  1. 防抖节流
  2. 到计时
  3. 动画 (有丢帧问题)

#3.2 Event Loop 机制

以前 js 是在浏览器环境中运行,由于 chrome 对 v8 做了开源;所以 js 有机会在服务端运行;浏览器和 node 都是 js 的运行环境,它们相当于是一个宿主,宿主能提供一个能力能帮助 js 实现 Event Loop

# js 单线程问题

所有任务都在一个线程上完成,一旦遇到大量任务或遇到一个耗时的任务,网页就可能出现假死,也无法响应用户的行为

# Event Loop 是什么

Event Loop 是一个程序结构,用于等待和发送信息的事件。 简单说就是在程序中设置 2 个线程,一个负责程序本身的运行,称为“主线程”;另一个负责主线程和其他进程(主要是各种 I/O 操作)的通信 被称为“Event Loop 线程”(也可以翻译为消息线层)

js 就是采用了这种机制,来解决单线程带来的问题。

#3.2.1 浏览器的 Event Loop

#异步实现
  1. 宏观:浏览器多线程(从宏观来看是多线程实现了异步)
  2. 微观:Event Loop,事件循环(Event Loop 翻译是事件循环,是实现异步的一种机制)
#先看一个例子
<span style="background-color:#282c34"><span style="color:#2c3e50"><span style="color:#cccccc"><code>console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">1</span><span style="color:#cccccc">)</span>
<span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cc99cd">function</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">2</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">,</span> <span style="color:#f08d49">0</span><span style="color:#cccccc">)</span>
Promise<span style="color:#cccccc">.</span><span style="color:#f08d49">resolve</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span><span style="color:#cc99cd">function</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">3</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">4</span><span style="color:#cccccc">)</span>
<span style="color:#999999">// 1 4 3 2</span></code></span></span></span>

 

1 和 4 是同步任务肯定是最先执行,现在要看异步任务,现在要看的是promise的回调为什么在定时器前面执行,那为什么promise后放入,为什么先执行呢?那是因为 Event Loop 的机制是有微任务的说法的;现在往下看。

 宏任务(普通任务)和微任务

宏任务(task)

  1. script:script 整体代码
  2. setImmediate:node 的一个方法
  3. setTimeout 和 setInterval
  4. requestAnimationFrame
  5. I/O
  6. UI rendering

......

微任务(microtask)

  1. Object.observe:监听对象变化的一个方法
  2. MutationObserver:可以监听 Dom 结构变化的一个 api
  3. postMessgae:window 对象通信的一个方法
  4. Promise.then catch finally
# Event Loop 的运行过程

 线程都有自己的数据存储空间,上图可以看见,堆的空间比较大,所以存储一些对象;栈的空间比较小, 所以存储一些基础数据类型、对象的引用、函数的调用;函数调用就入栈,执行完函数体里的代码就自动从栈中移除这个函数,这就是我们所说的调用栈; 栈是一个先进后出的数据结构,当最里面的函数出栈的时候,这个栈就空了;当我们调用时候会调用一些异步函数, 这个异步函数会找他们的异步处理模块,这个异步模块包括定时器、promise、ajax 等,异步处理模块会找它们各自 对应的线程,线程向任务队列中添加事件,看我们的蓝色箭头,表示在任务队列中添加事件,橘色的箭头是从任务队列中取事件,取出这个事件去执行对应的回调函数;

有 3 个点要注意

  1. 我们整个大的 script 的执行是全局任务也是一个宏任务的范畴,
  2. 当宏任务执行完,会去执行所有的微任务,
  3. 微任务全部执行完在去执行下一个宏任务,那什么时候去执行一个微任务呢,是等调用栈为空的时候, 调用栈不为空的时候,任务队列的微任务一直等待;微任务执行完又去取任务队列里的宏任务,去依次 执行宏任务,执行宏任务的时候就要检查当前有没有微任务,如果有微任务就去执行完所有微任务,然后 再去执行后续的宏任务
#代码示例 1

执行步骤

  1. 大的 script 是个宏任务,检查任务队列是否为空,当前不为空,然后执行 1 和 8 行代码;那么打印出了 1 和 4
  2. 执行完 1 和 8 行代码后去检查微任务队列,微任务队列不为空,执行了 Promise 的回调,此时打印出了 3
  3. 执行完 Promise 的回调后,在检查微任务队列,现在微任务队列为空,进行重新渲染一便
  4. 在去检查任务队列,现在任务队列中有了定时器的事件,又打印出了 2

注意点

  1. 一个 Event Loop 有一个或多个 task queue(任务队列)
  2. 每个个 Event Loop 有一个 microtask queue(微任务队列)
  3. requestAnimationFrame 不在任务队列也不在为任务队列,是在渲染阶段执行的
  4. 任务需要多次事件循环才能执行完,微任务是一次性执行完的
  5. 主程序和和 settimeout 都是宏任务,一个 promise 是微任务,第一个宏任务(主程序)执行完,执行全部的微任务(一个 promise),再执行下一个宏任务(settimeout)
#代码示例 2
<span style="background-color:#282c34"><span style="color:#2c3e50"><span style="color:#cccccc"><code>console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'start'</span><span style="color:#cccccc">)</span>

<span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'setTimeout'</span><span style="color:#cccccc">)</span>
  <span style="color:#cc99cd">new</span> <span style="color:#f8c555">Promise</span><span style="color:#cccccc">(</span>resolve <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'promise inner1'</span><span style="color:#cccccc">)</span>
    <span style="color:#f08d49">resolve</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'promise then1'</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">,</span> <span style="color:#f08d49">0</span><span style="color:#cccccc">)</span>

<span style="color:#cc99cd">new</span> <span style="color:#f8c555">Promise</span><span style="color:#cccccc">(</span>resolve <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'promise inner2'</span><span style="color:#cccccc">)</span> <span style="color:#999999">//同步执行的</span>
  <span style="color:#f08d49">resolve</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'promise then2'</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>

<span style="color:#999999">// 打应结果</span>
<span style="color:#999999">/*
    start
    promise inner2
    promise then2
    setTimeout
    promise inner1
    promise then1
   */</span>
</code></span></span></span>
# 代码示例 3
<span style="background-color:#282c34"><span style="color:#2c3e50"><span style="color:#cccccc"><code><span style="color:#cc99cd">async</span> <span style="color:#cc99cd">function</span> <span style="color:#f08d49">async1</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'async1 start'</span><span style="color:#cccccc">)</span>
  <span style="color:#cc99cd">await</span> <span style="color:#f08d49">async2</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'async1 end'</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span>

<span style="color:#cc99cd">async</span> <span style="color:#cc99cd">function</span> <span style="color:#f08d49">async2</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  <span style="color:#cc99cd">return</span> Promise<span style="color:#cccccc">.</span><span style="color:#f08d49">resolve</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span>_ <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'async2 promise'</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span>

console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'start'</span><span style="color:#cccccc">)</span>
<span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cc99cd">function</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'setTimeout'</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">,</span> <span style="color:#f08d49">0</span><span style="color:#cccccc">)</span>

<span style="color:#f08d49">async1</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>

<span style="color:#cc99cd">new</span> <span style="color:#f8c555">Promise</span><span style="color:#cccccc">(</span><span style="color:#cc99cd">function</span><span style="color:#cccccc">(</span>resolve<span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'promise1'</span><span style="color:#cccccc">)</span>
  <span style="color:#f08d49">resolve</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span><span style="color:#cc99cd">function</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#7ec699">'promise2'</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>

<span style="color:#999999">/*
       start
       async1 start
       promise1
       async2 promise
       promise2
       async1 end
       setTimeout
   */</span>
</code></span></span></span>

执行步骤

  1. 先执行主线程的同步任务(也是宏任务), 先执行start然后遇到了 setTimeout,把它放到下一次宏任务中执行,我们叫它宏 2;然后调用 async1()函数,执行了async1 start;又调用了 async2 函数执行 Promise.resolve().then;由于 then 的回调函数是微任务,就把它放到微任务队列中,我们叫它微 1;遇见 await 是等待的意思,需要把第一轮的微任务执行完,在执行 await 下面的内容,我们在执行 new Promise(),打印了promise1,又调用了 resolve()改变了 promise 状态,这个 then 的回调我们叫它微 2;第一轮宏任务执行完毕。

  2. 第一轮宏热任务执行完毕后,我们检查微任务队列中的微任务,把它全部执行完,就打印了async2 promisepromise2

  3. 第一轮微任务执行完,就执行 await 后面的内容async1 end

  4. await 后面的内容执行完后又执行宏任务setTimeout

#代码示例 4
<span style="background-color:#282c34"><span style="color:#2c3e50"><span style="color:#cccccc"><code><span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">1</span><span style="color:#cccccc">)</span>
  <span style="color:#cc99cd">new</span> <span style="color:#f8c555">Promise</span><span style="color:#cccccc">(</span>r <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    <span style="color:#f08d49">r</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span>res <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">2</span><span style="color:#cccccc">)</span>
    Promise<span style="color:#cccccc">.</span><span style="color:#f08d49">resolve</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
      console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">3</span><span style="color:#cccccc">)</span>
    <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
<span style="color:#f08d49">setTimeout</span><span style="color:#cccccc">(</span><span style="color:#cccccc">(</span><span style="color:#cccccc">)</span> <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
  console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">4</span><span style="color:#cccccc">)</span>
  <span style="color:#cc99cd">new</span> <span style="color:#f8c555">Promise</span><span style="color:#cccccc">(</span>r <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    <span style="color:#f08d49">r</span><span style="color:#cccccc">(</span><span style="color:#f08d49">1</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span><span style="color:#cccccc">.</span><span style="color:#f08d49">then</span><span style="color:#cccccc">(</span>res <span style="color:#67cdcc">=></span> <span style="color:#cccccc">{</span>
    console<span style="color:#cccccc">.</span><span style="color:#f08d49">log</span><span style="color:#cccccc">(</span><span style="color:#f08d49">5</span><span style="color:#cccccc">)</span>
  <span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
<span style="color:#cccccc">}</span><span style="color:#cccccc">)</span>
<span style="color:#999999">/*
1
2
3
4
5
*/</span>
</code></span></span></span>
  1. 先执行 script 代码,遇到第一个 setTimeout,放到宏任务队列中我们叫它宏 1,遇到第二个 setTimeout,放到宏任务队列中我们叫它宏 2。
  2. 检查微任务队列中有无任务,有就全部执行,本次宏任务下没有产生微任务,没有就拿出宏 1 进行执行,执行宏 1 打印1;然后遇到 promise 就把 then 的回调放到微任务队列;宏 1 执行完以后,就去检查微任务队列中有任务么,有就全部执行,所以我们就执行了 2,在 then 的回调中又产生了微任务,所以我们又执行了 3,记住一点,要把本次宏任务下所产生的微任务全部执行完才会执行下一个宏任务,记住是产生的,没有产生的不会执行。
  3. 一轮宏任务执行完以后,再去执行下一个宏任务,就会去执行宏 2,就打印了 4,在检查有没有产生了微任务,如果微任务队列中有微任务就全部执行,有微任务所以打印了 5。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/183580.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++学习之路(一)什么是C++?如何循序渐进的学习C++?【纯干货】

C是一种高级编程语言&#xff0c;是对C语言的扩展和增强。它在C语言的基础上添加了面向对象编程&#xff08;OOP&#xff09;的特性&#xff0c;使得开发者能够更加灵活和高效地编写代码。 C的名字中的“”符号表示在C语言的基础上向前发展一步&#xff0c;即“加加”&#x…

多功能回馈式交流电子负载的应用

多功能回馈式交流电子负载是用于模拟和测试电源、电池等电子设备的负载工具。它具有多种应用&#xff0c;可以用于测试和评估各种类型的电源&#xff0c;包括直流电源和交流电源。它可以模拟各种负载条件&#xff0c;如恒定电流、恒定电压和恒定功率&#xff0c;以验证电源的性…

电脑技巧:推荐八个非常实用的在线网站值得收藏

目录 1、wikihow 干货分享网站 2、次元小镇 二次元必备网站 3、AI创作家 4、SKRbt 搜索引擎网站 5、barbg 全球资源网站 6、书签地球 7、4KHDR世界 8、a real me 今天小编给大家推荐八个非常实用的在线网站值得收藏&#xff01; 1、wikihow 干货分享网站 这个网站是一…

微信小程序制作

如果你也想搭建一个小程序&#xff0c;但不知道如何入手&#xff0c;那么今天我就教你如何使用第三方制作平台&#xff0c;在短短三十分钟内搭建一个小程序。 一、登录小程序制作平台 首先&#xff0c;登录到小程序制作平台的官方网站或应用程序&#xff0c;进入后台管理系统。…

geemap学习笔记013:为遥感动态GIF图添加图名

前言 遥感动态GIF图可以展示地理区域随时间的变化&#xff0c;这对于监测自然灾害、湿地变化、城市扩展、农田变化等方面非常有用&#xff0c;并且可以反复观察图像&#xff0c;以更深入地了解地表的动态变化。本节主要是对遥感动态GIF图添加图名&#xff0c;以便于更好地理解…

【Redis】前言--redis产生的背景以及过程

一.介绍 为什么会出现Redis这个中间件&#xff0c;从原始的磁盘存储到Redis中间又发生了哪些事&#xff0c;下面进入正题 二.发展史 2.1 磁盘存储 最早的时候都是以磁盘进行数据存储&#xff0c;每个磁盘都有一个磁道。每个磁道有很多扇区&#xff0c;一个扇区接近512Byte。…

基于STC12C5A60S2系列1T 8051单片读写掉电保存数据IIC总线器件24C02一字节并显示在液晶显示器LCD1602上应用

基于STC12C5A60S2系列1T 8051单片读写掉电保存数据IIC总线器件24C02一字节并显示在液晶显示器LCD1602上应用 STC12C5A60S2系列1T 8051单片机管脚图STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式及配置STC12C5A60S2系列1T 8051单片机I/O口各种不同工作模式介绍IIC通信简单…

【深度学习】如何选择神经网络的超参数

1. 神经网络的超参数分类 神经网路中的超参数主要包括: 1. 学习率 η 2. 正则化参数 λ 3. 神经网络的层数 L 4. 每一个隐层中神经元的个数 j 5. 学习的回合数Epoch 6. 小批量数据 minibatch 的大小 7. 输出神经元的编码方式 8. 代价函数的选择 9. 权重初始化的方法 …

IP 代理的基础知识有哪些?

本文将介绍流冠IP代理的基础知识&#xff0c;帮助您了解IP代理的概念、类型、作用、设置方法和注意事项。 一、IP代理的概念 IP代理是一种网络代理服务&#xff0c;它通过代理服务器帮助用户访问互联网&#xff0c;并将用户的请求转发到目标网站&#xff0c;同时将目标网站的响…

Pycharm 教育版下载

1 访问 Jetbrains 主站-->Developer Tools-->PyCharm JetBrains: Essential tools for software developers and teams 2 页面往下划找到 PyCharm for Education-->CHECK IT OUT! PyCharm: the Python IDE for Professional Developers by JetBrains 3 点击 Downloa…

【SpringMVC】 对请求的不同响应

前言 本文学习如何运用不同的注解来返回不同的响应. 1.返回静态页面Controller 返回index.html页面 Controller 和 RestController的区别 controller 只有加上这个注解,Spring才会帮我们管理这个代码.后续我们访问时才能访问到. RestController 等同于 Controller ResponseBo…

域控操作五:统一熄屏睡眠时间

直接看图路径&#xff0c;我只设置了熄屏&#xff0c;如果要睡眠就下面那个启用设置时间

Elasticsearch基础教程

​ Elasticsearch是一个实时的分布式搜索分析引擎&#xff0c;底层基于Lucene实现。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;并且客户端可以使用标准的RESTful进行访问。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xf…

python树的双亲存储结构

这种存储结构是一种顺序存储结构&#xff0c;采用元素形如“[结点值&#xff0c;双亲结点索引]”的列表表示。通常每个结点有唯一的索引(或者伪地址&#xff09;,根结点的索引为0&#xff0c;它没有双亲结点&#xff0c;其双亲结点的索引为-1。例如&#xff0c;所示的树对应的双…

NVM得介绍和详细使用教程

NVM​​​​​​​&#xff08;Node Version Manager&#xff09;是一个用于管理多个Node.js版本的工具。它允许您在同一台计算机上轻松地切换和管理不同的Node.js版本。以下是NVM的介绍和详细使用教程&#xff1a; 安装NVM&#xff1a; 首先&#xff0c;您需要在计算机上安装N…

一文2000字使用JMeter进行接口测试教程!(建议收藏)

安装 使用JMeter的前提需要安装JDK&#xff0c;需要JDK1.7以上版本目前在用的是JMeter5.2版本&#xff0c;大家可自行下载解压使用 运行 进入解压路径如E: \apache-jmeter-5.2\bin&#xff0c;双击jmeter.bat启动运行 启动后默认为英文版本&#xff0c;可通过Options – Cho…

【开源】基于Vue.js的固始鹅块销售系统

项目编号&#xff1a; S 060 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S060&#xff0c;文末获取源码。} 项目编号&#xff1a;S060&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 鹅块类型模块2.3 固…

【miniQMT实盘量化5】获取财务报表数据

前言 上面文章&#xff0c;我们介绍了如何获取实时数据&#xff0c;这篇文章&#xff0c;我们继续往下探讨&#xff0c;介绍关于财务报表数据的获取。 财务报表数据 财务报表数据&#xff0c;也就是常说的基本面数据&#xff0c;是除了行情数据之外&#xff0c;辅助我们投资…

qgis添加xyz栅格瓦片

方式1&#xff1a;手动一个个添加 左侧浏览器-XYZ Tiles-右键-新建连接 例如添加高德瓦片地址 https://wprd01.is.autonavi.com/appmaptile?langzh_cn&size1&style7&x{x}&y{y}&z{z} 双击即可呈现 收集到的一些图源&#xff0c;仅供参考&#xff0c;其中一…

Java核心知识点整理大全11-笔记

Java核心知识点整理大全-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全4-笔记-CSDN博客 Java核心知识点整理大全5-笔记-CSDN博客 Java核心知识点整理大全6…