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

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

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

前言

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

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

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

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

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

白屏從何而來

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

  • 資源訪問錯誤
  • 代碼執(zhí)行錯誤

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

資源訪問錯誤

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

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

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

代碼執(zhí)行出錯

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

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

  • 讀取 undefined null 的屬性,null.a;
  • 對普通對象進行函數(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 就白屏了?

先請教一個問題,試問以下代碼的執(zhí)行是否會導(dǎo)致頁面白屏?

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

<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>

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

把視角切回 React,我們將渲染 ul h1 的過程類比為渲染 <Ul /> 組件 和 <H1 /> 組件,看看會發(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"));

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

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

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

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

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

但你能說這個機制是負向優(yōu)化的嗎?官方說法是:

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

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

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

既然 DOM 都被移除了,只剩下個光禿禿的 div#app 節(jié)點,加上 body 的默認背景顏色是 #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>

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

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

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

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

不再贅述如何避免白屏,因為錯誤時時刻刻會發(fā)生,我們能做的是盡人事,遵循以下原則:

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

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

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

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

組件 “熔斷”

熔斷機制指的是在股票市場的交易時間中,當(dāng)價格波動的幅度達到某一個限定的目標(biāo)(熔斷點)時,對其暫停交易一段時間的機制。 此機制如同保險絲在電流過大時候熔斷,避免引發(fā)更大的事故,因此得名。

它被大量應(yīng)用于容災(zāi)體系,對應(yīng) React 體系中,熔斷點等同于渲染錯誤發(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)雅降級

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

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 所選擇的錯誤邊界庫為 https://github.com/bvaughn/react-error-boundary,可在生產(chǎn)環(huán)境中投入使用。

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

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

我寧愿犯錯,也不愿什么也不做。

這一點我和 React Team 的觀點相同,與其展示錯誤的 UI,不如不展示。

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

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

相關(guān)文章

最新評論