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

React?中的?JS?報錯及容錯方案

 更新時間:2023年08月14日 10:57:39   作者:Grewer  
這篇文章主要為大家介紹了React?中的?JS?報錯及容錯方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

導(dǎo)致白屏的原因大概有兩種,一為資源的加載,二為 JS 執(zhí)行出錯

本文就 JS 中執(zhí)行的報錯,會比較容易造成"白屏"場景,和能解決這些問題的一些方法,作出一個匯總

常見的錯誤

SyntaxError

SyntaxError(語法錯誤)對象代表嘗試解析不符合語法的代碼的錯誤。當(dāng) Javascript 引擎解析代碼時,遇到了不符合語法規(guī)范的標(biāo)記(token)或標(biāo)記順序,則會拋出 SyntaxError

這里陳列下 SyntaxError 的常見錯誤

保留字錯誤

SyntaxError: "x" is a reserved identifier (Firefox)

SyntaxError: Unexpected reserved word (Chrome)

如在控制臺執(zhí)行下方代碼,則會上述錯誤出現(xiàn)

const enum = 1

enum 在嚴格模式和非嚴格模式下都是保留字。

而以下標(biāo)記符只會在嚴格模式下才作為保留字:

  • implements
  • interface
  • let
  • package
  • private
  • protected
  • public
  • static

例如:

const implements = 1 // ?
"use strict";
const implements = 1; // caught SyntaxError: Unexpected strict mode reserved word

命名錯誤

一個 JavaScript 標(biāo)識符必須以字母開頭,下劃線(_)或美元符號($)。他們不能以數(shù)字開頭。只有后續(xù)字符可以是數(shù)字(0-9)。

var 1life = 'foo';
// SyntaxError: identifier starts immediately after numeric literal
var foo = 1life;
// SyntaxError: identifier starts immediately after numeric literal

錯誤的標(biāo)點

在代碼中有非法的或者不期望出現(xiàn)的標(biāo)記符號出現(xiàn)在不該出現(xiàn)的位置。

“This looks like a string”;
// SyntaxError: illegal character
42 – 13;
// SyntaxError: illegal character

代碼里使用了中文的引號和橫杠,造成了解析錯誤,這里就體現(xiàn)了編輯器的重要性

JSON 解析

JSON.parse('[1, 2, 3, 4, ]');
JSON.parse('{"foo" : 1, }');
// SyntaxError JSON.parse: unexpected character
// at line 1 column 14 of the JSON data

json 解析失敗的類型有很多,這里就不贅述了,我們在進行 json 解析的時候,一定要加上 try...catch 語句來避免錯誤

分號問題

通常情況下,這個錯誤只是另一個錯誤一個導(dǎo)致的,如不正確轉(zhuǎn)義字符串,使用 var 的錯誤

const foo = 'Tom's bar';
// SyntaxError: missing ; before statement

通過其他方案聲明:

var foo = "Tom's bar";
var foo = 'Tom\'s bar';
var foo = `Tom's bar`; // 推薦這種方案

使用 var 錯誤

var array = [];
var array[0] = "there"; // SyntaxError missing ; before

類似當(dāng)前錯誤的還有很多,比如:

SyntaxError: missing ) after argument list

SyntaxError: missing ) after condition

SyntaxError: missing } after function body

SyntaxError: missing } after property list

這些都是語法的錯誤,在編輯器/IDE使用時期都能解析,但是在某些比較古老的框架下,
編輯器可能并不能識別出來他的語法,這便是此錯誤經(jīng)常出現(xiàn)的場景

SyntaxError 屬于運行時代碼錯誤,通常也是新手開發(fā)者容易犯得的錯誤 ,在 dev 時期就可以發(fā)現(xiàn),不然無法通過編譯,是屬于比較容易發(fā)現(xiàn)的問題

TypeError

TypeError(類型錯誤)對象通常(但并不只是)用來表示值的類型非預(yù)期類型時發(fā)生的錯誤。

以下情況會拋出 TypeError

  • 傳遞給運算符的操作數(shù)或傳遞給函數(shù)的參數(shù)與預(yù)期的類型不兼容;
  • 嘗試修改無法更改的值;
  • 嘗試以不適當(dāng)?shù)姆椒ㄊ褂靡粋€值。

不可迭代屬性

當(dāng)使用 for...of ,右側(cè)的值不是一個可迭代值時,或者作為數(shù)組解構(gòu)賦值時,會報此問題

例如:

const myobj = { arrayOrObjProp1: {}, arrayOrObjProp2: [42] };
const {
  arrayOrObjProp1: [value1],
  arrayOrObjProp2: [value2],
} = myobj; // TypeError: object is not iterable
const obj = { France: "Paris", England: "London" };
for (const p of obj) {
  // …
} // TypeError: obj is not iterable

