在for循环中打破Promise链

时间:2019-02-24 20:47:24

标签: javascript for-loop es6-promise

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

我想打破此for循环,以正确处理链条的拒绝。我只是发现不能在链的break方法内使用.catch

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

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可能会阻止其他传入请求。

3 个答案:

答案 0 :(得分:2)

使用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);
});

答案 1 :(得分:1)

几件事:当您在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,那么我们所做的就是将{{1在事件循环的下一个循环中回调到队列中。但保证100%,尚未运行setTimeout函数。稍后,在下一个事件循环中。

因此,下一个事件循环到来,并且承诺已经解决。这意味着下一个.then将开始运行。假设失败了。那时,由于我们链接了承诺(.then,因此我们立即跳到了链中的第一个promiseChain = promiseChain.then(或带有第二个参数的.catch),以及所有中间的{{1 }} s被完全跳过而不执行。或者,如果没有.then,那么这个诺言链就完成了。无需休息;这就是Promises的工作方式。

因此,如果您仅在链的末尾添加一个.then,那就太好了。

关于“事件循环”的事情:我真的建议观看来自JSConf.Asia 2018的Jake Archibald: In The Loop

大约catch ...听起来好像有些混乱。您只能在.catch函数的内部{strong}内部使用{strong},因此永远不能只使用一个await就完全阻止线程执行。它的工作就像链接await一样,只是语法糖。因此,@ trincot绝对正确,您将使用该语法更加开心。

答案 2 :(得分:1)

这是一个替代性答案,它只是连续执行诺言,除非诺言被拒绝,然后将其终止。这不使用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);