不解决不重要的 Promise 是一种不好的做法吗?

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

我正在尝试思考一种实践,我现在注意到在不同的代码库中,函数未解决补充异步函数调用。

我认为这样做是为了潜在地节省性能,因为等待承诺得到解决可能会增加额外的开销,而除了保证一切都已完成之外,不会获得真正的好处(如果承诺对函数的结果不重要)。完成了。

我见过的一个常见示例是缓存:

async function someFunction() {

  const result = await doSomething();
  
  cacheResult(result);
  
  return result;
}

async function cacheResult(someValue) {
  // ... cache logic returning a promise
}

我是否正确地假设在上面的示例中,存在

someFunction
在解决
cacheResult
之前完成的情况?如果是这样,那么我假设
cacheResult
将“在稍后的任意时间”解决?

如果我将

someFunction
包裹在
try/catch
块中怎么办:

try {
  await someFunction();
} catch (error) {
  // ... error handling
}

但是

cacheResult
承诺在一段时间后变成了拒绝。这是否会导致未处理的承诺拒绝并终止进程,即使我将其包围在
try/catch
中?

假设对

cacheResult
进行了适当的错误处理,并且它是一个需要花费大量时间的复杂函数,那么让其自行解决并继续处理而不损失性能是否是一种有效的做法?

javascript node.js async-await promise
2个回答
1
投票

我是否正确地假设在上面的示例中,存在 someFunction 在 cacheResult 解析之前完成的情况?

事实上,这是有保证的。

cacheResult
将立即执行,但尚未解析(除非您不执行 any 异步工作并立即返回)。举例说明:

async function doSomething() {
  return 1;
}

async function someFunction() {

  const result = await doSomething();

  cacheResult(result).then(console.log);

  return result;
}

async function cacheResult(someValue) {
  await null; // have this function take at least one tick.
  return 2;
}

someFunction().then(console.log);
// Logs 1, then 2.

如果是这样,那么我认为cacheResult将“在稍后的任意时间”解析?

是的。

事实上,如果

cacheResult
这样实现的话,根本就解决不了:

function cacheResult(someValue) {
  return new Promise((resolve, reject) => {
    // don't do anything with resolve() or reject()
  });
}

但是在一段时间后,cacheResult 承诺会变成拒绝。即使我将其包围在 try/catch 中,这是否会导致未处理的承诺拒绝并终止进程?

是的。这不会捕获

cacheResult
调用中的异常,并会导致未处理的承诺拒绝:

// Make it throw an error:
async function cacheResult(someValue) {
  await null; // have this function take at least one tick.
  throw new Error('Custom error');
}
// Run Node with warnings enabled:
// node --unhandled-rejections=warn example.js
// UnhandledPromiseRejectionWarning: Unhandled promise rejection. 
// This error originated either by throwing inside of an async 
// function without a catch block, or by rejecting a promise which 
// was not handled with .catch(). (...)

事实上,错误消息向您指出了这个答案。

假设对 cacheResult 进行了适当的错误处理,并且它是一个需要大量时间的复杂函数,那么让其自行解决并继续处理而不损失性能是否是一种有效的做法?

是的,完全没问题:

async function someFunction() {

  const result = await doSomething();

  cacheResult(result).catch(err => console.warn("cacheResult:", err));

  return result;
}

您可能需要考虑添加一种机制,确保缓慢的

cacheResult()
调用不会覆盖刚刚完成的较新的
cacheResult()
(例如保存时间戳或修订号)。


0
投票

是的,永远悬而未决的承诺是不好的做法,因为它们会占用资源。

但是在你的例子中没有(明显的)未解决的承诺。仅仅因为您没有

await
承诺,并不意味着它不会解决(假设
cacheResult
最终完成)。

但是,是的,即使您将

await someFunction()
包装到
try {...} catch {...}
块中,您的代码也会抛出未处理的承诺拒绝,因为您丢失了
cacheResult
返回的承诺的上下文。即,在
someFunction()
返回的 Promise 解决或拒绝之前,
cacheResult
中的异步代码将早已完成(并且它返回的 Promise 也将长期被解析(或可能被拒绝))。

所以,如果你不关心

cacheResults
是否成功,要么通过这样做来使其在任何情况下都不会抛出

async function cacheResult(foo) {
  try {
    //some async code
  } catch {
  }
}

或者在调用时添加拒绝处理程序

async function someFunction() {
   //some code
   cacheResult(...).catch(e => {})
   //some more code
}

这两个变体都会让

cacheResult
稍后完成,并在失败时直接忽略错误。当然,您可以(并且可能应该)在这两种变体中添加一些日志记录......

但要注意一件事:例如,nodejs 可能不会等待待处理的 Promise 并终止,因此,如果没有其他任何事情可以让您的进程保持活动状态,您的

cacheResult
函数可能会随时终止...

© www.soinside.com 2019 - 2024. All rights reserved.