异步失败时更喜欢抛出或拒绝
Prefer throw or reject when failing promise asynchronously
我有一个 Bluebird 承诺,它包装了一个 AJAX 请求,并且需要在请求失败时拒绝该承诺。我想向可能附加的任何 catch 块提供请求失败的原因,主要来自状态代码。为了实现这一点,我有 UnauthorizedError
和 NotFoundError
以及类似的 类,所有这些都扩展了 Error
以与 Bluebird 的模式匹配 catch
.
一起工作
我不确定的部分是我是否应该 throw
或调用拒绝处理程序。我的代码看起来像:
class Request {
// other methods
send(method, url, args, body) {
return new Promise((res, rej) => {
let xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = () => {
res(JSON.parse(xhr.responseText));
};
xhr.onerror = () => {
let status = xhr.status;
switch (status) {
case 401:
// Should I use throw:
throw new UnauthorizedError(url);
// or
rej(new UnauthorizedError(url));
}
};
xhr.send();
});
}
}
Promise
构造函数内部
promise 构造函数是抛出安全的,但本质上您通常不会在内部处理抛出安全的东西 - 因此例如以下内容不安全:
new Promise(function(resolve, reject){
setTimeout(function(){
// NEVER throw here, it'll throw globally and not reject the promise
}, 100);
});
promise 构造函数通常仅用于将回调 API 转换为 promises,并且由于回调不像 promises 那样是抛出安全的,因此当它们异步出错时您必须拒绝(而不是抛出)。
在 then
处理程序中
两者在功能上完全相同。当您从 then
处理程序中 throw
时,您将返回一个被拒绝的承诺。我更喜欢抛出,因为它比 return
更明确地表明发生了错误,但这并不重要。
除了 Angular 1.x 的 $q
之外,这对于任何承诺实现都是正确的,它区分了两者 - 但它是奇怪的球(当你 throw
那里即使您处理了错误,它也会记录)。
在你的代码中
在您的代码中,您拒绝和处理承诺的方式存在多个错误。 Promise 非常健壮,因为它们可以优雅地为您处理错误 - 在将回调 API 转换为 promises 时,您必须格外小心:
class Request {
// other methods
send(method, url, args, body) {
return new Promise((res, rej) => { // it's good that new Promise is the first
let xhr = new XMLHttpRequest(); // line since it's throw-safe. This is why it
xhr.open(method, url); // was chosen for the API and not deferreds
xhr.onload = () => {
// This _needs_ a try/catch, it will fail if responseText
// is invalid JSON and will throw to the global scope instead of rejecting
res(JSON.parse(xhr.responseText));
};
xhr.onerror = () => {
let status = xhr.status;
switch (status) {
case 401:
// this _must_ be a reject, it should also generally be surrounded
// with a try/catch
rej(new UnauthorizedError(url));
}
};
xhr.send(); // it's important that this is in the promise constructor
});
}
}
我有一个 Bluebird 承诺,它包装了一个 AJAX 请求,并且需要在请求失败时拒绝该承诺。我想向可能附加的任何 catch 块提供请求失败的原因,主要来自状态代码。为了实现这一点,我有 UnauthorizedError
和 NotFoundError
以及类似的 类,所有这些都扩展了 Error
以与 Bluebird 的模式匹配 catch
.
我不确定的部分是我是否应该 throw
或调用拒绝处理程序。我的代码看起来像:
class Request {
// other methods
send(method, url, args, body) {
return new Promise((res, rej) => {
let xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = () => {
res(JSON.parse(xhr.responseText));
};
xhr.onerror = () => {
let status = xhr.status;
switch (status) {
case 401:
// Should I use throw:
throw new UnauthorizedError(url);
// or
rej(new UnauthorizedError(url));
}
};
xhr.send();
});
}
}
Promise
构造函数内部
promise 构造函数是抛出安全的,但本质上您通常不会在内部处理抛出安全的东西 - 因此例如以下内容不安全:
new Promise(function(resolve, reject){
setTimeout(function(){
// NEVER throw here, it'll throw globally and not reject the promise
}, 100);
});
promise 构造函数通常仅用于将回调 API 转换为 promises,并且由于回调不像 promises 那样是抛出安全的,因此当它们异步出错时您必须拒绝(而不是抛出)。
在 then
处理程序中
两者在功能上完全相同。当您从 then
处理程序中 throw
时,您将返回一个被拒绝的承诺。我更喜欢抛出,因为它比 return
更明确地表明发生了错误,但这并不重要。
除了 Angular 1.x 的 $q
之外,这对于任何承诺实现都是正确的,它区分了两者 - 但它是奇怪的球(当你 throw
那里即使您处理了错误,它也会记录)。
在你的代码中
在您的代码中,您拒绝和处理承诺的方式存在多个错误。 Promise 非常健壮,因为它们可以优雅地为您处理错误 - 在将回调 API 转换为 promises 时,您必须格外小心:
class Request {
// other methods
send(method, url, args, body) {
return new Promise((res, rej) => { // it's good that new Promise is the first
let xhr = new XMLHttpRequest(); // line since it's throw-safe. This is why it
xhr.open(method, url); // was chosen for the API and not deferreds
xhr.onload = () => {
// This _needs_ a try/catch, it will fail if responseText
// is invalid JSON and will throw to the global scope instead of rejecting
res(JSON.parse(xhr.responseText));
};
xhr.onerror = () => {
let status = xhr.status;
switch (status) {
case 401:
// this _must_ be a reject, it should also generally be surrounded
// with a try/catch
rej(new UnauthorizedError(url));
}
};
xhr.send(); // it's important that this is in the promise constructor
});
}
}