JavaScript-asyc await

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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章