使用 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
})()
执行行为分析
-
a
函数的执行:a(1)
和a(2)
立即返回Promise
,并在 1000 毫秒后完成。Promise.all
等待所有Promise
完成,总时间接近 1000 毫秒。setTimeout
是非阻塞的,不会阻塞主线程。
-
b
函数的执行:b(1)
和b(2)
立即返回Promise
,但内部有同步阻塞的while
循环。Promise.all
依次执行b(1)
和b(2)
,每个阻塞约 1000 毫秒。- 总时间约为两个阻塞时间的总和,即 2000 毫秒。
结论
Promise
本身不改变代码的同步或异步性质。a
函数中的异步操作不会阻塞主线程。b
函数中的同步操作仍然会阻塞主线程。
Promise
是一个强大的工具,用于处理异步操作的结果,但它本身并不改变代码的同步或异步性质。理解这一点对于编写高效和响应迅速的 JavaScript 应用至关重要。希望本文能帮助你更好地理解 Promise
和同步/异步代码之间的关系。