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

React如何優(yōu)雅的捕獲異常

 更新時(shí)間:2021年06月18日 10:07:23   作者:云的世界  
捕獲異常是來(lái)定位你錯(cuò)誤代碼的。本文主要介紹了 React如何捕獲異常,你知道多少種方法,ErrorBoundary,ErrorBoundary-try-catch等等。本文就來(lái)詳細(xì)的介紹一下

前言

人無(wú)完人,所以代碼總會(huì)出錯(cuò),出錯(cuò)并不可怕,關(guān)鍵是怎么處理。
我就想問(wèn)問(wèn)大家react的應(yīng)用的錯(cuò)誤怎么捕捉呢? 這個(gè)時(shí)候:

  • 小白+++:怎么處理?
  • 小白++: ErrorBoundary
  • 小白+: ErrorBoundary, try catch
  • 小黑#:  ErrorBoundary, try catch, window.onerror
  • 小黑##: 這個(gè)是個(gè)嚴(yán)肅的問(wèn)題,我知道N種處理方式,你有什么更好的方案?

ErrorBoundary

EerrorBoundary是16版本出來(lái)的,有人問(wèn)那我的15版本呢,我不聽(tīng)我不聽(tīng),反正我用16,當(dāng)然15有unstable_handleError

關(guān)于ErrorBoundary官網(wǎng)介紹比較詳細(xì),這個(gè)不是重點(diǎn),重點(diǎn)是他能捕捉哪些異常。

  • 子組件的渲染
  • 生命周期函數(shù)
  • 構(gòu)造函數(shù)
  • class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

開(kāi)源世界就是好,早有大神封裝了react-error-boundary 這種優(yōu)秀的庫(kù)。
你只需要關(guān)心出現(xiàn)錯(cuò)誤后需要關(guān)心什么,還以來(lái)個(gè) Reset, 完美。

import {ErrorBoundary} from 'react-error-boundary'

function ErrorFallback({error, resetErrorBoundary}) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre>{error.message}</pre>
      <button onClick={resetErrorBoundary}>Try again</button>
    </div>
  )
}

const ui = (
  <ErrorBoundary
    FallbackComponent={ErrorFallback}
    onReset={() => {
      // reset the state of your app so the error doesn't happen again
    }}
  >
    <ComponentThatMayError />
  </ErrorBoundary>
)

遺憾的是,error boundaries并不會(huì)捕捉這些錯(cuò)誤:

  • 事件處理程序
  • 異步代碼 (e.g. setTimeout or requestAnimationFrame callbacks)
  • 服務(wù)端的渲染代碼
  • error boundaries自己拋出的錯(cuò)誤

原文可見(jiàn)參見(jiàn)官網(wǎng)introducing-error-boundaries

本文要捕獲的就是 事件處理程序的錯(cuò)誤。
官方其實(shí)也是有方案的how-about-event-handlers, 就是 try catch.

但是,那么多事件處理程序,我的天,得寫多少,。。。。。。。。。。。。。。。。。。。。

  handleClick() {
    try {
      // Do something that could throw
    } catch (error) {
      this.setState({ error });
    }
  }

Error Boundary 之外

我們先看看一張表格,羅列了我們能捕獲異常的手段和范圍。

異常類型 同步方法 異步方法 資源加載 Promise async/await
try/catch
window.onerror
error
unhandledrejection

try/catch

可以捕獲同步和async/await的異常。

window.onerror , error事件

    window.addEventListener('error', this.onError, true);
    window.onerror = this.onError

window.addEventListener('error') 這種可以比 window.onerror 多捕獲資源記載異常.
請(qǐng)注意最后一個(gè)參數(shù)是 true, false的話可能就不如你期望。
當(dāng)然你如果問(wèn)題這第三個(gè)參數(shù)的含義,我就有點(diǎn)不想理你了。拜。

unhandledrejection

請(qǐng)注意最后一個(gè)參數(shù)是 true。

window.removeEventListener('unhandledrejection', this.onReject, true)

其捕獲未被捕獲的Promise的異常。

