使用 Promise 实例封装之后的同步代码就变成异步了吗?

91 阅读2分钟

使用 Promise 实例封装之后的同步代码就变成异步了吗?

在 JavaScript 开发中,Promise 是一个强大的工具,用于处理异步操作。然而,有些人可能会误以为,只要将代码封装在 Promise 中,原本的同步代码就会变成异步代码。本文将通过具体的例子来解答这个问题。

Promise 的基本概念

Promise 是一个代表异步操作最终完成或失败的对象,并带有处理成功或失败结果的方法。它有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。

示例代码分析

我们来看以下两个函数示例:

const a = arg => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(arg)
      resolve(arg)
    }, 1000)
  })
}

const b = arg => {
  return new Promise(resolve => {
    let now = Date.now()
    while (Date.now() - now < 1000) {
      // do nothing
    }
    console.log(arg)
    resolve(arg)
  })
}
  • 函数 a 使用 setTimeout 来模拟一个异步操作,延迟 1000 毫秒后执行。
  • 函数 b 使用一个 while 循环来阻塞主线程大约 1000 毫秒。

接下来,我们在一个异步自执行函数中调用这些函数:

;(async () => {
  // a 执行
  console.time('time a')
  await Promise.all([a(1), a(2)])
  console.timeEnd('time a') // 预期输出: time a: 接近 1000ms

  // b 执行
  console.time('time b')
  await Promise.all([b(1), b(2)])
  console.timeEnd('time b') // 预期输出: time b: 接近 2000ms
})()

执行行为分析

  1. a 函数的执行

    • a(1)a(2) 立即返回 Promise,并在 1000 毫秒后完成。
    • Promise.all 等待所有 Promise 完成,总时间接近 1000 毫秒。
    • setTimeout 是非阻塞的,不会阻塞主线程。
  2. b 函数的执行

    • b(1)b(2) 立即返回 Promise,但内部有同步阻塞的 while 循环。
    • Promise.all 依次执行 b(1)b(2),每个阻塞约 1000 毫秒。
    • 总时间约为两个阻塞时间的总和,即 2000 毫秒。

结论

  • Promise 本身不改变代码的同步或异步性质。
  • a 函数中的异步操作不会阻塞主线程。
  • b 函数中的同步操作仍然会阻塞主线程。

Promise 是一个强大的工具,用于处理异步操作的结果,但它本身并不改变代码的同步或异步性质。理解这一点对于编写高效和响应迅速的 JavaScript 应用至关重要。希望本文能帮助你更好地理解 Promise 和同步/异步代码之间的关系。