优雅地处理“等待”Javascript承诺的拒绝
ES2017 async/await的一个好模式是:优雅地处理“等待”Javascript承诺的拒绝,javascript,node.js,asynchronous,async-await,es6-promise,Javascript,Node.js,Asynchronous,Async Await,Es6 Promise,ES2017 async/await的一个好模式是: async function () { try { var result = await some_promised_value() } catch (err) { console.log(`This block would be processed in a reject() callback with promise patterns but this is far more intuiti
async function () {
try {
var result = await some_promised_value()
} catch (err) {
console.log(`This block would be processed in
a reject() callback with promise patterns
but this is far more intuitive`)
return false // or something less obtuse
}
result = do_something_to_result(result)
return result;
}
能够处理这样的错误真的很好。但是如果我想异步获取一个值,我想保护它不被重新分配(例如:数据库会话),但我仍然想使用异步/等待模式(纯粹因为我认为它更直观)
以下操作不起作用,因为常量是块作用域:
async function () {
try {
const result = await get_session()
} catch (err) {
console.log(`This block should catch any
instantiation errors.`)
return false
}
// Can't get at result here because it is block scoped.
}
当然,您可以在try
块中执行函数的其余部分,但这样您就有可能发现错误,而这些错误本应在其他地方漏掉。(例如,我遇到了编写测试的挑战,其中测试失败等错误需要退回到测试套件中,但我想自己处理驱动程序实例化。也许我在这里陷入了某种反模式,因为我没有让这些错误退回到测试套件中。)
很明显,简单的答案是不要在这里使用这种模式。改用承诺和回访。或者使用var
并避免块作用域const
和let
。但我喜欢重新分配保护的好处,以及出于其他考虑的阻止范围
[问题]:这似乎是一个潜在的解决方案,但其可读性不如try/catch
。事实上,try/catch
不会破坏函数作用域,我可以在try/catch
块中使用return
,这在我看来更符合async/await
的精神,为异步代码带来了一种更具过程性的逻辑
理想情况下,您可能希望执行类似于const x=await y()catch(err)
或const x=await y()| | fail
的操作,但我想不出任何类似的流程在语法上是正确的
更新:
根据以下@jmar777的建议,另一个备选方案是:
const x = await y().catch(() => {/*handle errors here*/})
这可能是我在实践中发现的最接近最后两个例子的例子。但它打破了上面示例中阻止下游执行的返回
范围。这是一种很好的同步处理方式
每个解决方案都有其权衡
我已经用
let
在功能块顶部手动提升变量,作为一个有效的解决方案(如jmar777的回答所述),这仍然是一个有趣的问题,可以看到各种方法,因此我现在将这个问题留待讨论。您可能对使用const
的好处有误解。使用const
声明赋值并不会使该值不变,它只是意味着该常量的值不能更改或重新声明:
const声明创建对值的只读引用。这并不意味着它所持有的值是不可变的,只是变量标识符不能被重新分配。例如,如果内容是对象,这意味着对象本身仍然可以更改。()
在您的示例中,最好在try/catch之外手动提升结果
绑定:
async function () {
let result;
try {
result = await get_session()
} catch (err) {
console.log(`This block should catch any
instantiation errors.`)
}
// do whatever else you need with result here...
}
另一种方法是重新构造代码,使您根本不需要依赖try/catch。例如:
async function () {
const result = await get_session().catch(someRejectionHandler);
// do whatever else you need with result here...
}
请注意,下游代码需要优雅地处理
get\u session()
被拒绝,并且result
未基于成功响应初始化的情况。这与您最初的示例没有什么不同,但在扫描代码时可能没有那么明显。几年后回到这个问题,我想到了一个简单得多的答案,回想起来,我不明白为什么我对一个小的try/catch对感兴趣,然后在它之外执行更多的逻辑,而我可以简单地执行所有逻辑并在try语句内部返回
以问题为例,应用该结构将是:
async function () {
try {
const result = await get_session()
// Do what needs to be done and then:
return result
} catch (err) {
console.log(`This block should catch any
instantiation errors.`)
return false
}
}
如果需要从catch块中的try块访问任何内容,请在出现错误时提示它。当我问这个问题时,可能有一个原因我需要离开try的范围,但我看不到一个场景需要回头看。如果使用try/catch/finally并返回finally,则此解决方案将不起作用。但我认为我在野外根本没有遇到过这种模式 异步/等待不是ES7(ES2016)的一部分。它将成为今年的ES2017发布版的一部分。类似的答案希望能对您有所帮助。另请看啊,我想我误解了“不可变”的语义,而不是
const
的作用。我将修改这个问题以消除混淆。另外,在我编写的原始代码中,catch
块中有一个return
,为了防止下游执行,我将更新伪代码以匹配。从catch
内部返回的能力是我喜欢它而不是的原因之一。catch
带有回调,它看起来更符合async/wait
的风格。你的提升解决方案就是我用来让代码工作的解决方案。不过如果还有const就好了。你不需要在尝试中使用return语句吗?@PositiveGuy最有可能。错误处理逻辑不是问题的主题,因此这实际上只是一个try/catch存根,目的是演示手动将结果提升到更高的范围。