XMLHttpRequest 與 fetch

XMLHttpRequest 很好處理,自己有onerror事件。
當(dāng)然你99.99%也不會(huì)自己基于XMLHttpRequest封裝一個(gè)庫(kù), axios 真香,有這完畢的錯(cuò)誤處理機(jī)制。
至于fetch, 自己帶著catch跑,不處理就是你自己的問(wèn)題了。
這么多,太難了。
還好,其實(shí)有一個(gè)庫(kù)react-error-catch 是基于ErrorBoudary,error與unhandledrejection封裝的一個(gè)組件。
其核心如下

   ErrorBoundary.prototype.componentDidMount = function () {
        // event catch
        window.addEventListener('error', this.catchError, true);
        // async code
        window.addEventListener('unhandledrejection', this.catchRejectEvent, true);
    };

使用:

import ErrorCatch from 'react-error-catch'

const App = () => {
  return (
  <ErrorCatch
      app="react-catch"
      user="cxyuns"
      delay={5000}
      max={1}
      filters={[]}
      onCatch={(errors) => {
        console.log('報(bào)錯(cuò)咯');
        // 上報(bào)異常信息到后端,動(dòng)態(tài)創(chuàng)建標(biāo)簽方式
        new Image().src = `http://localhost:3000/log/report?info=${JSON.stringify(errors)}`
      }}
    >
      <Main />
    </ErrorCatch>)
}

export default

鼓掌,鼓掌。
其實(shí)不然: 利用error捕獲的錯(cuò)誤,其最主要的是提供了錯(cuò)誤堆棧信息,對(duì)于分析錯(cuò)誤相當(dāng)不友好,尤其打包之后。
錯(cuò)誤那么多,我就先好好處理React里面的事件處理程序。
至于其他,待續(xù)。

事件處理程序的異常捕獲

示例

我的思路原理很簡(jiǎn)單,使用decorator來(lái)重寫原來(lái)的方法。
先看一下使用:

   @methodCatch({ message: "創(chuàng)建訂單失敗", toast: true, report:true, log:true })
    async createOrder() {
        const data = {...};
        const res = await createOrder();
        if (!res || res.errCode !== 0) {
            return Toast.error("創(chuàng)建訂單失敗");
        }
        
        .......
        其他可能產(chǎn)生異常的代碼
        .......
        
       Toast.success("創(chuàng)建訂單成功");
    }

注意四個(gè)參數(shù):

  • message: 出現(xiàn)錯(cuò)誤時(shí),打印的錯(cuò)誤
  • toast: 出現(xiàn)錯(cuò)誤,是否Toast
  • report: 出現(xiàn)錯(cuò)誤,是否上報(bào)
  • log: 使用使用console.error打印

可能你說(shuō),這這,消息定死,不合理啊。我要是有其他消息呢。
此時(shí)我微微一笑別急, 再看一段代碼

  @methodCatch({ message: "創(chuàng)建訂單失敗", toast: true, report:true, log:true })
    async createOrder() {
        const data = {...};
        const res = await createOrder();
        if (!res || res.errCode !== 0) {
            return Toast.error("創(chuàng)建訂單失敗");
        }
       
        .......
        其他可能產(chǎn)生異常的代碼
        .......
        
       throw new CatchError("創(chuàng)建訂單失敗了,請(qǐng)聯(lián)系管理員", {
           toast: true,
           report: true,
           log: false
       })
       
       Toast.success("創(chuàng)建訂單成功");

    }

是都,沒(méi)錯(cuò),你可以通過(guò)拋出 自定義的CatchError來(lái)覆蓋之前的默認(rèn)選項(xiàng)。
這個(gè)methodCatch可以捕獲,同步和異步的錯(cuò)誤,我們來(lái)一起看看全部的代碼。

類型定義

export interface CatchOptions {
    report?: boolean;
    message?: string;
    log?: boolean;
    toast?: boolean;
}

// 這里寫到 const.ts更合理
export const DEFAULT_ERROR_CATCH_OPTIONS: CatchOptions = {
    report: true,
    message: "未知異常",
    log: true,
    toast: false
}

