異常捕獲

ES5 中的傳統作法

假設代碼塊執行拋出錯誤 fail,那麼捕獲該錯誤的寫法爲:異步

try {
  // 代碼塊執行,並拋出 fail 錯誤
  throw new Error('fail');
} catch (e) {
  console.log(e);
}

定時器

咱們先來針對上面的代碼改寫一下,加入一個定時器。async

try {
  setTimeout(()=>{
    throw new Error('fail');
    // Uncaught Error: fail
     }, 1000);
} catch (e) {
  console.log(e);
}

像這樣,將 try/catch 扔在定時器的外面,是沒法捕獲到內部的錯誤的。函數

正確的作法應該是:code

setTimeout(()=>{
  try{
    throw new Error('fail');
  } catch (e) {
    console.log(e);
  }
},1000);

Promise

function doSomething() {
  return new Promise((resolve, reject) => {
    // 同步代碼中的 throw 能夠被捕捉到
    throw new Error('fail');
  });
}

doSomething()
  .then((x) => {
    console.log('success:', x);
  })
  .catch((err) => {
    console.log('fail:', err);
  });

這樣寫是沒有問題的,錯誤可以被捕獲到。但只要稍微修改一下,可能就出現問題了。好比:同步

function doSomething() {
  return new Promise((resolve, reject) => {
    // 異步代碼中的 throw 不能被 Promise 的 catch 捕捉到
    setTimeout(() => {
      throw new Error("fail");
    }, 1000);
  });
}

doSomething()
  .then((x) => {
    console.log('success:', x);
  })
  .catch((err) => {
    console.log('fail:', err);
  });

這裏拋出但錯誤將不能被捕獲。因此,在 Promise 中,咱們通常經過 reject 來拋出錯誤。it

function doSomething(x) {
  return new Promise((resolve, reject) => reject(x));
}

doSomething('fail').then((x) => {
  console.log('success:', x);
}).catch((err) => {
  console.log('fail:', err);
});
// fail: fail

另外,還有一個比較有意思的細節,在 catch 以後繼續添加 .then 會被繼續執行。io

function doSomething(x) {
  return new Promise((resolve, reject) => reject(x));
}

doSomething('fail').then((x) => {
  console.log('success:', x);
}).catch((err) => {
  console.log('fail:', err);
  // 這裏能夠寫 return 給下面的方法繼續執行
}).then((x) => {
  console.log('continue:', x);
});
// fail: fail
// continue: undefined

Async/Await

本質上來說, Async/Await 是經過 Promise 實現,因此基本跟上面 Promise 所講的差很少。console

能夠在 await 方法外嵌套 try/catch,相似這樣:function

function doSomething(x) {
  return new Promise((resolve, reject) => reject(x));
}

(async () => {
  try {
    const result = await doSomething('fail');
    console.log('success:', result);
    // return 返回
  } catch (err) {
    console.log('fail:', err);
    // return 返回
  }
})();
// fail: fail

但這裏就有一個問題,好比函數須要有返回,那麼返回的語句就須要寫兩次,正常但時候返回結果,錯誤的時候,返回一個 throw new Error() 或者其餘的。有一個小的竅門,能夠這樣寫:class

function doSomething(x) {
  return new Promise((resolve, reject) => reject(x));
}

(async () => {
  const result = await doSomething('fail').catch((err) => {
    console.log('fail:', err);
    return 0; // 默認值
  });
  console.log('success:', result);
})();
// fail: fail
// success: 0

在錯誤捕獲到以後,從新分配一個默認值,讓代碼繼續運行。

相關文章
相關標籤/搜索