try catch
try catch JavaScript的異常捕獲機制,凡是在try語句塊中的代碼出錯了,都會被catch捕獲。
then catch
Promise實例有兩個方法:
-
then 指定了resolve狀態和reject的回調函數,通過then方法獲取異步操作的結果。
-
catch 專門用來捕獲Promise對象產生的錯誤
then和catch方法返回的是一個新的Promise對象,因爲Promise對象具有then和catch方法,所以可以一直.then和.catch下去。
.then(
value => {
console.log(value);
},
reason => {
console.log(reason);
}
)
then方法的參數是兩個回調函數,都接受Promise對象傳出的值作爲參數:
-
第一個參數是resolve狀態的回調函數
-
第二個參數是reject的回調函數, 這個參數是可選的
通常這個參數也不寫,因爲Promise實例還有一個方法叫catch是專門用來捕獲異常的。
catch 是 .then(null, rejection)的別名,用於指定發生錯誤時的回調函數。
一旦catch前面的任何一個Promise發生異常,都會被catch捕獲,包括Promise函數創建的Promise,還有.then返回的Promise,甚至catch前面如果還有一個catch在這個catch拋出的異常也會被後一個catch捕獲。
也就是說:
Promise對象的錯誤具有冒泡性質,會一直向後傳遞,直到被捕獲爲止,也即是說,錯誤總會被下一個catch語句捕獲。
所以,既然這個catch這麼厲害,then函數中的第二個參數常常被省略了,然後被這個catch方法替代。
所以通常這麼寫:
promise.then().catch()
promise.then().then().catch()
promise.then().then().catch().then().catch()
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
一般總是建議,Promise 對象後面要跟catch方法,這樣可以處理 Promise 內部發生的錯誤。catch方法返回的還是一個 Promise 對象,因此後面還可以接着調用then方法和catch方法。
直接返回一個狀態爲rejected Promise對象
Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態爲rejected。
var p = Promise.reject('出錯了');
//等價於
new Promise(function (resolve,reject) {
reject('出錯了');
})
Promise.reject()方法的參數,會原封不動地作爲reject的理由,變成後續方法的參數。不會像Promise.resolve那樣,根據不同的情況包裝Promise。
async函數
- async函數是Generator函數的語法糖(將Generator的星號換成async 將yield換成await)
Generator是一個狀態機,封裝了多個內部狀態,執行 Generator 函數會返回一個遍歷器對象,返回的遍歷器對象,可以使用next依次遍歷 Generator 函數內部的每一個狀態。Generator 函數是分段執行的,yield表達式是暫停執行的標記,而next方法可以恢復執行。Generator 函數的執行必須靠執行器。
- async函數的返回值爲Promise對象
- Promise對象的結果由async函數執行的返回值決定
async function test_02() {
return "success";
}
console.log(test_02());
或者
async function test_02() {
return "success";
}
p = test_02();
console.log(p);
test_02函數加了async,返回結果就是一個promise對象。
對象狀態爲resolved,對象值爲返回字符串“success”。
function test_01() {
new Promise((resolve, reject) => {
resolve('success');
reject('fail...')
}).then(
value => {
console.log(value);
},
reason => {
console.log(reason);
}
)
}
test_01();
test_01函數與test_02函數執行結果一樣,但是test_02函數更加簡潔。
async function test_02() {
throw 2;
};
const p = test_02();
p.then(
null,
reason => {
console.log('onRejected:' + reason);
}
);
console.log(p);
async函數的promise對象返回值,可以是成功,也可以是失敗。
await
-
await右側的表達式可以是promise對象,也可以是其他值(字符串、普通類型數值等)。
-
如果表達式是promise對象,await返回的是promise成功的值。promise失敗的值,由try/catch獲取。
-
await必須寫在async函數中,但aysnc函數中可以沒有await。
-
如果await的promise失敗,就會拋出異常。異常需通過try/catch捕獲處理。
async函數 相當於對多個Promise的封裝,所以必須等到內部所有的await命令執行完,纔會改變自己的狀態爲resolved,除非 碰到return語句或者拋出了異常。
只要一個await後面的Promise變爲rejected,整個async函數就會中斷執行,整個async返回的Promise對象就會是rejected狀態。
async function f() {
await Promise.reject('出錯了');
await Promise.resolve('hello world'); // 不會執行}
第一個await後面的對象reject了,所以整個async函數就中斷執行了。
有時,我們希望即使前一個異步操作失敗,也不要中斷後面的異步操作。
這時可以將第一個await放在try...catch結構裏面,這樣不管這個異步操作是否成功,第二個await都會執行。
通過try catch捕獲異常
如果有多個await命令,可以將其都放在try catch結構中,如果執行出錯,catch會去捕獲異常
async function f() {
try {
await Promise.reject('出錯了');
console.log('上面已經出錯了'); // 不打印
return await Promise.resolve('hello world'); // 不執行
} catch(e) {
console.log(e);
}
}
f()
.then(v => console.log(v))
catch會去捕獲try代碼塊中的錯誤,只要有一個拋出了異常,就不會繼續執行。
因爲使用了trycatch 所以 async 是順利執行完成的,其中的報錯被 try catch處理了,所以異常不會被async返回的Promise的catch捕獲,因此async返回的Promise對象狀態是resolved。
async function f() {
try {
await Promise.reject('出錯了');
console.log('上面已經出錯了'); // 不打印
return await Promise.resolve('hello world'); // 不執行
} catch(e) {
console.log("1111");
console.log(e);
}
}
f()
.then(v => {
console.log(v);
console.log(3333)
})
.catch(
console.log("2222")
)
line81 執行並打印undefined,是因爲最終promise對象轉爲resolved狀態,但是沒有value值。
function fn1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(5);
})
})
}
function fn2() {
return 6;
}
async function test() {
const v1 = await fn1();
const v2 = await fn2();
console.log('value1', v1);
console.log('value2', v2);
}
test();
運行結果:
value1 5
value2 6
await右側表達式爲promise,則得到結果爲promise成功的value。
await右側表達不是promise,則得到結果爲返回值自身。
await只能等得成功的結果,失敗的結果用try/catch
任何表達式之前都可以加await,看結果是不是promise。如果得到結果是promise,則返回promise內部的value。如果是普通值,則結果爲該值本身。
參考:
https://www.jianshu.com/p/2037e3b53d5f (async await promise try...catch)