Promise的执行顺序

问题

给出一下代码的输出结果:

console.log("script start");
let promise1 = new Promise(function (resolve) {
  console.log("promise1");
  resolve();
  console.log("promise1 end");
}).then(function () {
  console.log("promise2");
});
setTimeout(function () {
  console.log("settimeout");
});
console.log("script end");


// 输出顺序: script start
// promise1
// promise1 end
// script end
// promise2
// settimeout

解答

promise里面是同步,promise.then()是微任务,setTimeout是宏任务。
异步任务大致分为:微任务(micro task,如:promise.then、MutaionObserver等)和宏任务(macro task,如:setTimeout、setInterval、I/O等

在 JavaScript 中,事件循环(event loop)的执行顺序是这样的:

  1. 首先,执行当前主线程的所有同步任务,直到主线程空闲。
  2. 接着,执行微任务队列中的所有微任务(Microtasks)。微任务包括 Promise 的回调函数、MutationObserver 的回调函数等。
  3. 然后,从宏任务队列中选择一个任务执行。常见的宏任务包括 setTimeout、setInterval、I/O 操作等。
  4. 微任务队列为空时,重复步骤 1-3。
    因此,微任务是在每个宏任务执行完毕之后立即执行的。异步宏任务会在主线程任务执行完毕后,以及微任务执行完毕后再次选择执行。

这个执行顺序涉及到 JavaScript 中事件循环的机制。

首先,让我们一步步分析代码的执行过程:

  1. 执行 console.log("script start"),打印出 “script start”。
  2. 创建了一个新的 Promise 实例 promise1,并且立即执行了传入的执行器函数。这个执行器函数是同步执行的,所以会立即执行。在执行器函数内部:
    • 执行 console.log("promise1"),打印出 “promise1”。
    • 调用 resolve(),这会将 Promise 的状态从 pending 变为 resolved,并且触发后续的 then 方法。
    • 执行 console.log("promise1 end"),打印出 “promise1 end”。
  3. 继续执行同步代码,执行 console.log("script end"),打印出 “script end”。
  4. 执行微任务队列中的任务,即执行 then 方法中的回调函数。此时打印出 “promise2”。
  5. 执行宏任务队列中的任务,即 setTimeout 中的回调函数。此时打印出 “settimeout”。

所以,整个执行顺序是:

  • “script start”
  • “promise1”
  • “promise1 end”
  • “script end”
  • “promise2”
  • “settimeout”

这个执行顺序的关键在于理解 Promise 中执行器函数的同步执行以及事件循环中微任务和宏任务的执行顺序。

再来一题

 // 1——>2——>3——>5——>4——>setTimeout
    console.log(111);
    setTimeout(() => {
      console.log("setTimeout");
    });
    console.log(222);
    let p = new Promise((resolve, reject) => {
      resolve("aa");
      console.log(333);
    });
    console.log(p);
    p.then(
      (res) => {
        console.log(444, res);
      },
      (err) => {
        console.log(err);
      }
    );
    console.log(555);

在这里插入图片描述

规律

Promise 本身是同步的立即执行函数, 当在 executor 中执行 resolve 或者 reject 的时候, 此时是异步操作, 会先执行 then/catch 等,当主栈完成后,才会去调用 resolve/reject 中存放的方法执行,打印 p 的时候,是打印的返回结果,一个 Promise 实例。 解释一下这段话:

这段话描述了 Promise 的执行过程中的一些关键概念。让我来解释一下:

  1. Promise 是同步的立即执行函数: 当你创建一个 Promise 实例时,传入的执行器函数(executor)会立即执行。这个执行器函数是同步执行的,意味着它会在当前代码块中立即执行,而不会等待后续的事件或异步操作。

  2. resolve 和 reject 是异步操作: 在执行器函数中,调用 resolve 或 reject 方法会改变 Promise 的状态,并触发后续的 then 或 catch 方法。但是,这些方法本身是异步的。也就是说,调用 resolve 或 reject 并不会立即执行 then 或 catch 方法中的回调函数,而是会在当前代码块执行完毕后,通过事件循环机制将它们放入微任务队列中等待执行。

  3. then/catch 等会先执行: 因为 resolve 和 reject 的回调函数是异步执行的,所以在 Promise 的执行过程中,then、catch 等方法会优先执行。这是因为它们是 Promise 的接口,用于注册后续的操作,并且这些操作通常是基于 Promise 的状态变化来执行的。

  4. 打印 p 的时候是打印的返回结果,一个 Promise 实例: 当你创建一个 Promise 实例时,它会立即返回这个 Promise 实例。在这段代码中,let promise1 = new Promise(...) 创建了一个 Promise 实例,并将它赋值给变量 promise1。所以,当你打印 p 时,实际上打印的是这个 Promise 实例。这个 Promise 实例在当前代码块中是同步执行的,因此它会在 Promise 创建的时候就返回,而不会等待后续的 resolve 或 reject 调用。

综上所述,Promise 的执行过程涉及同步和异步操作的交织,而理解事件循环机制对于理解 Promise 的行为至关重要。

什么是executor

Executor 是在创建 Promise 实例时作为参数传递的一个函数,它用于定义 Promise 的行为。这个函数会立即执行,并且接收两个参数:resolve 和 reject,它们是两个由 JavaScript 引擎提供的函数,用于改变 Promise 的状态。

下面是一个简单的例子:

let promise = new Promise(function(resolve, reject) {
  // 这里是执行器函数
  // 在这个函数内部,你可以编写异步或同步的代码
  // 你可以根据具体的情况调用 resolve 或 reject
  setTimeout(function() {
    resolve("Promise resolved!"); // 将 Promise 状态设置为 resolved
  }, 1000);
});

promise.then(function(result) {
  console.log(result); // 打印出 "Promise resolved!"
});

在这个例子中,Promise 的执行器函数接收两个参数 resolve 和 reject,它们是由 JavaScript 引擎提供的函数。在执行器函数中,我们设置了一个定时器,1 秒后调用 resolve 方法。这会将 Promise 的状态从 pending 变为 resolved,并且将 “Promise resolved!” 作为结果传递给后续的 then 方法。

总之,执行器函数(executor)是在创建 Promise 实例时传入的一个函数,用于定义 Promise 的行为以及决定 Promise 的最终状态。

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JavaScript 中,Promise执行顺序可以分为以下几个步骤: 1. 创建 Promise 对象:使用 `new Promise()` 构造函数创建一个 Promise 对象,并传入一个执行器函数作为参数。 2. 执行器函数:执行器函数会立即执行,并接收两个参数,分别是 `resolve` 和 `reject`。在执行器函数中,你可以编写异步操作的代码逻辑。 3. 异步操作:在执行器函数中,你可以编写异步操作的代码,如异步请求、文件读取等。当异步操作完成时,可以调用 `resolve` 方法将 Promise 置为成功状态,或调用 `reject` 方法将 Promise 置为失败状态。 4. 状态改变:当调用 `resolve` 或 `reject` 方法后,Promise 的状态将发生改变。如果调用了 `resolve`,Promise 的状态将变为成功(fulfilled);如果调用了 `reject`,Promise 的状态将变为失败(rejected)。 5. 注册回调函数:可以使用 `then()` 方法来注册成功状态的回调函数,或使用 `catch()` 方法来注册失败状态的回调函数。这些回调函数将在 Promise 的状态发生改变后被调用。 6. 链式调用:通过链式调用 `then()` 方法,可以将多个回调函数串联起来,并且每个回调函数可以返回一个新的 Promise 对象,实现链式异步操作。 需要注意的是,Promise 是非阻塞的,即在执行异步操作时,JavaScript 主线程可以继续执行其他任务,而不会等待 Promise 的结果。当 Promise 的状态改变后,相关的回调函数才会被调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值