【问题标题】:Break a Promise chain inside for-loop在 for 循环中打破 Promise 链
【发布时间】:2019-02-24 20:47:24
【问题描述】:

我正在开发一个受此答案启发的承诺链: https://stackoverflow.com/a/44955506/7485805

我想打破这个 for 循环,以便正确处理链的拒绝。我只是想我不能在链的.catch 方法中使用break

如果有帮助,这是我的代码:

function pro (arr) {
  let chain = Promise.resolve();
  const self = {req: {}, res: {}};
  const length = arr.length;

  return new Promise((resolve, reject) => {
    for(let i=0; i<length; i++){
      chain = chain
          .then(() => arr[i].call(self) )
          .then(() => {
            if(i === (length - 1) )
              resolve();
          })
          .catch(e => {
            reject(e);
          })
    }
  })
  .then(() => {
    return self
  })
  .catch(e => {
    throw new Error (e);
  })

}

const x = function () {
  const self = this;
  return new Promise(resolve => {
    self.req = {key: "value"}
    resolve();
  })  
}

const y =  function () {
  const self = this;
  return new Promise((resolve, reject) => {
    console.log(self);
    reject();
  })
}

const z = function () {
  const self = this;
  return new Promise((resolve, reject) => {
    console.log('failed');
  })
}



pro([x, y, z])
.then((self) => {
  console.log('final',self);
})
.catch(e => {
  console.log('error', e);
})

x, y, z 是函数pro 中链接在一起的三个函数 而x 解析成功,y 被执行但被拒绝。

我想停止 z 的执行,因为继续执行毫无意义,并且可能会在实际代码中产生错误。

另外,如果有人可以为这段代码推荐一个更好的版本:

.then(() => {
  if(i === (length - 1) )
    resolve();
})

注意:我不能使用await,因为此代码将在服务器端执行,使用await 可能会阻止其他传入请求。

【问题讨论】:

标签: javascript for-loop es6-promise


【解决方案1】:

使用async/await 语法要容易得多:

async function pro(arr) {
    const self = {req: {}, res: {}};
    for(const f of arr) await f.call(self);
    return self;
}

async function pro(arr) {
    const self = {req: {}, res: {}};
    for(const f of arr) await f.call(self);
    return self;
}

const x = function () {
  const self = this;
  return new Promise(resolve => {
    self.req = {key: "value"}
    resolve();
  })  
}

const y =  function () {
  const self = this;
  return new Promise((resolve, reject) => {
    console.log(self);
    reject("y failed");
  })
}

const z = function () {
  const self = this;
  return new Promise((resolve, reject) => {
  	console.log('failed');
  })
}

pro([x, y, z]).then((self) => {
  console.log('final',self);
})
.catch(e => {
  console.log('error', e);
});

【讨论】:

  • 您确定使用await 不会阻止节点服务器上的其他传入请求吗?
  • 不,awaitnot blocking。它通过一个承诺立即使函数 return 。当该承诺解决时,它的上下文被恢复。
【解决方案2】:

一些事情:当你在 for 循环中构造你的 Promise 链时,就会发生这样的事情:链被构造。 .then 的执行最早将在下一个事件循环中发生。我将尝试说明:

var promiseChain = functionReturningPromise();
for(var i=0;i<3;i++){
  promiseChain = promiseChain.then(x=> {
    return anotherPromiseFunction(x);
  });
}

取决于functionReturningPromise 实际所做的事情,此时可能已经发生了一些事情......或者可能没有。例如,我们可能已经启动了一个fetch,或者可能启动了一个WebWorker.,但是如果我们在第一个Promise 中嵌套了一个setTimeout,那么我们所做的就是将setTimeout 回调放入队列中事件循环的下一个周期。但保证 100%,还没有运行 .then 函数。稍后,在下一个事件循环中。

所以下一个事件循环来了,promise 已经解决了。这意味着下一个.then 将运行。假设它失败了。那时,因为我们链接了 Promise (promiseChain = promiseChain.then),我们立即跳到链中的第一个 .catch(或带有第二个参数的 .then),并且所有介入的 .thens 都被完全跳过而不被执行。或者如果没有catches,那么这个promise链就完成了。无需休息;这就是 Promise 的工作原理。

所以,如果你只是在链的最后添加一个.catch,你就很好了。

关于这个“事件循环”的事情:我真的推荐观看Jake Archibald: In The Loop,来自 JSConf.Asia 2018。

还有关于await...听起来好像对它的工作原理有些困惑。您只能在async 函数中使用await inside,因此您永远无法使用单个await 完全阻止线程执行。它就像链接.thens 一样工作,只是语法糖。所以@trincot 绝对是正确的,你会更喜欢这种语法。

【讨论】:

  • 我真的很喜欢这里的解释。非常感谢。另外,您刚刚清除了我对await 的疑虑,我一定会观看 JSConf 链接。
【解决方案3】:

这是一个替代答案,它只是连续执行承诺,除非承诺被拒绝,然后停止。这不使用 await,但它应该让您大致了解如何在没有它的情况下完成它,但这段代码也写得很快,所以它不是最优化的代码。

const x = function() {
  return new Promise(resolve => {
    resolve('it resolved ma!');
  });
};

const y = function() {
  const self = this;
  return new Promise((resolve, reject) => {
    reject("reject");
  });
};

const z = function() {
  const self = this;
  return new Promise((resolve, reject) => {
    resolve("never gets executed");
  });
};

function runPromises(promises) {
  const results = [];
  let count = 0;
  const executePromise = i => {
    count++;
    return promises[i]()
      .then((response) => {
        results.push(response);
        if (count !== promises.length) {
          executePromise(count);
        }
      })
      .catch((e) => {
        results.push(e);
        console.log("stop right now, thank you very much");
      });
  };
  if (Array.isArray(promises)) {
    executePromise(count);
  }
  return results;
}

const results = runPromises([x, y, z]);
console.log(results);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-04-06
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多