【问题标题】:Promise.all rollback successful promises' actions on failurePromise.all 在失败时回滚成功的 Promise 的动作
【发布时间】:2019-10-08 23:03:32
【问题描述】:

我正在使用以下 sn-p 执行多个承诺:

await Promise.all([promise1, promise2, promise3]);

我想要实现的是从Promise.all() 回滚成功的承诺对失败情况的影响。 更具体地说,这意味着上面会做一些文件加密,但如果一个失败,我想删除其他两个(或一个)加密成功的文件,以便拥有一致和干净的文件组。

根据我的阅读,这意味着我需要两个步骤: 1. 捕获每个promise 的错误,这样Promise.all() 就不会抛出错误。 2. 令人费解的部分:有另一个Promise.all() 之类的:

await Promise.all([rollbackPromise1, rollbackPromise2, rollbackPromise3]);

这似乎是棘手的部分:我是否应该独立于失败的承诺执行所有回滚?这意味着我应该对每个错误进行另一个捕获,以便 Promise.all() 等待每次回滚完成。

这是最好的方法吗?我发现它在代码方面效率低下且丑陋。

【问题讨论】:

    标签: javascript node.js error-handling promise async-await


    【解决方案1】:

    您可以按如下方式创建一个简单的解决方案:

    const errorHandlers = []
    function enc1 () {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('str')
        }, 1000)
        errorHandlers.push(() => {
          console.log('handler 1')
        })
      })
    }
    function enc2 () {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('str')
        }, 2000)
        errorHandlers.push(() => {
          console.log('handler 2')
        })
      })
    }
    function enc3 () {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          reject('str')
        }, 3000)
        errorHandlers.push(() => {
          console.log('handler 3')
        })
      })
    }
    
    Promise.all([enc1(), enc2(), enc3()]).then(() => {
      console.log('all resovled')
    }).catch((e) => {
      errorHandlers.forEach(handler => handler(e))
    })

    它可以让您选择处理每个承诺中的“全局”错误。在创建promise all之前,可以重新设置errorHandlers,防止多个errorHandler执行

    【讨论】:

    • 我觉得这个,我没看错,不会等其他promise一旦失败就执行。这意味着 errorHandlers 可能会在相应的 Promise 完成执行之前以不稳定的状态开始执行,无论是否失败。
    • “如果我没记错的话”
    【解决方案2】:

    您可以创建自己的函数来实现函数的异步调用并在需要时执行回滚。

    // Function that'll perform a promise.all and rollback if required
    async function allWithRollback(promises) {
      // using the map we are going to wrap the promise inside of a new one
      return Promise.all(promises.map(([
        func,
        rollbackFunc,
      ], xi) => ((async() => {
        try {
          await func;
    
          console.log('One Function succeed', xi);
        } catch (err) {
          console.log('One Function failed, require rollback', xi);
    
          await rollbackFunc();
        }
      })())));
    }
    
    // Call the custom Promise.all
    allWithRollback([
      [
        // First param is the promise
        okPromise(),
    
        // Second param is the rollback function to execute
        () => {},
      ],
      [okPromise(), () => {}],
      [errPromise(), rollback1],
      [errPromise(), rollback2],
      [okPromise(), () => {}],
    ]);
    
    // ---------
    
    async function okPromise() {
      return true;
    }
    
    async function errPromise() {
      throw new Error('no one read this');
    }
    
    async function rollback1() {
      console.log('Performed the rollback1');
    }
    
    async function rollback2() {
      console.log('Performed the rollback2');
    }

    【讨论】:

    • 如果我理解正确的话,我认为okPromise()-s 也会有rollback-s。说得通。这种逻辑在处理这类问题时是否明智(我用过回滚)?因为回滚函数可能有自己的故障,所以没有办法真正保证执行。做这件事是否有意义,还是应该手动完成,只是作为错误日志注意到。因为后来我有更多的执行可能会失败,并且将回滚包含到所有以前的回滚中似乎有点矫枉过正。
    • 是的,okPromise() 也有他们的回滚。根据问题添加自动回滚可能是适当的。有些问题是“预期的”,你必须处理它们。当它出乎意料时,日志和手动处理似乎是合适的。这一切都与上下文有关。经常出错吗?错误会导致多重要?我的系统可用性必须为 99.99% 吗?如果不回滚,我的数据库是否会损坏?
    猜你喜欢
    • 1970-01-01
    • 2016-01-03
    • 2020-08-06
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 2014-11-07
    • 1970-01-01
    • 2011-10-16
    相关资源
    最近更新 更多