Stories

Detail Return Return

React請求機制優化思路 | 京東雲技術團隊 - Stories Detail

説起數據加載的機制,有一個繞不開的話題就是前端性能,很多電商門户的首頁其實都會做一些垂直的定製優化,比如讓請求在頁面最早加載,或者在前一個頁面就進行預加載等等。隨着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 Avatar buildyuan Avatar chaochenyinshi Avatar wisdomqq Avatar niandou Avatar kalii Avatar doupifaner Avatar jibvxiz Avatar cloudyttt Avatar luomg1995 Avatar sorra Avatar njwutong Avatar
Favorites 14 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.