【问题标题】:What is the best way to wrap synchronous functions in to a promise将同步函数包装到 Promise 中的最佳方法是什么
【发布时间】:2016-08-18 00:27:07
【问题描述】:

假设我有一个像path.join() 这样的同步函数。我想将它包装到 Promise 中,因为我希望在 catch() 块中处理异常。 如果我像下面这样包装它,我不会在Promise.catch() 块中得到异常。所以我必须使用if 来检查返回值是否是错误,然后调用resolvereject 函数。还有其他解决方案吗?

var joinPaths = function(path1,path2) {
  return new promise(function (resolve, reject) {
    resolve(path.join(path1, path2));
  });
};

【问题讨论】:

  • 为什么要将同步函数包装到 Promise 中?
  • 当需要用硬编码值替换一些异步调用时,单元测试是一种常见的情况
  • 将同步函数包装到 Promise 中的最好方法是不这样做。
  • @Srinesh:然后使用Promise.resolve().then(()=> path.join(path1, path2)).…
  • @RodrigoJuarez 如果我在 then() 中使用 path.join,那么我可以在 catch 块中管理所有异常

标签: javascript node.js promise


【解决方案1】:

目前还不清楚为什么要将同步操作包装在 Promise 中,因为这只会使其更难使用,而同步操作已经可以在 Promise 链中使用。

我认为从同步的东西中做出承诺的唯一两个地方是启动一个承诺链,其中后续操作将是异步的,或者当您进行分支时,分支的一个结果是异步承诺,另一个是是同步的。然后,在这种情况下,您只想在两种情况下都返回一个 Promise,以便调用者无论采用哪个分支都具有一致的异步接口。或者,这也可能发生在公共 API 的不同实现中,一个实现是同步的,另一个是异步的。 API 将设计为带有异步接口,而同步实现可能会将自身包装在一个承诺中,以履行通用 API 的异步契约。

除此之外,您通常不应将同步的事物设为异步,因为这只会使使用它们变得不必要地复杂化。

我所知道的将其变成承诺的最简单方法是:

Promise.resolve(path.join(path1, path2)).then(function(path) {
   // use the result here
});

根据您的 cmets,在 .then() 处理程序中,异常已经被 Promise 基础设施捕获并变成被拒绝的 Promise。所以,如果你有这个:

someAsyncOp().then(function(value) {
   // some other stuff
   // something that causes an exception
   throw new Error("timeout");
}).catch(function(err){
   console.log(err);   // will show timeout
});

然后,该异常已经映射为您的承诺拒绝。当然,如果您想在 .then() 处理程序中处理异常(而不是将承诺变成拒绝),那么您可以在同步操作周围使用传统的 try/catch 来捕获本地异常(与任何其他同步代码)。但是,如果您希望在 .then() 处理程序中出现异常时拒绝 promise,那么这一切都会自动为您完成(promise 的一个非常好的特性)。

【讨论】:

  • 如果我在 Promise 链中使用 path.join 并且我想处理 promise.catch() 块中的异常,如果不将其包装到 Promise 中,我该如何做到这一点?
  • @Srinesh - 与往常一样,如果您将实际代码和实际问题放入您的问题中,我们可以为您提供更好的帮助。我不完全按照您要执行的操作。承诺链中的 .then() 处理程序已经包装在 try/catch 中,.then() 处理程序中抛出的任何异常都将自动拒绝承诺链。您无需执行任何操作即可在 .then() 处理程序中获取该功能。您也可以自己使用 try/catch 来捕获同步异常并在本地进行处理。
  • 您可能希望在 Promise 中包装同步函数的一个原因是,如果您试图遵守合同,即if (needsUpdating) { return object.asyncUpdate(); } else { return object }; 如果一个路径返回一个 Promise,那么另一个路径也应该返回一个 Promise路径,即使它没有运行任何异步代码。
  • 我认为这与@DanielT 相同。提到过,但我认为它对于创建允许您交换不同供应商实现的 API 可能很有用。我目前正在制作一个应用程序的演示版本,其中真正的应用程序使用 Firestore,但我将在演示版本中使用 localStorage。即使 localStorage 是同步的,我还是想用承诺来包装以使事情变得透明。这听起来像个坏主意吗?
  • @ckot - 是的,有时是异步的 API 必须始终提供异步 API,即使在某些情况下实现不是异步的。这将是在 Promise 中包装一些同步代码的有效/有用的理由。
【解决方案2】:

不确定这是否是最好的方法,但它确实有效。我来 StackOverflow 看看有没有更好的方法。

new Promise((resolve, reject) => {
    try {
        resolve(path.join());
    } catch (err) {
        reject(err);
    }
})

【讨论】:

    【解决方案3】:

    非常快速的方法是在函数前面加上async 关键字。任何异步函数都会返回一个 Promise

    const sum = async (a, b) => a + b;
    
    sum(1, 2).then(value => console.log(value))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-08
      • 1970-01-01
      • 1970-01-01
      • 2011-08-08
      • 2020-09-27
      相关资源
      最近更新 更多