欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavsScript中Promise的錯(cuò)誤捕獲詳解

 更新時(shí)間:2022年06月27日 16:51:52   作者:編寫人生  
怎么捕獲錯(cuò)誤并且處理是一門語(yǔ)言必備的知識(shí),在JavaScript中也是如此,下面這篇文章主要給大家介紹了關(guān)于JavsScript中Promise錯(cuò)誤捕獲的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下

我們需要在異步任務(wù)中準(zhǔn)確的進(jìn)行錯(cuò)誤捕獲,以便我們可以知道錯(cuò)誤出在什么地方

如果對(duì)Promise和trycatch不夠理解的話,很多時(shí)候會(huì)出現(xiàn)Promise中的錯(cuò)誤無(wú)法被捕獲的情況,本文來(lái)討論這些情況

try catch

try catch 只能捕獲當(dāng)前上下文中的錯(cuò)誤,也就是只能捕獲同步任務(wù)的情況,如下場(chǎng)景:

try {
    throw "程序執(zhí)行遇到了一些錯(cuò)誤";
} catch(e) {
    console.log(e)
}
// 控制臺(tái)會(huì)輸出:程序執(zhí)行遇到了一些錯(cuò)誤

這很好,錯(cuò)誤被捕獲了,我們可以在程序中進(jìn)程錯(cuò)誤的處理;

但是對(duì)于異步的任務(wù),trycatch就顯得無(wú)能為力,不能正確捕獲錯(cuò)誤:

try {
    setTimeout(() => {
      throw "程序執(zhí)行遇到了一些錯(cuò)誤"  
    })
} catch(e) {
    console.log(e);
}
// 控制臺(tái)輸出:Uncaught 程序執(zhí)行遇到了一些錯(cuò)誤;

又或者這樣:

try {
    Promise.reject('程序執(zhí)行遇到了一些錯(cuò)誤');
} catch(e) {
    console.log(e);
}
// 控制臺(tái)輸出:Uncaught (in promise) 程序執(zhí)行遇到了一些錯(cuò)誤

上面的代碼都無(wú)法正常捕獲到錯(cuò)誤,因?yàn)椋?strong>trycatch永遠(yuǎn)捕獲的是同步的錯(cuò)誤

什么是同步的錯(cuò)誤?

當(dāng)在一個(gè)事件循環(huán)內(nèi),同一個(gè)任務(wù)隊(duì)列中出現(xiàn)的錯(cuò)誤,對(duì)于這個(gè)任務(wù)所在的上下文而言,就是同步錯(cuò)誤。

setTimeoutPromise被稱為任務(wù)源,來(lái)自不同的任務(wù)源注冊(cè)的回調(diào)函數(shù)會(huì)被放入不同的任務(wù)隊(duì)列中。

  • setTimeout中的任務(wù)會(huì)被放入宏任務(wù)

  • Promise中的任務(wù)會(huì)被放入微任務(wù)

    • 拓展:setTimeout是宿主瀏覽器發(fā)起的任務(wù),一般會(huì)被放入宏任務(wù)
    • 而Promise是由JS引擎發(fā)起的任務(wù),會(huì)被放入微任務(wù)

第一次事件循環(huán)中,JS引擎會(huì)把整個(gè)script代碼當(dāng)成一個(gè)宏任務(wù)執(zhí)行,執(zhí)行完成之后,再檢測(cè)本次循環(huán)中是否存在微任務(wù),存在的話就依次從微任務(wù)的任務(wù)隊(duì)列中讀取執(zhí)行完所有的微任務(wù),再讀取宏任務(wù)的任務(wù)隊(duì)列中的任務(wù)執(zhí)行,再執(zhí)行所有的微任務(wù),如此循環(huán)。

JS的執(zhí)行順序就是每次事件循環(huán)中的宏任務(wù)-微任務(wù)的不斷切換。

再看setTimeout中拋出的錯(cuò)誤,這個(gè)錯(cuò)誤已經(jīng)不在trycatch所在的事件循環(huán)中了,所以這是一個(gè)異步錯(cuò)誤,無(wú)法被trycatch捕獲到。

