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

JS前端白屏前世今生及解決方式

 更新時(shí)間:2023年08月14日 10:32:53   作者:包邦東  
這篇文章主要為大家介紹了JS前端白屏前世今生及解決方式案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

白屏(Blank Screen),它無(wú)所不及,摧枯拉朽,令用戶體感全失、測(cè)試提 P0 相見(jiàn)、研發(fā)不寒而栗,膽戰(zhàn)心驚,只知匆忙回滾。

對(duì)于離用戶最近的前端,更是重災(zāi)區(qū),瀏覽器上只要出現(xiàn)白屏,先找前端準(zhǔn)沒(méi)錯(cuò)。

近期工作中頻頻遇到線上白屏事故,我借這個(gè)機(jī)遇,介紹為什么會(huì)產(chǎn)生白屏,以及應(yīng)對(duì)之道。

兵法著:知彼知己,百戰(zhàn)不殆;不知彼知己,一勝一負(fù),不知彼不知己,每戰(zhàn)必殆。

只有足夠了解白屏,了解自身代碼的局限性,才能云淡風(fēng)輕,編程游刃有余。

白屏從何而來(lái)

導(dǎo)致白屏的原因,大概率分為兩種:

  • 資源訪問(wèn)錯(cuò)誤
  • 代碼執(zhí)行錯(cuò)誤

兩者雖然“各有千秋”,但從現(xiàn)代前端視角來(lái)看,都和 SPA 框架的廣泛應(yīng)用逃不了干系。

資源訪問(wèn)錯(cuò)誤

這里的資源特指 JavaScript 腳本、樣式表、圖片等靜態(tài)資源,不包括服務(wù)調(diào)用等動(dòng)態(tài)資源。

最典型的例子莫過(guò)于 React、Vue 等 SPA 框架構(gòu)建的 Web 應(yīng)用,一旦 [bundle|app].js 因?yàn)榫W(wǎng)絡(luò)原因訪問(wèn)失敗,便會(huì)引發(fā)頁(yè)面白屏。

你可以訪問(wèn) https://vue-ebgcbmiy3-b2d1.vercel.app/,按照如下步驟復(fù)現(xiàn):打開(kāi) DevTools > Network,找到 app.3b315b6b.js,右鍵并選中 Block request URL,隨后刷新頁(yè)面。

代碼執(zhí)行出錯(cuò)

如果說(shuō)資源訪問(wèn)錯(cuò)誤還有回旋的余地,可能用戶的網(wǎng)絡(luò)不穩(wěn)定,重試幾次便能恢復(fù)正常。

那么在 render 過(guò)程中,代碼執(zhí)行出錯(cuò)無(wú)異于被宣判死刑,包括但不限于:

  • 讀取 undefined null 的屬性,null.a;
  • 對(duì)普通對(duì)象進(jìn)行函數(shù)調(diào)用,const o = {}; o();
  • 將 null undefined 傳遞給 Object.keys,Object.keys(null);
  • JSON 反序列化接受到非法值,JSON.parse({});

你必須經(jīng)歷本地調(diào)試,CI、CD,構(gòu)建部署等一系列措施、或者直接 rollback.

為什么 read properties of undefined 就白屏了?

先請(qǐng)教一個(gè)問(wèn)題,試問(wèn)以下代碼的執(zhí)行是否會(huì)導(dǎo)致頁(yè)面白屏?

為了擺脫框架的約束,我特意使用原生 JavaScript、以命令式的編程范式動(dòng)態(tài)渲染一個(gè)網(wǎng)頁(yè)。

<body>
  <div id="root"></div>
  <script>
    const arr = ["webpack", "rollup", "parcel"];
    const root = document.getElementById("root");
    const ul = document.createElement("ul");
    for (let i = 0; i <= arr.length - 1; i++) {
      const li = document.createElement("li");
      li.innerHTML = arr[i];
      ul.appendChild(li);
    }
    root.appendChild(ul);
    const h1 = document.createElement("h1");
    // trigger read properties of undefined
    h1.textContent = document.createTextNode({}.a.b);
    root.appendChild(h1);
  </script>
</body>

瀏覽器的真實(shí)表現(xiàn)是 ul 被正常渲染,而 h1 直接不渲染,兩者互不影響,更不會(huì)導(dǎo)致白屏。