自定義的CatchError

import { CatchOptions, DEFAULT_ERROR_CATCH_OPTIONS } from "@typess/errorCatch";

export class CatchError extends Error {

    public __type__ = "__CATCH_ERROR__";
    /**
     * 捕捉到的錯(cuò)誤
     * @param message 消息
     * @options 其他參數(shù)
     */
    constructor(message: string, public options: CatchOptions = DEFAULT_ERROR_CATCH_OPTIONS) {
        super(message);
    }
}

裝飾器

import Toast from "@components/Toast";
import { CatchOptions, DEFAULT_ERROR_CATCH_OPTIONS } from "@typess/errorCatch";
import { CatchError } from "@util/error/CatchError";


const W_TYPES = ["string", "object"];
export function methodCatch(options: string | CatchOptions = DEFAULT_ERROR_CATCH_OPTIONS) {

    const type = typeof options;

    let opt: CatchOptions;

    
    if (options == null || !W_TYPES.includes(type)) { // null 或者 不是字符串或者對(duì)象
        opt = DEFAULT_ERROR_CATCH_OPTIONS;
    } else if (typeof options === "string") {  // 字符串
        opt = {
            ...DEFAULT_ERROR_CATCH_OPTIONS,
            message: options || DEFAULT_ERROR_CATCH_OPTIONS.message,
        }
    } else { // 有效的對(duì)象
        opt = { ...DEFAULT_ERROR_CATCH_OPTIONS, ...options }
    }

    return function (_target: any, _name: string, descriptor: PropertyDescriptor): any {

        const oldFn = descriptor.value;

        Object.defineProperty(descriptor, "value", {
            get() {
                async function proxy(...args: any[]) {
                    try {
                        const res = await oldFn.apply(this, args);
                        return res;
                    } catch (err) {
                        // if (err instanceof CatchError) {
                        if(err.__type__ == "__CATCH_ERROR__"){
                            err = err as CatchError;
                            const mOpt = { ...opt, ...(err.options || {}) };

                            if (mOpt.log) {
                                console.error("asyncMethodCatch:", mOpt.message || err.message , err);
                            }

                            if (mOpt.report) {
                                // TODO::
                            }

                            if (mOpt.toast) {
                                Toast.error(mOpt.message);
                            }

                        } else {
                            
                            const message = err.message || opt.message;
                            console.error("asyncMethodCatch:", message, err);

                            if (opt.toast) {
                                Toast.error(message);
                            }
                        }
                    }
                }
                proxy._bound = true;
                return proxy;
            }
        })
        return descriptor;
    }
}

總結(jié)一下

利用裝飾器重寫原方法,達(dá)到捕獲錯(cuò)誤的目的
自定義錯(cuò)誤類,拋出它,就能達(dá)到覆蓋默認(rèn)選項(xiàng)的目的。增加了靈活性。

  @methodCatch({ message: "創(chuàng)建訂單失敗", toast: true, report:true, log:true })
    async createOrder() {
        const data = {...};
        const res = await createOrder();
        if (!res || res.errCode !== 0) {
            return Toast.error("創(chuàng)建訂單失敗");
        }
       Toast.success("創(chuàng)建訂單成功");
       
        .......
        其他可能產(chǎn)生異常的代碼
        .......
        
       throw new CatchError("創(chuàng)建訂單失敗了,請(qǐng)聯(lián)系管理員", {
           toast: true,
           report: true,
           log: false
       })
    }

下一步

啥下一步,走一步看一步啦。
不,接下來(lái)的路,還很長(zhǎng)。  這才是一個(gè)基礎(chǔ)版本。

擴(kuò)大成果

@XXXCatch
classs AAA{
    @YYYCatch
    method = ()=> {
    }
}

抽象,再抽象,再抽象

再見(jiàn)。

寫在最后

error-boundaries
React異常處理
catching-react-errors
react進(jìn)階之異常處理機(jī)制-error Boundaries
decorator
core-decorators
autobind.js