JS 中有內(nèi)置的可迭代對象,如: String、Array、TypedArray、MapSet 以及 Intl.Segments (en-US),因為它們的每個 prototype 對象都實現(xiàn)了 @@iterator 方法。

Object 是不可迭代的,除非它們實現(xiàn)了迭代協(xié)議。

簡單來說,對象中缺少一個可迭代屬性: next 函數(shù)

將上述 obj 改造:

const obj = {
  France: "Paris", England: "London",
  [Symbol.iterator]() {
    // 用原生的空數(shù)組迭代器來兼容
    return [][Symbol.iterator]();
  },
};
for (const p of obj) {
  // …
}

如此可不報錯,但是也不會進入循環(huán)中

點此查看什么是迭代協(xié)議

空值問題

null.foo;
// 錯誤類型:null 沒有這個屬性
undefined.bar;
// 錯誤類型:undefined 沒有這個屬性
const foo = undefined;
foo.substring(1); // TypeError: foo is undefined

雖然看起來簡單,但是他是出現(xiàn)白屏最為頻繁的報錯原因之一

在以前我們通常這樣解決問題:

var value = null;
value && value.foo;

現(xiàn)在我們可以使用 可選鏈 Optional chaining 來解決這個問題

var value = null;
value?.foo;
// 但是他也不能用來賦值:
value?.foo = 1

可選鏈語法:

obj.val?.prop
obj.val?.[expr]
obj.func?.(args)

錯誤的函數(shù)執(zhí)行

錯誤的函數(shù)名稱:

var x = document.getElementByID("foo");
// TypeError: document.getElementByID is not a function
var x = document.getElementById("foo"); // 正確的函數(shù)

不存在的函數(shù):

var obj = { a: 13, b: 37, c: 42 };
obj.map(function(num) {
  return num * 2;
});
// TypeError: obj.map is not a function

in 的錯誤場景

在判斷一個對象中是否存在某個值時,比較常用的是一種方法是使用 in 來判斷:

var foo = { baz: "bar" };
if('baz' in foo){
  // operation 
}

因為不能確定 foo['baz'] 的具體值,所以這種方案也是不錯的,但是當(dāng) foo 的類型也不能確認的時候就會容易出現(xiàn)報錯了

var foo = null;
"bar" in foo;
// TypeError: invalid 'in' operand "foo"
"Hello" in "Hello World";
// TypeError: invalid 'in' operand "Hello World"

字符串和空值不適合使用此語法

_另外需要注意的是_,在數(shù)組中需要小心使用

const number = [2, 3, 4, 5];
3 in number // 返回 true.
2 in number // 返回 true.
5 in number // 返回 false,因為 5 不是數(shù)組上現(xiàn)有的索引,而是一個值;

因為錯誤是跟隨著不同的值類型,而數(shù)據(jù)的接收/轉(zhuǎn)變我們并不能做到 100% 的把控。
它是我們平時線上報錯最頻繁的一種類型,也是最容易造成頁面白屏的。需要保持 120% 的小心。

RangeError

RangeError 對象表示一個特定值不在所允許的范圍或者集合中的錯誤。

在以下的情況中,可能會遇到這個問題:

  • 將不允許的字符串值傳遞給 String.prototype.normalize(),或
  • 嘗試使用 Array 構(gòu)造函數(shù)創(chuàng)建一個具有不合法的長度的字符串,或
  • 傳遞錯誤值到數(shù)值計算方法(Number.toExponential()、Number.toFixed() 或 Number.toPrecision())。

這里舉幾個例子:

String.fromCodePoint("_"); // RangeError
new Array(-1); // RangeError
new Date("2014-25-23").toISOString(); // RangeError
(2.34).toFixed(-100); // RangeError
(42).toString(1);
const b = BigInt(NaN);
// RangeError: NaN cannot be converted to a BigInt because it is not an integer

總的來說 RangeError 都是因為傳入了不正確的值而導(dǎo)致的,這種情況發(fā)生的概率較小,部分數(shù)字都是自己可以手動控制或者寫死在代碼里的
除非是定制化很高的情況,比如低代碼,讓用戶隨意輸入的時候,在使用的時候,最好先做出判斷,或者加上 try...catch

ReferenceError

ReferenceError(引用錯誤)對象代表當(dāng)一個不存在(或尚未初始化)的變量被引用時發(fā)生的錯誤。

這種報錯的場景大多處于嚴格模式下,在正常情況下 "變量未定義" 這種報錯出現(xiàn)的情況較多

foo.substring(1); // ReferenceError: foo is not defined

如上,foo 未定義即直接使用,則就會出現(xiàn)報錯

還有一類報錯是賦值的問題,比如上方講過的可選鏈功能,他是不能賦值的:

foo?.bar = 123