把視角切回 React,我們將渲染 ul h1 的過(guò)程類比為渲染 <Ul /> 組件 和 <H1 /> 組件,看看會(huì)發(fā)生什么?

const Ul = () => (
  <ul>
    {["webpack", "rollup", "parcel"].map((v) => (
      <li>{v}</li>
    ))}
  </ul>
);
// trigger read properties of undefined
const H1 = () => <h1>{{}.a.b}</h1>;
const App = () => {
  return (
    <>
      <Ul />
      <H1 />
    </>
  );
};
ReactDOM.render(<App />, document.getElementById("root"));

毫無(wú)意外,頁(yè)面呈現(xiàn)白屏狀態(tài),<H1 /> 的渲染錯(cuò)誤致使整個(gè) <App /> 都崩潰了。

根本原因是自 React 16 起,任何未被錯(cuò)誤邊界捕獲的錯(cuò)誤將會(huì)導(dǎo)致整個(gè) React 組件樹(shù)被卸載

翻譯一下就是如果在組件的渲染期間內(nèi),發(fā)生了 Uncaught Errors,而又未被 Error Boundaries 捕獲,整個(gè) <App /> 所表示的 DOM 結(jié)構(gòu)都被會(huì)移除,如下所示:

ReactDOM.render(null, document.getElementById("root"));

React 用白屏真正詮釋了什么叫唇寒齒亡,牽一發(fā)而動(dòng)全身,這也驗(yàn)證了我之前的說(shuō)法,現(xiàn)代 Web 應(yīng)用頻繁白屏和 SPA 框架逃不了干系。

但你能說(shuō)這個(gè)機(jī)制是負(fù)向優(yōu)化的嗎?官方說(shuō)法是:

我們對(duì)這一決定有過(guò)一些爭(zhēng)論,但根據(jù)我們的經(jīng)驗(yàn),把一個(gè)錯(cuò)誤的 UI 留在那比完全移除它要更糟糕。例如,在類似 Messenger 的產(chǎn)品中,把一個(gè)異常的 UI 展示給用戶可能會(huì)導(dǎo)致用戶將信息錯(cuò)發(fā)給別人。同樣,對(duì)于支付類應(yīng)用而言,顯示錯(cuò)誤的金額也比不呈現(xiàn)任何內(nèi)容更糟糕。

我越來(lái)越相信,前端層出不窮的框架或是新技術(shù),雖然它的 leverage 足夠大,但背后隱含著 trade-off,在絕大多數(shù)場(chǎng)景下表現(xiàn)優(yōu)異,在另一些場(chǎng)景下你也必須要接受它的“規(guī)則”。

為什么不能是 ? 屏、?? 屏?

既然 DOM 都被移除了,只剩下個(gè)光禿禿的 div#app 節(jié)點(diǎn),加上 body 的默認(rèn)背景顏色是 #FFF,理所應(yīng)當(dāng)白屏。

<body>
<div id="app"></div>
<script src="/js/chunk-vendors.61a12961.js"></script>
<script src="/js/app.3b315b6b.js"></script>
</body>

因此,不僅黑屏、藍(lán)屏可以實(shí)現(xiàn),只要將 body 的背景顏色稍作調(diào)整,彩虹屏也可以實(shí)現(xiàn),彼時(shí)復(fù)盤文檔的標(biāo)題名為 「XXX 引發(fā)彩虹屏」,活成了前端喜劇人的樣子。

我認(rèn)為白屏只是一種代號(hào),引申的含義是頁(yè)面無(wú)內(nèi)容渲染。

我還想強(qiáng)調(diào),白屏只是一種外在表現(xiàn)形式,內(nèi)在錯(cuò)誤已經(jīng)發(fā)生,不可挽回,肯定會(huì)給用戶帶來(lái)功能上的影響,只不過(guò)白屏的視覺(jué)沖擊力最強(qiáng),大腦直覺(jué)反饋十分嚴(yán)重。

如何降低白屏的“破壞力”

