我们应该在 Javascript 中选择 async wait 而不是 Promise

问题描述 投票:0回答:4

我知道

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);
javascript node.js asynchronous async-await v8
4个回答
12
投票

您的基准与

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));

显示整个错误堆栈,包括位置。


8
投票

大多数情况下,答案是“视情况而定”。

在谈论性能之前,更重要的方面是代码的可维护性,以及

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
}

1
投票

工会的答案为基础

您可以使用

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
有任何性能优势。


0
投票

我想从相反的方向回答这个问题,即何时使用 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);
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.