使用异步/等待与承诺的区别?
Posted
技术标签:
【中文标题】使用异步/等待与承诺的区别?【英文标题】:Difference of using async / await vs promises? 【发布时间】:2019-04-03 01:41:09 【问题描述】:我正在寻找关于在我的 nodeJS 应用程序中使用什么的答案。
我有处理我对 mssql 的通用 dB 访问的代码。这段代码是使用 async
函数编写的,然后我使用 promise 调用该函数并且一切正常。
随着我的应用程序越来越大,代码越来越大,我计划将一些逻辑移动到函数中,然后调用它们。
所以我的问题是:混合使用 async/await 和 Promise 有什么缺点,还是真的没关系?
Async / await 使编写更具可读性的代码变得更容易,因为我必须在返回某些内容之前读取和写入多个数据库,并且我需要其中一些结果。
那么问题是什么是更好的方法? 已设置且无法更改的 dB 层上的异步/等待 逻辑层 async / await 这将允许我在函数调用上进行 async / 和 await ,或者如果我对逻辑使用 promise,那么我在函数调用时会被 promise 卡住。
所以我希望有人能给我更多的见解,如果一个人比另一个人有更多的优势,除了能够编写更清晰的代码。
【问题讨论】:
这篇文章强调了 async/await 相对于 promises 的一些优势...hackernoon.com/… - 但我很想知道使用一种方法是否有任何性能改进... @Alqbal 与 async/await 相比没有性能改进。async/await
仅适用于承诺,因此没有async/await
OR 承诺,只有async/await
AND 承诺。所以,你真的是在问你是只使用简单的承诺还是使用 async/await
的承诺。
我们可以清理一些重要的东西吗? async / await
都是关于承诺的,所以这个问题的措辞是误导性的。 await
语句等待承诺被履行。您真正要问的是使用 await
与 then()
方法。简短的回答是,这主要是品味问题,因为他们做同样的工作。
【参考方案1】:
async/await
和 promises 密切相关。 async
函数返回承诺,await 是等待承诺解决的语法糖。
混合使用 Promise 和 async
函数的唯一缺点可能是代码的可读性和可维护性,但您当然可以将异步函数的返回值用作 Promise,以及将 await
用于返回的常规函数一个承诺。
您是否选择其中一个主要取决于可用性(您的 node.js / 浏览器是否支持async
?)和您的审美偏好,但一个好的经验法则(基于我当时的偏好写作)可能是:
如果需要串行运行异步代码:考虑使用async/await
:
return asyncFunction()
.then(result => f1(result))
.then(result2 => f2(result2));
对
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result2);
如果你需要嵌套的 Promise:使用 async/await
:
return asyncFunction()
.then(result =>
return f1(result)
.then(result2 => f2(result, result2);
)
对
const result = await asyncFunction();
const result2 = await f1(result);
return await f2(result, result2);
如果您需要并行运行:使用 Promise。
return Promise.all(arrayOfIDs.map(id => asyncFn(id)))
建议您可以在表达式中使用await
来等待多个任务,如下所示:*注意,这仍然是从左到右依次等待,如果您不这样做也可以期待错误。否则,由于fail fast behaviour 的Promise.all()
导致行为不同
const [r1, r2, r3] = [await task1, await task2, await task3];
(async function()
function t1(t)
console.time(`task $t`);
console.log(`start task $t`);
return new Promise((resolve, reject) =>
setTimeout(() =>
console.timeEnd(`task $t`);
resolve();
, t);
)
console.log('Create Promises');
const task1 = t1(100);
const task2 = t1(200);
const task3 = t1(10);
console.log('Await for each task');
const [r1, r2, r3] = [await task1, await task2, await task3];
console.log('Done');
())
但与Promise.all
一样,并行promise 需要在出现错误时得到妥善处理。你可以阅读更多关于here的信息。
注意不要将前面的代码与以下代码混淆:
let [r1, r2] = [await t1(100), await t2(200)];
function t1(t)
console.time(`task $t`);
console.log(`start task $t`);
return new Promise((resolve, reject) =>
setTimeout(() =>
console.timeEnd(`task $t`);
resolve();
, t);
)
console.log('Promise');
Promise.all([t1(100), t1(200), t1(10)]).then(async() =>
console.log('Await');
let [r1, r2, r3] = [await t1(100), await t1(200), await t1(10)]
);
使用这两种方法是不等价的。 Read more about the difference.
最后,Promise.all
是一种更简洁的方法,可以更好地扩展到任意数量的任务。
【讨论】:
实际上你可以使用 awaitlet [r1, r2] = [await task1, await task2]
并行运行。看***.com/questions/35612428/…
@Qwerty 感谢您的反馈!我不确定这是否正确。检查我的编辑和链接的答案。那有意义吗?如果我弄错了,请告诉我!
@lucascaro 我有疑问。与使用 then 相比,await 不会使代码阻塞吗?
某种意义上,你可以这么想,await
“暂停”当前函数,直到 promise 被解决,但是由于这个函数是异步的,它不会阻塞任何外部的当前函数。
您的代码没有反映@Qwerty 的建议(如果您点击链接会更清楚)。 task1
和 task2
是 Promise,因此它们已经在并行运行。在使用await
之前,您需要先调用每个t1()
,而不是[await t1(100), await t1(200), await t1(10)]
。一个冗长的方式是let task1 = t1(100); let task2 = t1(200); let task3 = t1(10); let [r1, r2, r3] = [await task1, await task2, await task3];
。但是在 async/await 代码中使用 Promise.all
是有意义的,因为 await
只需要 Promise
: let [r1, r2, r3] = await Promise.all([t1(100), t1(200), t1(10)]);
【参考方案2】:
其实这取决于你的节点版本,但如果你可以使用async/await
,那么你的代码将更具可读性和更易于维护。
当您将函数定义为“异步”时,它会返回本机 Promise
,当您使用 await 调用它时,它会执行 Promise.then。
注意:
将您的 await 调用放在 try/catch
中,因为如果 Promise 失败,它会发出 'catch'
,您可以在 catch 块中处理它。
try
let res1 = await your-async-function(parameters);
let res2 = await your-promise-function(parameters);
await your-async-or-promise-function(parameters);
catch(ex)
// your error handler goes here
// error is caused by any of your called functions which fails its promise
// this methods breaks your call chain
你也可以像这样处理你的'catch':
let result = await your-asyncFunction(parameters).catch((error)=>//your error handler goes here);
提到的这个方法不会产生异常,所以继续执行。
我认为async/await
除了原生 Promise 模块实现之外没有任何性能差异。
我建议使用bluebird
模块而不是node 内置的原生promise。
【讨论】:
【参考方案3】:此时使用 Promises 的唯一原因是使用 Promise.all()
调用多个异步作业,否则通常使用 async/await 或 Observables 会更好。
【讨论】:
您可以使用Promise.all()
和async/await
。 const [p1, p2, p3] = await Promise.all([p1(), p2(), p3()]);
p1,p2,p3 都是该实例中的经典承诺。如果您单独等待它们中的每一个,它们将被同步执行。
它们都同时执行。在调用下一个之前,我们不会等待一个完成。我们只是等待所有人完成Promise.all()
。
没错。但是如果你调用 await p1()、await p2、await p3,它们将是并发的。 p1-p3 必须声明为明确的承诺。
如果这个答案能解释 why 或 如何 使用 async/await 或 Observables 会更好。正如所写的那样,对于尚未熟悉这些主题的人来说,这似乎不是很有帮助。【参考方案4】:
这取决于你擅长什么方法,promise 和 async/await 都很好,但是如果你想写异步代码,使用同步代码结构你应该使用 async/await 方法。就像下面的例子,一个函数返回具有 Promise 或 async/await 风格的用户。 如果我们使用 Promise:
function getFirstUser()
return getUsers().then(function(users)
return users[0].name;
).catch(function(err)
return
name: 'default user'
;
);
如果我们使用 aysnc/await
async function getFirstUser()
try
let users = await getUsers();
return users[0].name;
catch (err)
return
name: 'default user'
;
在 promise 方法中,我们需要一个 thenable 结构来遵循,而在 async/await 方法中,我们使用 'await' 来保持异步函数的执行。
您可以查看此链接以获得更清晰的信息访问https://medium.com/@bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
【讨论】:
【参考方案5】:昨天我做了一个初步决定,从使用 Promises 切换到使用 Async/Await,独立于 nodejs,基于访问 Promise 链中先前值的困难。我确实提出了一个紧凑的解决方案,使用 'bind' 将值保存在 'then' 函数中,但 Async 在允许直接访问局部变量和参数方面似乎更好(而且确实如此)。当然,Async/Await 更明显的优势是消除了令人分心的显式“then”函数,取而代之的是看起来很像普通函数调用的线性表示法。
但是,我今天的阅读发现了 Async/Await 的问题,这使我的决定偏离了方向。我想我会坚持使用 Promises(可能使用宏预处理器使“then”函数看起来更简单),直到 Async/Await 得到修复,几年后。
这是我发现的问题。我很想知道我错了,这些都有简单的解决方案。
需要外部的 try/catch 或最终的 Promise.catch(),否则会丢失错误和异常。
最终的等待需要 Promise.then() 或额外的外部异步函数。
只能使用 for/of 正确完成迭代,不能使用其他迭代器。
Await 一次只能等待一个 Promise,而不是像 Promise 链中的 Promise.all 这样的并行 Promise。
Await 不支持 Promise.race(),如果需要的话。
【讨论】:
1 对于 Promises 和 Async Await 都为真 你能详细说明3吗? 我将 #3 建立在我读到的一些我再也找不到的东西上。事实上,jakearchibald.com/2017/async-iterators-and-generators,从大约 3 年前的 Chrome 开始,表明异步与迭代器一起工作得很好。不知道这篇文章对Chrome等浏览器是否还有效,也没有时间尝试这种异步技术。以上是关于使用异步/等待与承诺的区别?的主要内容,如果未能解决你的问题,请参考以下文章