動態

詳情 返回 返回

React請求機制優化思路 | 京東雲技術團隊 - 動態 詳情

説起數據加載的機制,有一個繞不開的話題就是前端性能,很多電商門户的首頁其實都會做一些垂直的定製優化,比如讓請求在頁面最早加載,或者在前一個頁面就進行預加載等等。隨着react18的發佈,請求機制這一塊也是被不斷談起,並且在後續其實也給出了明確的方向。

假如我們頁面中有三個組件C1、C2、C3依次嵌套,每個組件中有對應的請求F1、F2、F3,通常大多數人會使用useeffect和state變量來實現數據流的獲取,這樣就意味着必須在組件加載時才能發起請求,所有數據獲取都發生在組件的生命週期中,如下圖所示,我們可以將這種獲取數據的方式稱作瀑布流渲染,但是這種方式有一個問題是,在這種方法中,組件之間的數據獲取是按順序進行的,這實際上意味着它們彼此阻塞,如果組件的層級嵌套很深的話,就會導致頁面的加載時間特別長。

render then fetch.png

為了阻止組件間數據獲取的這種順序阻塞,另一種方法就是在組件加載前可以使用Promise.all獲取所有的請求數據,這樣在組件加載時就已經獲取到所有的數據了。這種方式解決了組件加載順序阻塞彼此數據流獲取的問題,但是也產生了一個新的問題,在請求完成之前頁面都會是空白的。

先請求再渲染.png

基於第二種先請求後渲染的方式,還可以使用Suspense將請求和渲染並行化,Suspense 可以使得組件可以“等待”某些操作結束後,再進行渲染。而這種方式如果要用到實際項目中,還需要考慮C1、C2、C3對應的請求寫在哪裏,如果寫在組件中,那麼加載還是慢的。如果拆分出來,就需要考慮文件拆分、code splitting等工程化問題。

邊請求邊渲染.png

在認真的分析了以上三種方式以後,發現各有優劣,同時基於上述方案,我也提供一個請求優化的思路,首先將請求的JS單獨拆分出來打一個文件request.js,在html頭部引入request.js並使用async屬性讓腳本並行執行(如下代碼所示),這樣既可以保證我們的請求在最開始就能發出,也能不阻塞後續React代碼打包的js文件的執行,相當請求和渲染的代碼在並行執行。

// html頭部引入request.js
<script async src="/js/request.js"></script>

在發送完請求之後,需要將返回的數據注入到React組件中,這部分怎麼注入呢?簡單的代碼示例如下:

// request.js 中請求部分 evt是發佈訂閲模式的一個實例
window.InitData = {
    data: null,
    on: (msg, fn) => evt.on(msg, e => fn(e)),
    emit: (msg, data) => evt.emit(msg, data),
};

fetch().then(rs => {
    InitData.data = rs;
    InitData.emit("init_data", rs);
    return rs;
});
// index.js react代碼邏輯

…….

useEffect(() => {
    if (InitData.data !== null) {
        // 這裏已經獲取到了請求的返回值
        doSomething();
    } else {
        InitData.on("init_data", (data) => {            
            // 利用發佈訂閲模式獲取到數據
            doSomething();
        });
    }
}, []);

…….

總體思路就是在html中最先加載單獨打包出來的請求文件並加入async屬性使腳本並行執行,將返回的數據掛載到window下或者利用發佈訂閲模式將數據注入到react組件中。這樣其實類似於邊請求邊渲染的模式,利用提前請求來減少加載的時間。後續也是希望能用工程化的方式去解決數據的請求機制。

未來的話在開發時肯定是更傾向於邊請求邊渲染的這種模式,在React的官網中也有説到未來計劃讓Suspense 處理更多的場景,包括獲取數據等等,在新發布的React18中Suspense也是支持了服務端渲染,包括近期開源的remix也都在優化請求機制能夠讓應用更快的加載。也歡迎有興趣的小夥伴一起來討論和實踐。

作者:京東零售 梁峯峯

來源:京東雲開發者社區

user avatar san-mu 頭像 buildyuan 頭像 chaochenyinshi 頭像 wisdomqq 頭像 niandou 頭像 kalii 頭像 doupifaner 頭像 jibvxiz 頭像 cloudyttt 頭像 luomg1995 頭像 sorra 頭像 njwutong 頭像
點贊 14 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.