如何不忘记在 Javascript 中到处使用 await?
Posted
技术标签:
【中文标题】如何不忘记在 Javascript 中到处使用 await?【英文标题】:How not to forget using await everywhere in Javascript? 【发布时间】:2018-01-08 22:14:27 【问题描述】:尝试写一个小chrome扩展,依赖chrome.*
接口的大量回调查询函数,我很快就进入了promises和async/await,因为我需要保证某些操作的顺序,同时尝试避免callback hell。
但是,一旦我将 async/await 引入到某些函数中,每个使用它们的函数也必须转换为 async function
以便能够 await
返回值。最终,甚至一些全局常量也变成了 Promise,例如
const DEBUG = new Promise(function(resolve)
chrome.management.getSelf(resolve);
).then(function(self)
return self.installType == 'development';
);
但是,现在我需要到处写 await
并引入奇怪的错误,例如 if(DEBUG)...
总是被执行变得太容易了。
虽然看起来 possible to identify the errors using ESLINT,但到处写 await
似乎是不必要的麻烦,因此我想知道 Javascript 是否有一些我缺少的更好的构造?
(主观上我当前对 await/async 的使用似乎倒退了;除非明确等待,否则 Promise 会保持原样,但我似乎更希望在 async 函数中默认等待 Promise 并仅在明确请求时才保留为裸 Promise .)
【问题讨论】:
不确定这是否是您要查找的内容,但您始终可以链接您的Promise.prototype.then()
语句,即 new Promise(...).then(...).then(...)
关于全局常量,只需将整个模块包装在一个函数中,该函数由 await
s 和 Promise.all
与所有异步加载的常量一起执行,然后才执行您的主脚本。
"一旦我介绍了 async/await" - 我很确定您之前遇到过完全相同的问题,因为您的逻辑一直是异步的。不管你是使用回调、承诺还是带有await
糖的承诺。
@PatrickBarr 这本质上是具有相同问题的不同语法。现在只有这样,而不是const x = await getX(); const y = await x.getY(); dostuff(x,y); ...
,我会写getX().then(x => Promise.all([x, x.getY()])).then(([x,y]) => dostuff(x,y); ...)
,这并不难忘记做,但如果忘记了更难重构。
Great article on how to avoid, that everything up to the top has to be async/await
once you start the habbit。请参阅“陷阱 3”(剧透:您可以将异步函数的结果视为承诺)
【参考方案1】:
由于缺少可以轻松捕获此类错误的类型系统(您考虑过 Typescript 还是 Flow?),您可以使用 Systems Hungarian Notation 作为变量名。选择像P
、Promise
或$
这样的后缀前缀并将其添加到所有的promise 变量中,类似于通常使用Async
后缀命名的异步函数。然后只做类似的事情
const debug = await debugPromise
您可以快速看到if (debug)
很好,但if (debugPromise)
不是。
一旦我在某些函数中引入了 async/await,每个使用它们的函数也必须转换为 async 函数,以便能够等待返回值。最终,甚至一些全局常量也变成了 Promise
我不会那样做。尝试使尽可能少的函数异步。如果他们本身并没有做本质上异步的事情,而只是依赖于一些 Promise 的结果,那么将这些结果声明为函数的参数。一个简单的例子:
// Bad
async function fetchAndParse(options)
const response = await fetch(options);
// do something
return result;
// usage:
await fetchAndParse(options)
// Good:
function parse(response)
// do something
return result;
// usage:
await fetch(options).then(parse) // or
parse(await fetch(options))
同样的模式也可以应用于全局变量——要么让它们成为每个函数的显式参数,要么让它们成为包含所有其他函数作为闭包的模块函数的参数。然后await
全局承诺只在模块中一次,在声明或执行其他任何内容之前,然后使用纯结果值。
// Bad:
async function log(line)
if (await debugPromise)
console.log(line);
async function parse(response)
await log("parsing")
// do something
return result;
… await parse(…) …
// Good:
(async function mymodule()
const debug = await debugPromise;
function log(line)
if (debug)
console.log(line);
function parse(response)
log("parsing")
// do something
return result;
… parse(…) …
());
【讨论】:
关于命名,Async
后缀很常见;这是.NET convention,也是adopted by Bluebird。
@StephenCleary 谢谢,我已经在想是否应该澄清一下,对于 promise 变量和异步函数不会使用 same 后缀。
谢谢伯吉。解释得很清楚。这很好。还有两种情况 - 1)在异步/等待承诺使用期间出现错误。 2) 拒绝使用 async/await for promises 时的使用问题。您如何遵循处理异步/等待中的错误的良好做法?其次,在执行 async/await for promises 时有什么好的方法来处理拒绝代码?任何参考或代码示例都可以
@Gary 就像在其他地方一样使用try
/catch
。或some variations,具体取决于您的具体需求。
@FrankNocke“可以被视为”几乎没有意义。它们是承诺:-)以上是关于如何不忘记在 Javascript 中到处使用 await?的主要内容,如果未能解决你的问题,请参考以下文章
javascript介绍及如何在html中使用js与jQuery