這一類在編碼因為容易分析,一般在編輯器中就能容易發(fā)現(xiàn),所以并不會帶來很多困擾。

其他

InternalError 對象表示出現(xiàn)在 JavaScript 引擎內(nèi)部的錯誤。尚未成為任何規(guī)范的一部分,所以我們可以忽略。

EvalError 代表了一個關(guān)于 eval() 全局函數(shù)的錯誤。

他不在當(dāng)前的 ECMAScript 規(guī)范中使用,因此不會被運行時拋出。但是對象本身仍然與規(guī)范的早期版本向后兼容。

URIError 對象用來表示以一種錯誤的方式使用全局 URI 處理函數(shù)而產(chǎn)生的錯誤。

例如:

decodeURIComponent('%')
// caught URIError: URI malformed
decodeURI("%")     
// Uncaught URIError: URI malformed at decodeURI

所以使用 decodeURIComponent 函數(shù)時,需要加上 try...catch 來保持正確性

另類錯誤

unhandledrejection

當(dāng) Promise 被 reject 且沒有 reject 處理器的時候,會觸發(fā) unhandledrejection 事件;
這個時候,就會報一個錯誤:unhanled rejection;沒有堆棧信息,只能依靠行為軌跡來定位錯誤發(fā)生的時機。

window.addEventListener('unhandledrejection', event =>
{
    console.log('unhandledrejection: ', event.reason); // 打印
});
let p = Promise.reject("oops");
// 打印 unhandledrejection:  oops
// caught (in promise) oops

手動拋出錯誤

我們在書第三方庫的時候,可以手動拋出錯誤。但是throw error會阻斷程序運行,請謹慎使用。

throw new Error("出錯了!"); // caught Error: 出錯了!
throw new RangeError("出錯了,變量超出有效范圍!");
throw new TypeError("出錯了,變量類型無效!");

同樣的,此種方案我們可以使用在 Promise 的 then 中:

// 模擬一個接口的返回
Promise.resolve({code: 3000, message: '這是一個報錯!'}).then(res => {
  if (res.code !== 200) {
    throw new Error(`code 3000: ${res.message}`)
  }
  console.log(res); // 這里可以看做是執(zhí)行正常操作, 拋出錯誤時, 此處就不會執(zhí)行了
}).catch(err => {
  alert(err.message)
});

在 catch 中我們可以通過 name 來判斷不同的 Error:

try {
  throw new TypeError(`This is an Error`)
} catch (e) {
  console.log(e.name); // TypeError
}

再加上自定義的 Error,我們就可以制作更加自由的報錯信息:

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}
try {
  throw new ValidationError(`This is an Error`)
} catch (e) {
  console.log(e.name);
  // 'ValidationError'
  if (e instanceof ValidationError) {
    alert("Invalid data: " + e.message); // Invalid data: This is an Error
  }
}

在 Error 的基礎(chǔ)上我們還可以做更深入的繼承,來制作更多的自定義 Error

報錯在 react 中的影響

react 報錯按照位置,我將他分成兩類,一類是渲染報錯,另一類是執(zhí)行報錯;
渲染即 render 函數(shù)中的視圖渲染報錯,另一個則是執(zhí)行函數(shù)報錯;

函數(shù)的執(zhí)行報錯,是不會影響視圖的渲染的,即白屏,但是他會有一些不良影響,如

  • 代碼執(zhí)行暫停,部分邏輯未執(zhí)行,未能閉環(huán)整體邏輯,如點擊按鈕一直卡在 loading 中
  • 數(shù)據(jù)的渲染出現(xiàn)異常,兩邊數(shù)據(jù)對不上

在視圖渲染中(包括函數(shù)的 return) ,觸發(fā) JS 錯誤,都會渲染問題

那為什么整個頁面都會白屏呢 ?

原因是自 React 16 起,任何未被錯誤邊界捕獲的錯誤將會導(dǎo)致整個 React 組件樹被卸載。

錯誤邊界

在 react 中存在此生命周期 componentDidCatch,他會在一個子組件拋出錯誤后被調(diào)用。

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  // 最新的官方推薦, 通過此 api 獲取是否觸發(fā)錯誤
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }
  // 舊方案是在此處 setState
  componentDidCatch(error, info) {
    // Example "componentStack":
    //   in ComponentThatThrows (created by App)
    //   in ErrorBoundary (created by App)
    //   in div (created by App)
    //   in App
    logComponentStackToMyService(info.componentStack);
  }
  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}
<ErrorBoundary fallback={<p>Something went wrong</p>}>
  <Profile />
</ErrorBoundary>

這是來自官網(wǎng)的一個簡單例子,可以覆蓋子組件出錯的情況,避免本身組件或兄弟組件收到波及,而錯誤邊界組件的粒度需要開發(fā)者本身來界定