不再贅述如何避免白屏,因?yàn)殄e(cuò)誤時(shí)時(shí)刻刻會(huì)發(fā)生,我們能做的是盡人事,遵循以下原則:

  • 依賴不可信,npm 的 Breaking Change
  • 調(diào)用不可信,HTTP/RPC 等 API 調(diào)用不僅會(huì)失敗,還會(huì)返回約定之外的數(shù)據(jù),不兼容過(guò)時(shí)版本
  • 輸入不可信,用戶常常會(huì)輸入一些邊界值、非法值 能盡可能避免異常。

我們關(guān)注的是錯(cuò)誤已經(jīng)發(fā)生的窘境下,如何及時(shí)補(bǔ)救,把外在的不良表現(xiàn)弱化成用戶可以接受,或者無(wú)感知的狀態(tài)。

借助于 ErrorBoundary,它能捕獲任意子組件在渲染期間發(fā)生的 Uncaught Errors,從而避免整體組件樹(shù)的卸載,把白屏扼殺在搖籃中。

除此之外,它還能對(duì)渲染錯(cuò)誤的組件做兜底,具體的處理措施有兩種:熔斷和降級(jí)。

組件 “熔斷”

熔斷機(jī)制指的是在股票市場(chǎng)的交易時(shí)間中,當(dāng)價(jià)格波動(dòng)的幅度達(dá)到某一個(gè)限定的目標(biāo)(熔斷點(diǎn))時(shí),對(duì)其暫停交易一段時(shí)間的機(jī)制。 此機(jī)制如同保險(xiǎn)絲在電流過(guò)大時(shí)候熔斷,避免引發(fā)更大的事故,因此得名。

它被大量應(yīng)用于容災(zāi)體系,對(duì)應(yīng) React 體系中,熔斷點(diǎn)等同于渲染錯(cuò)誤發(fā)生,暫定交易等同于卸載組件,直接不渲染,舍車保帥。

直接看例子:

import { ErrorBoundary } from "react-error-boundary";
const Other = () => <h1>I AM OTHER</h1>;
const Bug = () => {
  const [val, setVal] = useState({});
  const triggerError = () => {
    setVal(undefined);
  };
  return (
    <>
      <button onClick={triggerError}>trigger render error</button>
      <h1>I HAVE BUG, DO NOT CLICK ME</h1>
      {Object.keys(val)}
    </>
  );
};
const App = () => (
  <>
    <Other />
    <ErrorBoundary fallbackRender={() => null}>
      <Bug />
    </ErrorBoundary>
  </>
);

組件優(yōu)雅降級(jí)

優(yōu)雅降級(jí)指使用 替代渲染出錯(cuò)的組件,并做符合功能場(chǎng)景,用戶心智的提示。

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 App = () => (
  <>
    <Other />
    <ErrorBoundary fallbackRender={ErrorFallback}>
      <Bug />
    </ErrorBoundary>
  </>
);

以上 demo 所選擇的錯(cuò)誤邊界庫(kù)為 https://github.com/bvaughn/react-error-boundary,可在生產(chǎn)環(huán)境中投入使用。

前提是大家都要有對(duì)每個(gè)組件加上錯(cuò)誤邊界的共識(shí),配合團(tuán)隊(duì)內(nèi)部的監(jiān)控上報(bào)和 Lint 檢測(cè),才能最大限度降低白屏的“破壞力”,打造一個(gè)穩(wěn)定性更強(qiáng)的線上環(huán)境。

題外話:主動(dòng) throw error 導(dǎo)致白屏

我寧愿犯錯(cuò),也不愿什么也不做。

這一點(diǎn)我和 React Team 的觀點(diǎn)相同,與其展示錯(cuò)誤的 UI,不如不展示。

錯(cuò)誤的 UI,隨時(shí)是個(gè)定時(shí)炸彈,在特定情況下就會(huì)爆炸,試想用戶在錯(cuò)誤的界面進(jìn)行操作,小則造成 BUG,大則造成經(jīng)濟(jì)損失、安全泄露,會(huì)帶來(lái)不可損失的影響,所以遇到對(duì)于非預(yù)期的行為,一定要主動(dòng) throw error,并做好組件熔斷及降級(jí)。

以上就是JS前端白屏前世今生及解決方式的詳細(xì)內(nèi)容,更多關(guān)于JS前端白屏解決的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論