Error handling with promises
// 用 .catch 處理錯誤
// URL 錯誤,沒有這個伺服器
fetch('https://no-such-server.blabla') // rejects
.then(response => response.json())
.catch(err => alert(err)) // TypeError: failed to fetch (the text may vary)
// 不是有效的 JSON
fetch('/') // fetch works fine now, the server responds with the HTML page
.then(response => response.json()) // rejects: the page is HTML, not a valid json
.catch(err => alert(err)) // SyntaxError: Unexpected token < in JSON at position 0
// 接收所有錯誤的方法,把 .catch 加到鏈的最後面
fetch('/article/promise-chaining/user.json')
.then(response => response.json())
.then(user => fetch(`https://api.github.com/users/${user.name}`))
.then(response => response.json())
.then(githubUser => new Promise(function(resolve, reject) {
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => {
img.remove();
resolve(githubUser);
}, 3000);
}))
.catch(error => alert(error.message));
Implicit try…catch
// executor 和 promise handlers 有隱藏的 try..catch,當異常發生會接收錯誤
// executor
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(alert); // Error: Whoops!
// same
new Promise((resolve, reject) => {
reject(new Error("Whoops!"));
}).catch(alert); // Error: Whoops!
// promise handlers
new Promise(function(resolve, reject) {
resolve("ok");
}).then(function(result) {
throw new Error("Whoops!"); // rejects the promise
}).catch(alert); // Error: Whoops!
// 適用於任何錯誤
new Promise((resolve, reject) => {
resolve("ok");
}).then((result) => {
blabla(); // no such function
}).catch(alert); // ReferenceError: blabla is not defined
Rethrowing
// 可以有多個 .then,然後在一次 .catch 處理所有錯誤,在 try..catch 中,可以分析錯誤,
// 無法處理,可以重新拋出錯誤。
// 正常處理錯誤
// the execution: catch -> then
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function(error) {
alert("The error is handled, continue normally");
}).then(() => alert("Next successful handler runs"));
// 重新拋出錯誤
// the execution: catch -> catch -> then
new Promise((resolve, reject) => {
throw new Error("Whoops!");
}).catch(function(error) { // (*)
if (error instanceof URIError) {
// handle it
} else {
alert("Can't handle such error");
throw error; // throwing this or another error jumps to the next catch
}
}).then(function() {
/* never runs here */
}).catch(error => { // (**)
alert(`The unknown error has occurred: ${error}`);
// don't return anything => execution goes the normal way
});
Fetch error handling example
// fetch 回報錯誤當無法發出請求的時候,但一些錯誤像是 error 500、error 404 仍被認為是有效的請求
// 如果伺服器返回非 JSON 的頁面,在 * 回復 error 500,或者如果沒有該使用者,githubpage 返回
// error 404,
fetch('no-such-user.json') // (*)
.then(response => response.json())
.then(user => fetch(`https://api.github.com/users/${user.name}`)) // (**)
.then(response => response.json())
.catch(alert); // SyntaxError: Unexpected token < in JSON at position 0
// ...
// 進一步分析錯誤,如果 response.status 不是 200 拋出錯誤
// 創造一個自定義的 HttpError 跟其他類型的錯誤分開,有錯誤分類可以輕鬆在錯誤處理檢查到
class HttpError extends Error { // (1)
constructor(response) {
super(`${response.status} for ${response.url}`);
this.name = 'HttpError';
this.response = response;
}
}
function loadJson(url) { // (2)
return fetch(url)
.then(response => {
if (response.status == 200) {
return response.json();
} else {
throw new HttpError(response);
}
})
}
loadJson('no-such-user.json') // (3)
.catch(alert); // HttpError: 404 for .../no-such-user.json
// 如果得到 error 404,要求用戶填入正確名字
function demoGithubUser() {
let name = prompt("Enter a name?", "iliakan");
return loadJson(`https://api.github.com/users/${name}`)
.then(user => {
alert(`Full name: ${user.name}.`); // (1)
return user;
})
.catch(err => {
if (err instanceof HttpError && err.response.status == 404) { // (2)
alert("No such user, please reenter.");
return demoGithubUser();
} else {
throw err;
}
});
}
demoGithubUser();
Unhandled rejections
// 沒有 .catch 處理錯誤
new Promise(function() {
noSuchFunction(); // Error here (no such function)
})
.then(() => {
// successful promise handlers, one or more
}); // without .catch at the end!
// 一个没有 .catch 的 promise 链
new Promise(function() {
throw new Error("Whoops!");
}).then(function() {
// ...something...
}).then(function() {
// ...something else...
}).then(function() {
// ...后面没有 catch!
});
// 出现错误,则 promise 状态变为 “rejected”,跳到最近的 rejection 处理程序,
// 沒有 .catch 處理錯誤,程式碼卡住
// 在这种情况下,大多数 JavaScript 引擎会跟踪此类情况并生成全局错误。我们可以在控制台中看到它。
// 在瀏覽器裡,可以用 unhandledrejection 捕捉錯誤
window.addEventListener('unhandledrejection', function(event) {
// the event object has two special properties:
alert(event.promise); // [object Promise] - the promise that generated the error
alert(event.reason); // Error: Whoops! - the unhandled error object
});
new Promise(function() {
throw new Error("Whoops!");
}); // no catch to handle the error
Last updated