同理,Promise.reject()此處雖然是同步執(zhí)行的,但是此處reject的內(nèi)容卻在另一個(gè)微任務(wù)循環(huán)中,對(duì)于trycatch來(lái)講也不是同步的,所以這兩個(gè)錯(cuò)誤都無(wú)法被捕獲。

Promise.reject

要理解Promise.reject首先要了解它的返回值,Promise.reject返回的是一個(gè)Promise對(duì)象,請(qǐng)注意:是Promise對(duì)象。

Promise對(duì)象在任何時(shí)候都是一個(gè)合法的對(duì)象,它不是錯(cuò)誤也不是異常,所以在任何實(shí)現(xiàn),直接對(duì)Promise.reject或者一個(gè)返回Promise對(duì)象的調(diào)用直接try catch是沒(méi)有意義的,一個(gè)正常的對(duì)象永遠(yuǎn)不可能觸發(fā)catch捕獲。

假設(shè)我們由如下代碼:

function getData() {
    Promise.reject('遇到了一些錯(cuò)誤');
};
function click() {
    try {
        getData();
    } catch(e) {
        console.log(e);
    }
}
click(); // 我們模擬業(yè)務(wù)場(chǎng)景中的click事件
// 控制臺(tái)輸出: Uncaught (in promise) 遇到了一些錯(cuò)誤

Promise已經(jīng)通過(guò)reject拋出了錯(cuò)誤,為什么try catch捕獲不到呢?

首先,需要知道,對(duì)于一個(gè)函數(shù)的錯(cuò)誤是否可以被捕獲到,可以嘗試將函數(shù)調(diào)用的返回值替換到函數(shù)調(diào)用出,看看是否為一個(gè)錯(cuò)誤

上面getDate()調(diào)用會(huì)被替換為undefined

對(duì)于一個(gè)沒(méi)有明確return的函數(shù)調(diào)用,其返回值永遠(yuǎn)是undefined的,所以代碼如下:

function click() {
    try {
        undefined;
    } catch(e) {
        console.log(e);
    }
}

了解js基礎(chǔ)的人肯定知道,這不算異常,這個(gè)代碼會(huì)正常執(zhí)行,不會(huì)走到catch中。

可能會(huì)有另一種思路,就是將Promise.reject返回出去,那么代碼就變成:

function getData() {
  return Promise.reject('遇到了一些錯(cuò)誤');
};
function click() {
    try {
        getData();
    } catch(e) {
        console.log(e);
    }
}
click();

Promise.reject返回的是一個(gè)Promise對(duì)象,它是對(duì)象,不是錯(cuò)誤。所以在try catch中完成getData()調(diào)用后這里會(huì)出現(xiàn)一個(gè)Promise對(duì)象,這個(gè)對(duì)象是一個(gè)再正常不過(guò)的對(duì)象,不會(huì)被catch捕獲,所以這個(gè)try catch依然是無(wú)效的。

于是,又出現(xiàn)一種思路:再調(diào)用處使用Promise的catch方法進(jìn)行捕獲,于是代碼變成:

function getData() {
  return Promise.reject('遇到了一些錯(cuò)誤');
};
function click() {
    try {
        getData().catch(console.log);
    } catch(e) {
        console.log(e);
    }
}
click();

這是可行的,rejext的錯(cuò)誤可以被捕獲,但這不是try catch的功勞,而是Promise的內(nèi)部消化,所以這里的try catch依然沒(méi)有意義。

解決Promise異常捕獲

Promise異常是最常見(jiàn)的異步異常,其內(nèi)部的錯(cuò)誤基本都是被包裝成了Promise對(duì)象后進(jìn)行傳遞,所以解決Promise異步捕獲整體思路有兩個(gè):

  • 使用Promise的catch方法內(nèi)部消化;
  • 使用async和await將異步錯(cuò)誤轉(zhuǎn)同步錯(cuò)誤再由try catch捕獲

Promise.catch

