最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavsScript中Promise的錯誤捕獲詳解

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

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

如果對Promise和trycatch不夠理解的話,很多時候會出現(xiàn)Promise中的錯誤無法被捕獲的情況,本文來討論這些情況

try catch

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

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

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

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

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

又或者這樣:

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

上面的代碼都無法正常捕獲到錯誤,因為:trycatch永遠(yuǎn)捕獲的是同步的錯誤

什么是同步的錯誤?

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

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

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

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

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

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

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

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

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

Promise.reject

要理解Promise.reject首先要了解它的返回值,Promise.reject返回的是一個Promise對象,請注意:是Promise對象

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

解決Promise異常捕獲

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

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

Promise.catch

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

如下:

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

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

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

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

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

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

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

例如:

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

click();

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

注意事項

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

兜底方案

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

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

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

我們再討論then方法中的第二個參數(shù)和Promise.catch方法的區(qū)別

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

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

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

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

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

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

總結(jié)

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

相關(guān)文章

  • Electron 結(jié)合 Selenium + chromedriver 驅(qū)動服務(wù)實現(xiàn)瀏覽器多開思路詳解

    Electron 結(jié)合 Selenium + chromedriver 

    這篇文章主要介紹了Electron 結(jié)合 Selenium + chromedriver 驅(qū)動服務(wù)實現(xiàn)瀏覽器多開思路詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-07-07
  • 前端JavaScript?6?種主流接口請求技術(shù)全解

    前端JavaScript?6?種主流接口請求技術(shù)全解

    這篇文章主要介紹了前端JavaScript?6?種主流接口請求技術(shù)的相關(guān)資料,包括XMLHttpRequest、FetchAPI、Axios、jQueryAjax、WebSocket和GraphQL,并提供了每種方案的基礎(chǔ)用法、高級配置、優(yōu)點、缺點及適用場景,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-03-03
  • JavaScript中的class類詳解

    JavaScript中的class類詳解

    JavaScript?中的類(Class)是一種新的語言特性,它讓我們可以使用面向?qū)ο缶幊痰乃枷雭砀臃奖愕亟M織和管理代碼。在本文中,我們將詳細(xì)介紹?JavaScript?中的類特性,感興趣的同學(xué)可以借鑒閱讀
    2023-05-05
  • js點擊出現(xiàn)場層層外點擊層消失的代碼

    js點擊出現(xiàn)場層層外點擊層消失的代碼

    主要是修復(fù)了如果層上有東東的話,點擊也消失的情況
    2008-09-09
  • JS實現(xiàn)京東首頁之頁面頂部、Logo和搜索框功能

    JS實現(xiàn)京東首頁之頁面頂部、Logo和搜索框功能

    這篇文章主要實現(xiàn)京東的頁面頂部,logo和搜索框功能,本文有效果展示,頁面布局詳細(xì)分析,具體實現(xiàn)代碼,介紹的非常詳細(xì),具有參考借鑒價值,需要的的朋友參考下吧
    2017-01-01
  • JS實現(xiàn)按鈕控制計時開始和停止功能

    JS實現(xiàn)按鈕控制計時開始和停止功能

    這篇文章給大家介紹了JS實現(xiàn)按鈕控制計時開始和停止功能,代碼簡單易懂,非常不錯,具有參考借鑒價值,需要的朋友參考下吧
    2017-07-07
  • 用js實現(xiàn)計算加載頁面所用的時間

    用js實現(xiàn)計算加載頁面所用的時間

    用js實現(xiàn)計算加載頁面所用的時間的代碼,需要的朋友可以參考下。
    2010-04-04
  • 原生JS實現(xiàn)pc端輪播圖效果

    原生JS實現(xiàn)pc端輪播圖效果

    這篇文章主要為大家詳細(xì)介紹了原生JS實現(xiàn)pc端輪播圖效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • JavaScript“盡快失敗”的原則實例詳解

    JavaScript“盡快失敗”的原則實例詳解

    我第一次聽說編碼原則中有“盡快失敗”這一條時,覺得很奇怪,為什么代碼要失???應(yīng)該成功才對呀。下面小編通過實例代碼給大家介紹js 盡快失敗的原則,一起看看吧
    2016-10-10
  • js 調(diào)用本地exe的例子(支持IE內(nèi)核的瀏覽器)

    js 調(diào)用本地exe的例子(支持IE內(nèi)核的瀏覽器)

    js 調(diào)用本地exe程序.我實驗了一下 : 使用IE內(nèi)核的瀏覽器 都支持 火狐好像不行,感興趣的碰可以研究下
    2012-12-12

最新評論

葵青区| 富顺县| 灵武市| 庆云县| 茌平县| 眉山市| 扎鲁特旗| 祁门县| 沧源| 京山县| 自贡市| 丰都县| 衡水市| 兰溪市| 清镇市| 兴和县| 建昌县| 许昌市| 崇阳县| 抚州市| 玉林市| 利川市| 巴东县| 新巴尔虎右旗| 甘肃省| 大理市| 古蔺县| 潜江市| 元江| 南乐县| 台南市| 广元市| 门头沟区| 石河子市| 甘洛县| 盱眙县| 南城县| 二连浩特市| 娱乐| 普洱| 垣曲县|