1

我无法正确捕获承诺链中的错误/拒绝。

const p1 = () => {
    return new Promise((resolve, reject) => {
        console.log("P1");
        resolve();
    });
};

const p2 = () => {
    return new Promise((resolve, reject) => {
        console.log("P2");
        reject();
    });
};


const p3 = () => {
    return new Promise((resolve, reject) => {
        console.log("P3");
        resolve();
    });
};

p1().catch(() => {
    console.log("Caught p1");
}).then(p2).catch(() => {
    console.log("Caught p2");
}).then(p3).catch(() => {
    console.log("Caught p3");
}).then(() => {
    console.log("Final then");
});

当 promise 被拒绝时,以下内容.then仍然会被执行。据我了解,当在承诺链中发生错误/拒绝时,其后的.then调用将不再执行。

P1
P2
Caught p2
P3
Final then

拒绝被正确捕获,但为什么在捕获后记录“P3”?

我究竟做错了什么?

为了澄清@evolutionxbox,这是我的预期结果:

Promise.resolve().then(() => {
    console.log("resolve #1");
    return Promise.reject();
}).then(() => {
    console.log("resolve #2");
    return Promise.resolve();
}).then(() => {
    console.log("resolve #3");
    return Promise.resolve();
}).then(() => {
    console.log("Final end");
}).catch(() => {
    console.log("Caught");
});

这段代码的工作方式与它应该的完全一样。而且我看不出我的代码有什么不同,除了我分别声明了这些函数。

无论承诺在哪里被拒绝,上面的代码都会停止。

4

4 回答 4

2

这是您的代码的同步等效项:

const f1 = () => {
  console.log("F1");
};

const f2 = () => {
  console.log("F2");
  throw new Error();
};

const f3 = () => {
  console.log("F3");
};

try {
  f1();
} catch {
  console.log("Caught f1");
}

try {
  f2();
} catch {
  console.log("Caught f2");
}

try {
  f3();
} catch {
  console.log("Caught f3");
}

console.log("Final code");

如您所见,这给出了匹配的结果。希望看到同步代码你不会对为什么感到惊讶。在 atry..catch中,您可以尝试恢复。这个想法是,这catch停止错误传播,您可以希望进一步继续。或者,如果您确实想停止,您仍然必须throw再次明确,例如:

doCode();

try {
    makeCoffee();
} catch(err) {
    if (err instanceof IAmATeapotError) {
        //attempt recovery
        makeTea();
    } else {
        //unrecoverable - log and re-throw
        console.error("Fatal coffee related issue encountered", err);
        throw err;
    }
}

doCode();

这也是目的Promise#catch()- 因此您可以尝试恢复或至少在出现问题时采取行动。这个想法是,在之后.catch()您可能可以继续:

const orderPizza = (topping) => 
  new Promise((resolve, reject) => {
    if (topping === "pepperoni")
      reject(new Error("No pepperoni available"));
    else
      resolve(`${topping} pizza`);
  });

const makeToast = () => "toast";
const eat = food => console.log(`eating some ${food}`);

async function main() {
  await orderPizza("cheese")
    .catch(makeToast)
    .then(eat);
    
  console.log("-----");
  
  await orderPizza("pepperoni")
    .catch(makeToast)
    .then(eat);
}

main();

为了拒绝来自 a 的 Promise 链,.catch()您需要做一些与正常情况类似的事情,catch并通过引发另一个错误来导致错误恢复失败你可以throw或返回一个拒绝的承诺

这段代码的工作方式与它应该的完全一样。而且我看不出我的代码有什么不同,除了我分别声明了这些函数。

无论承诺在哪里被拒绝,上面的代码都会停止。

您显示的第二段代码在拒绝后完全失败,因为没有其他.catch()成功的 -es。它基本上类似于这个同步代码:

try {
    console.log("log #1");
    throw new Error();
    console.log("log #2");
    console.log("log #3");
    console.log("Final end");
} catch {
    console.log("Caught");
}

因此,如果您不想提前恢复,也可以跳过.catch()而不是引发另一个错误。

于 2021-03-01T22:26:11.730 回答
1

尝试这个。

const p1 = (arg) => {
  // Promise returns data in the respected arguments
  return new Promise((resolve, reject) => {
    // Data to be accessed through first argument.
    resolve(arg);

  });
};


const p2 = (arg) => {
  return new Promise((resolve, reject) => {

    // Data to be accessed through second argument.
    reject(arg);

  });
}

p1('p1').then(resolve => {
  console.log(resolve + ' is handled with the resolve argument. So it is accessed with .then()');
}) // Since reject isn't configured to pass any data we don't use .catch()

p2('p2').catch(reject => {
  console.log(reject + ' is handled with the reject argument. So it is accessed with .catch()');
}) // Since resolve ins't configured to pass any data we don't use .then()

// You would normally configure a Promise to return a value on with resolve, and access it with .then() when it completes a task successfully.

// .catch() would then be chained on to the end of .then() to handle errors when a task cannot be completed.

// Here is an example.

const p3 = () => {
  return new Promise((resolve, reject) => {

    var condition = true;

    if (condition === true) {
      resolve('P3');
    } else {
      reject('Promise failed!');
    }

  });
};

p3('p3').then(resolve => {
  console.log(resolve);
}).catch(reject => {
  console.log(reject);
})

于 2021-03-01T20:29:05.660 回答
0

当 promise 被拒绝时,以下内容.then仍然会被执行。

是的。准确地说:thenandcatch方法调用都是同步执行的(一口气),因此所有涉及的 Promise 都是一次性创建的。传递给这些方法的回调是异步执行的,因为相关的 Promise 解决(完成或拒绝)。

据我了解,当在承诺链中发生错误/拒绝时,其后的.then调用将不再执行。

不是这种情况。根据传递给它的回调中发生的情况catch,返回的 Promise 可以完成或拒绝,因此当该 Promise 解决时,更下游的回调将相应地执行。

拒绝被正确捕获,但为什么在捕获后记录“P3”?

在您的情况下,catch回调返回undefined(它只执行 a console.log),它的承诺fullfulls!结果,链式then回调——在那个承诺上——被执行……等等。

如果你想“停止”

如果你想保持链原样,但希望有一个拒绝导致不再执行thencatch回调的行为,那么不要解决相关的承诺:

const stop = new Promise(resolve => null);

const p1 = () => {
    return new Promise((resolve, reject) => {
        console.log("P1");
        resolve();
    });
};

const p2 = () => {
    return new Promise((resolve, reject) => {
        console.log("P2");
        reject();
    });
};


const p3 = () => {
    return new Promise((resolve, reject) => {
        console.log("P3");
        resolve();
    });
};

p1().catch(() => {
    console.log("Caught p1");
    return stop; // don't resolve
}).then(p2).catch(() => {
    console.log("Caught p2");
    return stop;
}).then(p3).catch(() => {
    console.log("Caught p3");
    return stop;
}).then(() => {
    console.log("Final then");
});

于 2021-03-01T20:57:42.913 回答
0

你没有做错任何事。在您的代码中,您调用第一个承诺p1。然后你写p1.catch(...).then(...).then(...).then(...)。这是一个链,意味着您应该调用3 次,因为您在p1then承诺中调用了 resolve 方法(所有这些都依赖于第一个承诺)。then

于 2021-03-01T20:15:12.917 回答