對(duì)于Promise.reject中拋出的錯(cuò)誤,或者Promise構(gòu)造器中拋出的錯(cuò)誤,亦或者then中出現(xiàn)的錯(cuò)誤,無(wú)論是運(yùn)行時(shí)還是通過(guò)throw主動(dòng)拋出的,原則上都可以被catch捕獲。

如下:

function getData() {
    Promise.reject('這里發(fā)生了錯(cuò)誤').catch(console.log);
}
?
function click() {
    getData();
}
?
click();

亦或者在調(diào)用處捕獲,但這需要被調(diào)用的函數(shù)能返回Promise對(duì)象;

function getData() {
    return Promise.reject('程序發(fā)生了一些錯(cuò)誤');
}

function click() {
    getData().catch(console.log);
}
click();

上面兩個(gè)方案都可行,事實(shí)上建議在業(yè)務(wù)邏輯允許的情況下,將Promise都返回出去,以便能向上傳遞,同時(shí)配合**unhandledrejection**進(jìn)行兜底

async await 異步轉(zhuǎn)同步

使用async和await可以將一個(gè)異步函數(shù)調(diào)用在語(yǔ)義上變成同步執(zhí)行的效果,這樣我們就可以使用try catch去統(tǒng)一處理。

例如:

function getData() {
    return Promise.reject('程序發(fā)生錯(cuò)誤');
}
async function click() {
    try {
        await getData();
    } catch(e) {
        console.log(e);
    }
}

click();

需要注意的是,如果getData方法沒(méi)有寫return, 那么就無(wú)法將Promise對(duì)象向上傳遞,那么調(diào)用出的await等到的就是一個(gè)展開的undefined, 依舊不能進(jìn)行錯(cuò)誤處理。

注意事項(xiàng)

一個(gè)函數(shù)如果內(nèi)部處理了Promise異步對(duì)象,那么原則上其處理結(jié)果應(yīng)該也是一個(gè)Promise對(duì)象,對(duì)于需要進(jìn)行錯(cuò)誤捕獲的場(chǎng)景,Promise對(duì)象應(yīng)該始終通過(guò)return向上傳遞

兜底方案

一般情況下,同步錯(cuò)誤如果沒(méi)有進(jìn)行捕獲,那么這個(gè)錯(cuò)誤所在的事件循環(huán)將終止,所以在開發(fā)階段沒(méi)有捕獲的錯(cuò)誤,使用一種方法進(jìn)行兜底是很有必要的。

對(duì)于同步錯(cuò)誤,可以定義window.onerror進(jìn)行兜底處理,或者使用window.addEventListener('error', errHandler)來(lái)定義兜底函數(shù)。

對(duì)于Promise異常,則可以同步使用window.onunhandledrejection或者window.addEventListener('unhandledrejection', errHandler)來(lái)定義兜底函數(shù)。

我們?cè)儆懻搕hen方法中的第二個(gè)參數(shù)和Promise.catch方法的區(qū)別

Promise中的then的第二個(gè)參數(shù)和catch有什么區(qū)別?

  • reject是用來(lái)拋出錯(cuò)誤的,屬于Promise的方法
  • catch是用來(lái)處理異常的,屬于Promise實(shí)例的方法、
  • 區(qū)別

    主要區(qū)別就是,如果在then的第一個(gè)函數(shù)中拋出了異常,后面的catch能捕獲到,但是then的第二個(gè)參數(shù)卻捕獲不到

    then的第二個(gè)參數(shù)和catch捕獲信息的時(shí)候會(huì)遵循就近原則,如果是promise內(nèi)部報(bào)錯(cuò),reject拋出錯(cuò)誤后,then的第二個(gè)參數(shù)和catch方法都存在的情況下,只有then的第二個(gè)參數(shù)能捕獲到,如果then的第二個(gè)參數(shù)不存在,則catch方法會(huì)被捕獲到。

題: then方法的連續(xù)調(diào)用,怎么能夠知道是第幾個(gè)then方法報(bào)錯(cuò)了呢。