降級和熔斷

在官方的文檔中他更加推薦此組件 react-error-boundary,它有著更加豐富的使用:

他可以簡單的顯示錯誤:

function Fallback({ error }) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{ color: "red" }}>{error.message}</pre>
    </div>
  );
}
<ErrorBoundary
  FallbackComponent={Fallback}
>
  <ExampleApplication />
</ErrorBoundary>;

也可以使用重置方案:

function Fallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <p>Something went wrong:</p>
      <pre style={{ color: "red" }}>{error.message}</pre>
      <button onclick={resetErrorBoundary}></button>
    </div>
  );
}

通過此方法重置組件,避免了刷新頁面,對于用戶來說更加友好

更多使用,可以查看此處

總結(jié)

JS中有很多報錯,但是編輯器/編譯,已經(jīng)幫助我們過濾了一大部分的錯誤,但是仍然會有部分報錯會在特殊條件下出現(xiàn)

所以一方面需要充分的測試,如最大值/最小值/特殊值等等,另一方面就是需要積累經(jīng)驗,一些寫法就是容易出現(xiàn)問題,可以通過 codeReview 來預(yù)防部分問題但最終要堅守軟件開發(fā)的 不信任原則,保持 overly pessimistic (過于悲觀),把和程序有關(guān)的一切請求、服務(wù)、接口、返回值、機器、框架、中間件等等都當(dāng)做不可信的,步步為營、處處設(shè)防。

引用

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Refer...

http://www.dbjr.com.cn/article/268041.htm

http://www.dbjr.com.cn/javascript/295123kgd.htm

以上就是React 中的 JS 報錯及容錯方案的詳細內(nèi)容,更多關(guān)于React JS 報錯容錯方案的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • React元素與組件的區(qū)別示例詳解

    React元素與組件的區(qū)別示例詳解

    這篇文章主要為大家介紹了React元素與組件的區(qū)別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-11-11
  • react之umi配置國際化語言locale的踩坑記錄

    react之umi配置國際化語言locale的踩坑記錄

    這篇文章主要介紹了react之umi配置國際化語言locale的踩坑記錄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • 關(guān)于react的代理配置(可配置多個代理)

    關(guān)于react的代理配置(可配置多個代理)

    這篇文章主要介紹了關(guān)于react的代理配置(可配置多個代理),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 在React中實現(xiàn)子組件向父組件傳值的幾種方法

    在React中實現(xiàn)子組件向父組件傳值的幾種方法

    在React應(yīng)用中,組件間的通信是常見的需求,通常,父組件通過props向子組件傳遞數(shù)據(jù),但有時也需要子組件向父組件傳遞數(shù)據(jù),本文將探討如何在React中實現(xiàn)子組件向父組件傳值的幾種方法,需要的朋友可以參考下
    2025-04-04
  • 淺談箭頭函數(shù)寫法在ReactJs中的使用

    淺談箭頭函數(shù)寫法在ReactJs中的使用

    這篇文章主要介紹了淺談箭頭函數(shù)寫法在ReactJs中的使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • React中實現(xiàn)父組件調(diào)用子組件的三種方法

    React中實現(xiàn)父組件調(diào)用子組件的三種方法

    在React中,組件之間的通信是一個常見的需求,有時,我們需要從父組件調(diào)用子組件的方法,這可以通過幾種不同的方式實現(xiàn),需要的朋友可以參考下
    2024-04-04
  • 詳解React Hooks是如何工作的

    詳解React Hooks是如何工作的

    React Hooks是在React 16.8版本新增的特性,在我看了React官網(wǎng)和一些博客對React Hook的講解后還是覺得沒有g(shù)et到本質(zhì)。本篇博客通過手動實現(xiàn)useState()來了解Hook的原理和本質(zhì)。閱讀此篇博客的前提是你要知道一些 React Hooks的基本用法和使用規(guī)則,不然會看得云里霧里。
    2021-05-05
  • 使用React+SpringBoot開發(fā)一個協(xié)同編輯的表格文檔實現(xiàn)步驟

    使用React+SpringBoot開發(fā)一個協(xié)同編輯的表格文檔實現(xiàn)步驟

    隨著云計算和團隊協(xié)作的興起,協(xié)同編輯成為了許多企業(yè)和組織中必不可少的需求,本文小編就將為大家介紹如何使用React+SpringBoot簡單的開發(fā)一個協(xié)同編輯的表格文檔,感興趣的朋友一起看看吧
    2023-11-11
  • React組件里this指向了undefined原理解析

    React組件里this指向了undefined原理解析

    這篇文章主要為大家介紹了React組件里this指向了undefined原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • react組件中的constructor和super知識點整理

    react組件中的constructor和super知識點整理

    這篇文章主要介紹了react組件中的constructor和super知識點整理,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08

最新評論