短路 Promise.allSerial(),没有异步等待

A short-circuiting Promise.allSerial(), without async-await

我需要执行一系列异步任务,以便执行一个任务 当且仅当 该系列中紧接其前的任务成功执行。我还需要收集这些任务的部分或全部结果集。所以,如果第三个任务失败了,我需要前两个任务的结果。

现在,我可以非常轻松优雅地使用 async-await 风格的 promises 来实现上述内容,甚至可以让我满意地工作,但是 不是以下非async-await版本:

  // an async task that fails on an input of 200
  function task(timeout) {
    return new Promise((resolve, reject) => {
      console.log(`Starting a ${timeout}ms task... `);
      if (timeout == 200) {
        console.log(`Starting a ${timeout}ms task... FAILED. timeout = ${timeout}`);
        reject(`task(${timeout}): FAILED`);
      } else {
        setTimeout(() => {
          let result = timeout * 10;
          output.push(result);
          console.log(`Starting a ${timeout}ms task... done. Result: ${result}`);
          resolve();
        }, timeout);
      }
    });
  }

  let input = [400, 300, 200, 100, 50];
  let output = [];

  let p = Promise.resolve(); // initialize
  for (let i = 0; i < input.length; ++i) {
    let timeout = input[i];
    p = p
      .then(() => {
        return task(timeout);
      })
      .catch((e) => {
        throw e;
      });
  }

  p = p.finally(() => {
    console.log(`Results so far: ${output.join(", ")}`);
  });

输出

Starting a 400ms task... 
Starting a 400ms task... done. Result: 4000
Starting a 300ms task... 
Starting a 300ms task... done. Result: 3000
Starting a 200ms task... 
Starting a 200ms task... FAILED. timeout = 200
Results so far: 4000, 3000
(node:1882) UnhandledPromiseRejectionWarning: task(200): FAILED
(node:1882) 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(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 3)
(node:1882) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

问题:

我正在处理 .catch() 中被拒绝的承诺,但我收到了上述警告。为什么?

平台:

节点:12.8.3

OS: Mac OSX 10.14.4

.catch((e) => {
  throw e;
});

那不是处理错误...那是抛出错误!!

处理 p 上的错误,因为您真的不想处理 task 中的错误,因为这意味着被拒绝的任务之后的任务实际上 运行。显然,您不希望这样!

// an async task that fails on an input of 200
function task(timeout) {
  return new Promise((resolve, reject) => {
    console.log(`Starting a ${timeout}ms task... `);
    if (timeout == 200) {
      console.log(`Starting a ${timeout}ms task... FAILED. timeout = ${timeout}`);
      reject(`task(${timeout}): FAILED`);
    } else {
      setTimeout(() => {
        let result = timeout * 10;
        output.push(result);
        console.log(`Starting a ${timeout}ms task... done. Result: ${result}`);
        resolve();
      }, timeout);
    }
  });
}

let input = [400, 300, 200, 100, 50];
let output = [];

let p = Promise.resolve(); // initialize
for (let i = 0; i < input.length; ++i) {
  let timeout = input[i];
  p = p
    .then(() => {
      return task(timeout);
    });
}

p = p
  .catch(() => {}) // error handled!
  .finally(() => {
    console.log(`Results so far: ${output.join(", ")}`);
  });

作为替代方案...

  • task中删除output.push并将其移动到执行任务的地方
  • 简化循环

你可以做到

function task(timeout) {
  return new Promise((resolve, reject) => {
    console.log(`Starting a ${timeout}ms task... `);
    if (timeout == 200) {
      console.log(`Starting a ${timeout}ms task... FAILED. timeout = ${timeout}`);
      reject(`task(${timeout}): FAILED`);
    } else {
      setTimeout(() => {
        let result = timeout * 10;
        console.log(`Starting a ${timeout}ms task... done. Result: ${result}`);
        resolve(result); // resolve the result
      }, timeout);
    }
  });
}
let input = [400, 300, 200, 100, 50];
let output = [];
               // adding the result to output here vvvvvvvvvvvvvvvvvvvvvvvvv
let p = input.reduce((p, t)=>p.then(() => task(t)).then(r => output.push(r)), Promise.resolve());
p
.catch((e) => {})
.finally(() => console.log(`Results so far: ${output.join(", ")}`))