new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve(1);
    }, 1000)
}).then(res => {
    console.log(res);
    return new Promise((resolve,reject) => {
        reject('第一個(gè)then方法報(bào)錯(cuò)了');
    })
}).then(res => {
    console.log(res);
    return new Promise((resolve,reject) => {
		reject('第二個(gè)then方法報(bào)錯(cuò)了');
    })
}).catch(err => {
    console.log(err);
})

總結(jié)

到此這篇關(guān)于JavsScript中Promise錯(cuò)誤捕獲的文章就介紹到這了,更多相關(guān)JS Promise錯(cuò)誤捕獲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Electron應(yīng)用顯示隱藏時(shí)展示動(dòng)畫效果實(shí)例

    Electron應(yīng)用顯示隱藏時(shí)展示動(dòng)畫效果實(shí)例

    最近使用electron實(shí)現(xiàn)一個(gè)簡(jiǎn)單的功能,下面這篇文章主要給大家介紹了關(guān)于Electron應(yīng)用顯示隱藏時(shí)展示動(dòng)畫效果的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-05-05
  • 微信小程序?qū)崿F(xiàn)訂單倒計(jì)時(shí)

    微信小程序?qū)崿F(xiàn)訂單倒計(jì)時(shí)

    這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)訂單倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • JavaScript實(shí)現(xiàn)淘寶購(gòu)物件數(shù)選擇

    JavaScript實(shí)現(xiàn)淘寶購(gòu)物件數(shù)選擇

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)淘寶購(gòu)物件數(shù)的選擇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • JS循環(huán)中正確使用async、await的姿勢(shì)分享

    JS循環(huán)中正確使用async、await的姿勢(shì)分享

    async?/?await是ES7的重要特性之一,也是目前社區(qū)里公認(rèn)的優(yōu)秀異步解決方案,下面這篇文章主要給大家介紹了關(guān)于JS循環(huán)中正確使用async、await的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2021-12-12
  • JS實(shí)現(xiàn)頁(yè)面進(jìn)入和返回定位到具體位置

    JS實(shí)現(xiàn)頁(yè)面進(jìn)入和返回定位到具體位置

    其實(shí)瀏覽器也自帶了返回的功能,也就是說(shuō),自帶了返回定位的功能,返回定位到具體位置有兩種方法,下面通過(guò)場(chǎng)景分析給大家詳細(xì)講解,需要的的朋友參考下
    2016-12-12
  • 原生javaScript實(shí)現(xiàn)圖片延時(shí)加載的方法

    原生javaScript實(shí)現(xiàn)圖片延時(shí)加載的方法

    這篇文章主要介紹了原生javaScript實(shí)現(xiàn)圖片延時(shí)加載的方法,無(wú)需通過(guò)載入jQuery腳本即可實(shí)現(xiàn)圖片的延時(shí)加載效果,是非常實(shí)用的技巧,需要的朋友可以參考下
    2014-12-12
  • JavaScript實(shí)現(xiàn)圖片DIV豎向滑動(dòng)的方法

    JavaScript實(shí)現(xiàn)圖片DIV豎向滑動(dòng)的方法

    這篇文章主要介紹了JavaScript實(shí)現(xiàn)圖片DIV豎向滑動(dòng)的方法,涉及javascript操作div層的相關(guān)技巧,需要的朋友可以參考下
    2015-04-04
  • Bootstrap表單組件教程詳解

    Bootstrap表單組件教程詳解

    表單常見(jiàn)的元素主要包括:文本輸入框、下拉選擇框、單選框、復(fù)選框、文本域、按鈕等。接下來(lái)通過(guò)本文給大家介紹Bootstrap表單組件教程,感興趣的朋友一起學(xué)習(xí)吧
    2016-04-04
  • 詳解JS中???和?.?和||的區(qū)別

    詳解JS中???和?.?和||的區(qū)別

    這篇文章主要介紹了詳解JS中???和?.?和||的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • firefox下frameset取不到值的解決方法

    firefox下frameset取不到值的解決方法

    IE FF都可以直接通過(guò)Frame的Name來(lái)訪問(wèn),但是FrameSet不支持name屬性
    2010-09-09

最新評(píng)論