如果您不解决或拒绝承诺会怎样?
What happens if you don't resolve or reject a promise?
我有一个场景,我正在返回一个承诺。
承诺基本上是由 ajax 请求触发的。
在拒绝承诺时,它会显示一个错误对话框,指出存在服务器错误。
我想做的是当响应代码为401时,我既不想解决承诺也不想拒绝它(因为它已经显示了错误对话框)。我只想重定向到登录页面。
我的代码看起来像这样:
function makeRequest(ur, params) {
return new Promise(function (resolve, reject) {
fetch(url, params).then((response) => {
let status = response.status;
if (status >= 200 && status < 300) {
response.json().then((data) => {
resolve(data);
});
} else {
if (status === 401) {
redirectToLoginPage();
} else {
response.json().then((error) => {
if (!error.message) {
error.message = constants.SERVER_ERROR;
}
reject({ status, error });
});
}
}
});
});
}
如您所见,如果状态为 401,我将重定向到登录页面。承诺既未解决也未拒绝。
这段代码可以吗,或者有更好的方法来实现吗?
它有效并且不是真正的问题,除非 makeRequest
的调用者期望实现承诺。所以,你在那里违约了。
相反,您可以推迟承诺,或(在本例中)拒绝状态 code/error。
Promise 只是一个具有 Javascript 属性的对象。它没有魔力。因此,未能解决或拒绝承诺就无法将状态从 "pending" 更改为其他任何状态。这不会在 Javascript 中引起任何基本问题,因为 promise 只是一个常规的 Javascript 对象。如果没有代码保留对 promise 的引用,promise 仍将被垃圾收集(即使仍未决)。
这里的真正结果是,如果承诺的状态永远不会改变,这对承诺的消费者意味着什么?任何用于解决或拒绝转换的 .then()
或 .catch()
侦听器将永远不会被调用。大多数使用 promises 的代码都希望它们在将来的某个时候解决或拒绝(这就是为什么首先使用 promises 的原因)。如果他们不这样做,那么该代码通常永远无法完成其工作。
您可能有一些其他代码来完成该任务的工作,而 promise 只是被放弃而没有做它的事情。如果您这样做,Javascript 中没有内部问题,但这不是 promise 设计的工作方式,通常也不是 promises 的消费者期望它们工作的方式。
As you can see if the status is 401, I am redirecting to login page.
Promise is neither resolved nor rejected.
Is this code OK? Or is there any better way to accomplish this.
在这种特殊情况下,一切正常,重定向是一种特殊且独特的情况。重定向到新的浏览器页面将完全清除当前页面状态(包括所有 Javascript 状态),因此使用重定向走捷径并留下其他未解决的问题是完全可以的。当新页面开始加载时,系统将完全重新初始化您的 Javascript 状态,以便清除所有仍未决的承诺。
正如其他人所说,如果您不 resolve/reject 承诺,这确实不是问题。无论如何,我会以不同的方式解决您的问题:
function makeRequest(ur,params) {
return new Promise(function(resolve,reject) {
fetch(url,params)
.then((response) => {
let status = response.status;
if (status >= 200 && status < 300) {
response.json().then((data) => {
resolve(data);
})
}
else {
reject(response);
}
})
});
}
makeRequest().then(function success(data) {
//...
}, function error(response) {
if (response.status === 401) {
redirectToLoginPage();
}
else {
response.json().then((error) => {
if (!error.message) {
error.message = constants.SERVER_ERROR;
}
//do sth. with error
});
}
});
这意味着我会拒绝每一个不良响应状态,然后在您的 makeRequest
的 error handler
中处理它。
我认为 "what happens if we don't resolve reject" 的回答很好 - 您可以选择添加 .then
还是 .catch
。
但是,这个代码可以吗?或者有没有更好的方法来完成这个。我会说有两件事:
您在 new Promise
中包装了一个 Promise,但它不是必需的,并且 fetch
调用 可能会失败 ,您应该采取行动,以便您的调用方法不会坐等一个永远不会被解决的 Promise。
这是一个示例(我认为这应该适用于您的业务逻辑,不是 100% 确定):
const constants = {
SERVER_ERROR: "500 Server Error"
};
function makeRequest(url,params) {
// fetch already returns a Promise itself
return fetch(url,params)
.then((response) => {
let status = response.status;
// If status is forbidden, redirect to Login & return nothing,
// indicating the end of the Promise chain
if(status === 401) {
redirectToLoginPage();
return;
}
// If status is success, return a JSON Promise
if(status >= 200 && status < 300) {
return response.json();
}
// If status is a failure, get the JSON Promise,
// map the message & status, then Reject the promise
return response.json()
.then(json => {
if (!json.message) {
json.message = constants.SERVER_ERROR;
}
return Promise.reject({status, error: json.message});
})
});
}
// This can now be used as:
makeRequest("http://example", {})
.then(json => {
if(typeof json === "undefined") {
// Redirect request occurred
}
console.log("Success:", json);
})
.catch(error => {
console.log("Error:", error.status, error.message);
})
相比之下,调用您的代码使用:
makeRequest("http://example", {})
.then(info => console.log("info", info))
.catch(err => console.log("error", err));
不会记录任何内容,因为对 http://example
的调用将失败,但 catch
处理程序将永远不会执行。
ECMAScript 规范解释了 promises 和 new Promise()
的目的:
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
25.6.3.1 Promise ( executor )
NOTE The executor argument must be a function object. It is called for initiating and reporting completion of the possibly deferred action represented by this Promise object.
您应该使用承诺来获取未来的价值。此外,为了使您的代码简洁明了,您应该仅使用 promises 来获取未来的值,而不要做其他事情。
由于您还将程序控制流(重定向逻辑)混合到您的 promise 的“执行程序”逻辑中,您的 promise 不再是“计算结果的占位符”;相反,它现在是一个 JavaScript 伪装成承诺的小程序。
因此,我建议不要将此 JavaScript 程序包装在 new Promise()
中,而是像普通 JavaScript 程序一样编写它:
async function makeRequest(url, params) {
let response = await fetch(url, params);
let { status } = response;
if (status >= 200 && status < 300) {
let data = await response.json();
successLogic(data);
} else if (status === 401) {
redirectToLoginPage();
} else {
let error = await response.json()
if (!error.message) {
error.message = constants.SERVER_ERROR;
}
errorLogic({ status, error });
}
}
我有一个场景,我正在返回一个承诺。 承诺基本上是由 ajax 请求触发的。
在拒绝承诺时,它会显示一个错误对话框,指出存在服务器错误。
我想做的是当响应代码为401时,我既不想解决承诺也不想拒绝它(因为它已经显示了错误对话框)。我只想重定向到登录页面。
我的代码看起来像这样:
function makeRequest(ur, params) {
return new Promise(function (resolve, reject) {
fetch(url, params).then((response) => {
let status = response.status;
if (status >= 200 && status < 300) {
response.json().then((data) => {
resolve(data);
});
} else {
if (status === 401) {
redirectToLoginPage();
} else {
response.json().then((error) => {
if (!error.message) {
error.message = constants.SERVER_ERROR;
}
reject({ status, error });
});
}
}
});
});
}
如您所见,如果状态为 401,我将重定向到登录页面。承诺既未解决也未拒绝。
这段代码可以吗,或者有更好的方法来实现吗?
它有效并且不是真正的问题,除非 makeRequest
的调用者期望实现承诺。所以,你在那里违约了。
相反,您可以推迟承诺,或(在本例中)拒绝状态 code/error。
Promise 只是一个具有 Javascript 属性的对象。它没有魔力。因此,未能解决或拒绝承诺就无法将状态从 "pending" 更改为其他任何状态。这不会在 Javascript 中引起任何基本问题,因为 promise 只是一个常规的 Javascript 对象。如果没有代码保留对 promise 的引用,promise 仍将被垃圾收集(即使仍未决)。
这里的真正结果是,如果承诺的状态永远不会改变,这对承诺的消费者意味着什么?任何用于解决或拒绝转换的 .then()
或 .catch()
侦听器将永远不会被调用。大多数使用 promises 的代码都希望它们在将来的某个时候解决或拒绝(这就是为什么首先使用 promises 的原因)。如果他们不这样做,那么该代码通常永远无法完成其工作。
您可能有一些其他代码来完成该任务的工作,而 promise 只是被放弃而没有做它的事情。如果您这样做,Javascript 中没有内部问题,但这不是 promise 设计的工作方式,通常也不是 promises 的消费者期望它们工作的方式。
As you can see if the status is 401, I am redirecting to login page. Promise is neither resolved nor rejected.
Is this code OK? Or is there any better way to accomplish this.
在这种特殊情况下,一切正常,重定向是一种特殊且独特的情况。重定向到新的浏览器页面将完全清除当前页面状态(包括所有 Javascript 状态),因此使用重定向走捷径并留下其他未解决的问题是完全可以的。当新页面开始加载时,系统将完全重新初始化您的 Javascript 状态,以便清除所有仍未决的承诺。
正如其他人所说,如果您不 resolve/reject 承诺,这确实不是问题。无论如何,我会以不同的方式解决您的问题:
function makeRequest(ur,params) {
return new Promise(function(resolve,reject) {
fetch(url,params)
.then((response) => {
let status = response.status;
if (status >= 200 && status < 300) {
response.json().then((data) => {
resolve(data);
})
}
else {
reject(response);
}
})
});
}
makeRequest().then(function success(data) {
//...
}, function error(response) {
if (response.status === 401) {
redirectToLoginPage();
}
else {
response.json().then((error) => {
if (!error.message) {
error.message = constants.SERVER_ERROR;
}
//do sth. with error
});
}
});
这意味着我会拒绝每一个不良响应状态,然后在您的 makeRequest
的 error handler
中处理它。
我认为 "what happens if we don't resolve reject" 的回答很好 - 您可以选择添加 .then
还是 .catch
。
但是,这个代码可以吗?或者有没有更好的方法来完成这个。我会说有两件事:
您在 new Promise
中包装了一个 Promise,但它不是必需的,并且 fetch
调用 可能会失败 ,您应该采取行动,以便您的调用方法不会坐等一个永远不会被解决的 Promise。
这是一个示例(我认为这应该适用于您的业务逻辑,不是 100% 确定):
const constants = {
SERVER_ERROR: "500 Server Error"
};
function makeRequest(url,params) {
// fetch already returns a Promise itself
return fetch(url,params)
.then((response) => {
let status = response.status;
// If status is forbidden, redirect to Login & return nothing,
// indicating the end of the Promise chain
if(status === 401) {
redirectToLoginPage();
return;
}
// If status is success, return a JSON Promise
if(status >= 200 && status < 300) {
return response.json();
}
// If status is a failure, get the JSON Promise,
// map the message & status, then Reject the promise
return response.json()
.then(json => {
if (!json.message) {
json.message = constants.SERVER_ERROR;
}
return Promise.reject({status, error: json.message});
})
});
}
// This can now be used as:
makeRequest("http://example", {})
.then(json => {
if(typeof json === "undefined") {
// Redirect request occurred
}
console.log("Success:", json);
})
.catch(error => {
console.log("Error:", error.status, error.message);
})
相比之下,调用您的代码使用:
makeRequest("http://example", {})
.then(info => console.log("info", info))
.catch(err => console.log("error", err));
不会记录任何内容,因为对 http://example
的调用将失败,但 catch
处理程序将永远不会执行。
ECMAScript 规范解释了 promises 和 new Promise()
的目的:
A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possibly asynchronous) computation.
25.6.3.1 Promise ( executor )
NOTE The executor argument must be a function object. It is called for initiating and reporting completion of the possibly deferred action represented by this Promise object.
您应该使用承诺来获取未来的价值。此外,为了使您的代码简洁明了,您应该仅使用 promises 来获取未来的值,而不要做其他事情。
由于您还将程序控制流(重定向逻辑)混合到您的 promise 的“执行程序”逻辑中,您的 promise 不再是“计算结果的占位符”;相反,它现在是一个 JavaScript 伪装成承诺的小程序。
因此,我建议不要将此 JavaScript 程序包装在 new Promise()
中,而是像普通 JavaScript 程序一样编写它:
async function makeRequest(url, params) {
let response = await fetch(url, params);
let { status } = response;
if (status >= 200 && status < 300) {
let data = await response.json();
successLogic(data);
} else if (status === 401) {
redirectToLoginPage();
} else {
let error = await response.json()
if (!error.message) {
error.message = constants.SERVER_ERROR;
}
errorLogic({ status, error });
}
}