我知道
async await
是镇上的新 Promise
,它是一种编写异步代码的新方法,我也知道
我们不必编写
.then
,创建一个匿名函数来处理响应
Async/await
终于可以使用相同的构造来处理同步和异步错误,很好的旧式 try/catch
从
promise
链返回的错误堆栈没有给出错误发生位置的任何线索。但是,async/await 的错误堆栈指向包含错误的函数
等等...
但是 在这里我做了一个简单的基准测试https://repl.it/repls/FormalAbandonedChimpanzee
在基准测试中,我运行了 2 个循环 100 万次。 在第一个循环中,我调用一个返回 1 的函数 在另一个函数中,我调用一个抛出 1 作为异常的函数。
调用返回 1 的函数的第一个循环所花费的时间几乎是抛出 1 作为错误的函数的一半。
这表明
throw
所花费的时间几乎是 return
所花费时间的两倍
node v7.4 linux/amd64
return takes 1.233seconds
1000000
throw takes 2.128seconds
1000000
下面的基准代码
function f1() {
return 1;
}
function f2() {
throw 1;
}
function parseHrtimeToSeconds(hrtime) {
var seconds = (hrtime[0] + (hrtime[1] / 1e9)).toFixed(3);
return seconds;
}
var sum = 0;
var start = 0;
var i = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
var seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('return takes ' + seconds + 'seconds');
console.log(sum);
sum = 0;
start = process.hrtime();
for (i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
seconds = parseHrtimeToSeconds(process.hrtime(start));
console.log('throw takes ' + seconds + 'seconds');
console.log(sum);
您的基准与
async/await
与原始承诺之间的性能无关。我所看到的是抛出错误需要更长的时间来计算。这是预料之中的。
回到主要问题,应该使用
async/await
而不是 .then
与原始承诺?
请记住,
async/await
只是原始承诺的语法糖,因此不会对整体性能产生太大影响。然而,它确实使您的代码更加线性,从而消除了开发人员的大量认知开销。
结论是使用你喜欢的。 Promise 可以进行 polyfill,但新语法不能,因此在决定使用哪种样式时,您可能需要记住这一点。
一些误解:
从承诺链返回的错误堆栈没有给出错误发生位置的线索
事实并非如此。快速检查:
function error() {
return new Promise(function(res, rej) {
res(undefined()); // uh oh
});
}
error().then(console.log, e => console.log("Uh oh!", e.stack));
显示整个错误堆栈,包括位置。
大多数情况下,答案是“视情况而定”。
在谈论性能之前,更重要的方面是代码的可维护性,以及
async
/await
vs raw Promise
的局限性。
async
/await
是顺序执行异步代码的好方法,而 Promise
使您能够同时运行异步代码。
async function foo() {
const a = await backend.doSomething()
const b = await backend.doAnotherThing()
return a + b
}
在上面的代码中,直到
backend.doAnotherThing()
返回后才会执行backend.doSomething()
。另一方面:
function foo() {
Promise.all([backend.doSomething(), backend.doAnotherThing()])
.then(([a, b]) => {
return a + b
})
}
将执行这两个调用,并等待两个调用完成。
正如您提到的
async
/await
的好处,我个人广泛使用它。除上述情况外。
如果您需要性能,并且对您来说,
async
/await
与Promise
之间的性能差异比async
/await
相对于Promise
的可读性优势更重要,无论如何,请继续。
只要是有意识的选择,就应该没问题。
更新:正如 Derek 提到的我会功夫
您可以通过
async
/await
获得并行执行:
async function foo() {
const p1 = backend.doSomething()
const p2 = backend.doAnotherThing()
return await p1 + await p2
}
以工会的答案为基础:
您可以使用
Promise.all
实现与
async/await
相同的行为
function foo() {
Promise.all([backend.doSomething(), backend.doAnotherThing()])
.then(([a, b]) => {
return a + b
})
}
async function foo() {
const a = backend.doSomething()
const b = backend.doAnotherThing()
return await a + await b
}
后端任务同时发生,我们等待两者完成后再返回。另请参阅我写的 MDN 示例
基于此,我不确定直接使用 Promises 是否比
async/await
有任何性能优势。
我想从相反的方向回答这个问题,即何时使用 Promise 而不是 async/await。除了这些情况之外,我认为使用 async/await 会更合适。
所以除了Promise并发我会使用async/await。 Promise 并发有 four 静态方法。
其他答案都提到了
Promise.all()
但是如果你需要全部承诺解决你可以选择Promise.allSettled()
对于
Promise.any()
我有它的用例,当任何承诺得到履行时是否可以脱离await Promise.all(Chrome 80)
Promise.any()
和Promise.race()
之间的区别是,当所有promise都拒绝时,Promise.any()
会拒绝,而当任何一个promise拒绝时,Promise.any()
会拒绝。
Promise.race()
的一个用例是实现超时,因为 async/await 没有内置的超时支持。
我将直接从 https://www.freecodecamp.org/news/how-to-use-promises-in-javascript/ 复制。一切功劳归作者所有。
async function fetchDataWithTimeout() {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('Timeout exceeded')), 5000);
});
try {
const response = await Promise.race([fetch('https://api.example.com/data'), timeoutPromise]);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}