到此這篇關(guān)于React如何優(yōu)雅的捕獲異常的文章就介紹到這了,更多相關(guān)React 捕獲異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • React Hooks使用方法全方位介紹

    React Hooks使用方法全方位介紹

    在react類組件(class)寫法中,有setState和生命周期對(duì)狀態(tài)進(jìn)行管理,但是在函數(shù)組件中不存在這些,故引入hooks(版本:>=16.8),使開(kāi)發(fā)者在非class的情況下使用更多react特性
    2023-03-03
  • React-Router如何進(jìn)行頁(yè)面權(quán)限管理的方法

    React-Router如何進(jìn)行頁(yè)面權(quán)限管理的方法

    本篇文章主要介紹了React-Router如何進(jìn)行頁(yè)面權(quán)限管理的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • React組件的應(yīng)用介紹

    React組件的應(yīng)用介紹

    React組件分為函數(shù)組件與class組件;函數(shù)組件是無(wú)狀態(tài)組件,class稱為類組件;函數(shù)組件只有props,沒(méi)有自己的私有數(shù)據(jù)和生命周期函數(shù);class組件有自己私有數(shù)據(jù)(this.state) 和 生命周期函數(shù)
    2022-09-09
  • react 權(quán)限樹形結(jié)構(gòu)實(shí)現(xiàn)代碼

    react 權(quán)限樹形結(jié)構(gòu)實(shí)現(xiàn)代碼

    這篇文章主要介紹了react 權(quán)限樹形結(jié)構(gòu)實(shí)現(xiàn)代碼,項(xiàng)目背景react + ant design,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧
    2024-05-05
  • React中多語(yǔ)言的配置方式

    React中多語(yǔ)言的配置方式

    這篇文章主要介紹了React中多語(yǔ)言的配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • react native環(huán)境安裝流程

    react native環(huán)境安裝流程

    React Native 是目前流行的跨平臺(tái)移動(dòng)應(yīng)用開(kāi)發(fā)框架之一。本文介紹react native環(huán)境安裝流程及遇到問(wèn)題解決方法,感興趣的朋友一起看看吧
    2021-05-05
  • react調(diào)試和測(cè)試代碼的小技巧

    react調(diào)試和測(cè)試代碼的小技巧

    在開(kāi)發(fā)React應(yīng)用時(shí),嚴(yán)格模式StrictMode可以幫助開(kāi)發(fā)者捕捉到組件中的錯(cuò)誤和潛在問(wèn)題,安裝React Developer Tools瀏覽器擴(kuò)展檢查組件的props和狀態(tài),直接修改以及分析性能,@testing-library/react和Cypress或Playwright等工具可以有效地測(cè)試React組件和執(zhí)行端到端測(cè)試
    2024-10-10
  • React?Hook?四種組件優(yōu)化總結(jié)

    React?Hook?四種組件優(yōu)化總結(jié)

    這篇文章主要介紹了React?Hook四種組件優(yōu)化總結(jié),文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)孩子,需要的朋友可以參考一下
    2022-07-07
  • React文件分段上傳實(shí)現(xiàn)方法詳解

    React文件分段上傳實(shí)現(xiàn)方法詳解

    這篇文章主要介紹了React文件分段上傳實(shí)現(xiàn)方法,將文件切成多個(gè)小的文件;將切片并行上傳;所有切片上傳完成后,服務(wù)器端進(jìn)行切片合成;當(dāng)分片上傳失敗,可以在重新上傳時(shí)進(jìn)行判斷,只上傳上次失敗的部分實(shí)現(xiàn)斷點(diǎn)續(xù)傳;當(dāng)切片合成為完整的文件,通知客戶端上傳成功
    2022-11-11
  • 詳解基于React.js和Node.js的SSR實(shí)現(xiàn)方案

    詳解基于React.js和Node.js的SSR實(shí)現(xiàn)方案

    這篇文章主要介紹了詳解基于React.js和Node.js的SSR實(shí)現(xiàn)方案,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03

最新評(píng)論