成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

如何優(yōu)化你的超大型React應(yīng)用 【原創(chuàng)精讀】

xiguadada / 1460人閱讀

摘要:往往純的單頁面應(yīng)用一般不會(huì)太復(fù)雜,所以這里不引入和等等,在后面復(fù)雜的跨平臺(tái)應(yīng)用中我會(huì)將那些技術(shù)一擁而上。構(gòu)建極度復(fù)雜,超大數(shù)據(jù)的應(yīng)用。

React為了大型應(yīng)用而生,ElectronReact-native賦予了它構(gòu)建移動(dòng)端跨平臺(tái)App和桌面應(yīng)用的能力,Taro則賦予了它一次編寫,生成多種平臺(tái)小程序和React-native應(yīng)用的能力,這里特意說下 Taro,它是國產(chǎn),文檔寫得比較不錯(cuò),而且它的升級(jí)速度比較快,有issue我看也會(huì)及時(shí)解決,他們的維護(hù)人員還是非常敬業(yè)的!


Tips:本文某些知識(shí)點(diǎn)如果介紹不對(duì)或者不全的地方歡迎指出,本文可能內(nèi)容比較多,閱讀時(shí)間花費(fèi)比較長,但是希望你可以認(rèn)真看下去,可以的話最好手把手去實(shí)現(xiàn)一些code,本文所有代碼均手寫。

本文會(huì)從原生瀏覽器環(huán)境,到跨平臺(tái)開發(fā)逐漸去深入介紹,先給一些資料

手寫React優(yōu)化腳手架帶項(xiàng)目

react-ssr的源碼

手寫Node.js原生靜態(tài)資源服務(wù)器

跨平臺(tái)Electron的demo

原生瀏覽器環(huán)境:

原生瀏覽器環(huán)境其實(shí)是最考驗(yàn)前端工程師能力的編程環(huán)境,因?yàn)槲覀兦岸舜蟛糠忠婚_始面向?yàn)g覽器編程,現(xiàn)在很多很多工作5-10年的前端,性能面板API都不知道用,怎么看調(diào)用函數(shù)分析耗時(shí)都不知道,這也是最近面試的情況,覺得有人說35歲失業(yè)的情況,是普遍存在,但是很大部分是你在混啊兄弟。

原生瀏覽器環(huán)境中使用React框架,比較常見的是制作單頁面SPA應(yīng)用:
原生的SPA應(yīng)用,分以下幾種:

CSR渲染(客戶端渲染)

SSR渲染(服務(wù)端渲染)

混合渲染(預(yù)渲染,webpack的插件預(yù)渲染,Next.js的約定式路由SSR,或者使用Node.js做中間件,做部分SSR,加快首屏渲染,或者指定路由SSR.)

下面會(huì)分別仔細(xì)介紹這幾種渲染形式的精細(xì)化渲染,以及優(yōu)缺點(diǎn):
CSR渲染

客戶端請(qǐng)求RestFul接口,接口吐回靜態(tài)資源文件

Node.js實(shí)現(xiàn)代碼

const express = require("express")
const app = express()

app.use(express.static("pulic"))//這里的public就是靜態(tài)資源的文件夾,讓客戶端拉取的,這里的代碼是前端的代碼已經(jīng)構(gòu)建完畢的代碼 

app.get("/",(req,res)=>{
 //do something 
    
})

app.listen(3000,err=>{
    if(!err)=>{
        console.log("監(jiān)聽端口號(hào)3000成功")
    }
})

客戶端收到一個(gè)HTML文件,和若干個(gè)CSS文件,以及多個(gè)javaScript文件

用戶輸入了url地址欄然后客戶端返回靜態(tài)文件,客戶端開始解析

客戶端解析文件,js代碼動(dòng)態(tài)生成頁面。(這也是為什么說單頁面應(yīng)用的SEO不友好的原因,初始它只是一個(gè)空的div標(biāo)簽的HTML文件)

判斷一個(gè)頁面是不是CSR,很大程度上可以根據(jù)右鍵點(diǎn)開查看頁面元素,如果只有一個(gè)空的div標(biāo)簽,那么大概率可以說是單頁面,CSR,客戶端渲染的網(wǎng)頁。

CSR的應(yīng)用,如何精細(xì)化渲染呢?
單頁面采取CSR形式,大都依賴框架,VueReact之類。一旦使用這類型技術(shù)架構(gòu),狀態(tài)數(shù)據(jù)集中管理,單向數(shù)據(jù)流,不可變數(shù)據(jù),路由懶加載,按需加載組件,適當(dāng)?shù)木彺鏅C(jī)制(PWA技術(shù)),細(xì)致拆分組件,單一數(shù)據(jù)來源刷新組件,這些都是我們可以精細(xì)化的方向。往往純CSR的單頁面應(yīng)用一般不會(huì)太復(fù)雜,所以這里不引入PWAweb work等等,在后面復(fù)雜的跨平臺(tái)應(yīng)用中我會(huì)將那些技術(shù)一擁而上。

單一數(shù)據(jù)來源決定組件是否刷新是精細(xì)化最重要的方向。

class app extends React.PureComponent{

    ///////
}

export default connect(
 (({xx,xxx,xxxx,xxxxx}))
////

)(app)
一旦業(yè)務(wù)邏輯非常復(fù)雜的情況下,假設(shè)我們使用的是dva集中狀態(tài)管理,同時(shí)連接這么多的狀態(tài)樹模塊,那么可能會(huì)造成狀態(tài)樹模塊中任意的數(shù)據(jù)刷新導(dǎo)致這個(gè)組件被刷新,但是其實(shí)這個(gè)組件此時(shí)是不需要刷新的。

這里可以將需要的狀態(tài)通過根組件用props傳入,精確刷新的來源,單一可變數(shù)據(jù)來源追溯性強(qiáng),也更方便debug

單向數(shù)據(jù)流不可變數(shù)據(jù),通過immutable.js這個(gè)庫實(shí)現(xiàn)

    import Immutable from require("immutable");
    var map1: Immutable.Map;
    map1 = Immutable.Map({ a: 1, b: 2, c: 3 });
    var map2 = map1.set("b", 50);
    map1.get("b"); // 2
    map2.get("b"); // 50
不可變數(shù)據(jù),數(shù)據(jù)共享,持久化存儲(chǔ),通過is比較,每次map生成的都是唯一的 ,它們比較的是codehash的值,性能比通過遞歸或者直接比較強(qiáng)很多。在PureComponent淺比較不好用的時(shí)候

一般的組件,使用PureComponent減少重復(fù)渲染即可

PureComponent,平時(shí)我們創(chuàng)建 React 組件一般是繼承于 Component,而 PureComponent 相當(dāng)于是一個(gè)更純凈的 Component,對(duì)更新前后的數(shù)據(jù)進(jìn)行了一次淺比較。只有在數(shù)據(jù)真正發(fā)生改變時(shí),才會(huì)對(duì)組件重新進(jìn)行 render。因此可以大大提高組件的性能。

PureComponent部分源碼,其實(shí)就是淺比較,只不過對(duì)一些特殊值進(jìn)行了判斷:


function is(x: any, y: any) {
    return (
        (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y) 
    );
}
這里特別注意,為什么使用immutable.js和pureComponent,因?yàn)?b>React一旦根組件被刷

新,會(huì)自上而下逐漸刷新整個(gè)子孫組件,這樣性能損耗重復(fù)渲染就會(huì)多出很多,所以我們不僅要單一數(shù)據(jù)來源控制組件刷新,偶爾還需要在shouldComponentUpdate中對(duì)比nextProps和this.props 以及this.state以及nextState.

路由懶加載+code-spliting,加快首屏渲染,也可以減輕服務(wù)器壓力,因?yàn)楹芏嗳丝赡茉L問你的網(wǎng)頁并不會(huì)看某些路由的內(nèi)容

使用react-loadable,支持SSR,非常推薦,官方的lazy不支持SSR,這是一個(gè)遺憾,這里需要配合wepback4optimization配置,進(jìn)行代碼分割

Tips:這里需要下載支持動(dòng)態(tài)importbabel預(yù)設(shè)包 @babel/plugin-syntax-dynamic-import ,它支持動(dòng)態(tài)倒入組件
webpack配置:

 optimization: {
        runtimeChunk: true,
        splitChunks: {
            chunks: "all"
        }
    }
    import React from "react"
    import Loading from "./loading-window"http://占位的那個(gè)組件,初始加載
    import Loadable from "react-loadable"
    const LoadableComponent = Loadable({
        loader: () => import("./sessionWindow"),//真正需要加載的組件
        loading: Loading,
      });
      
      
    export default LoadableComponent

好了,現(xiàn)在路由懶加載組件以及代碼分割已經(jīng)做好了,而且它支持SSR。非常棒

由于純CSR的網(wǎng)頁一般不是很復(fù)雜,這里再介紹一個(gè)方面,那就是,能不用redux,dva等集中狀態(tài)管理的狀態(tài)就不上狀態(tài)樹,實(shí)踐證明,頻繁更新狀態(tài)樹對(duì)用戶體驗(yàn)來說是影響非常大的。這個(gè)異步的過程,更耗時(shí)。遠(yuǎn)不如支持通過props等方式進(jìn)行組件間通信,原則上除了很多組件共享的數(shù)據(jù)才上狀態(tài)樹,否則都采用其他方式進(jìn)行通信。

SSR,服務(wù)端渲染:
服務(wù)端渲染可以分為:
純服務(wù)端渲染,如jade,tempalte,ejs等模板引擎進(jìn)行渲染,然后返回給前端對(duì)應(yīng)的HTML文件

這里也使用Node.js+express框架

const express= require("express")
const app =express()
const jade = require("jade")
const result = ***
const url path = *** 
const html = jade.renderFile(url, { data: result, urlPath })//傳入數(shù)據(jù)給模板引擎
app.get("/",(req,res)=>{
    res.send(html)//直接吐渲染好的`html`文件拼接成字符串返回給客戶端
}) //RestFul接口 

app.listen(3000,err=>{
    //do something
})
混合渲染,使用webpack4插件,預(yù)渲染指定路由,被指定的路由為SSR渲染,后臺(tái)0代碼實(shí)現(xiàn)
const PrerenderSPAPlugin = require("prerender-spa-plugin")
new PrerenderSPAPlugin({
            routes: ["/","/home","/shop"],
            staticDir: resolve(__dirname, "../dist"),
          }),
混合渲染,使用Node.js作為中間件,SSR指定的路由加快首屏渲染,當(dāng)然CSS也可以服務(wù)端渲染,動(dòng)態(tài)Title和meta標(biāo)簽,更好的SEO優(yōu)化,這里Node.js還可以同時(shí)處理數(shù)據(jù),減輕前端的計(jì)算負(fù)擔(dān)。

我覺得掘金上的神三元那篇文章就寫得很好,后面我自己去逐步實(shí)現(xiàn)了一次,感覺對(duì)SSR對(duì)理解更為透徹,加上本來就每天在寫Node.js,還會(huì)一點(diǎn)Next,Nuxt,服務(wù)端渲染,覺得大同小異。

服務(wù)端渲染本質(zhì),在服務(wù)端把代碼運(yùn)行一次,將數(shù)據(jù)提前請(qǐng)求回來,返回運(yùn)行后的html文件,客戶端接到文件后,拉取js代碼,代碼注水,然后顯示,脫水,js接管頁面。

同構(gòu)直出代碼,可以大大降低首屏渲染時(shí)間,經(jīng)過實(shí)踐,根據(jù)不同的內(nèi)容和配置可以縮短40%-65%時(shí)間,但是服務(wù)端渲染會(huì)給服務(wù)器帶來壓力,所以折中根據(jù)情況使用。

以下是一個(gè)最簡單的服務(wù)端渲染,服務(wù)端直接吐拼接后的html結(jié)構(gòu)字符串:

var express = require("express")
var app = express()

app.get("/", (req, res) => {
 res.send(
 `
   
     
       hello
     
     
       

hello world

` ) }) app.listen(3000, () => { if(!err)=>{ console.log("3000監(jiān)聽")? } })
只要客戶端訪問localhost:3000就可以拿到數(shù)據(jù)頁面訪問
服務(wù)端渲染核心,保證代碼在服務(wù)端運(yùn)行一次,將reduxstore狀態(tài)樹中的數(shù)據(jù)一起返回給客戶端,客戶端脫水,渲染。 保證它們的狀態(tài)數(shù)據(jù)和路由一致,就可以說是成功了。必須要客戶端和服務(wù)端代碼和數(shù)據(jù)一致性,否則SSR就算失敗。
//server.js

// server/index.js
import express from "express";
import { render } from "../utils";
import { serverStore } from "../containers/redux-file/store";
const app = express();
app.use(express.static("public"));
app.get("*", function(req, res) {
  if (req.path === "/favicon.ico") {
    res.send();
    return;
  }
  const store = serverStore();
  res.send(render(req, store));
});
const server = app.listen(3000, () => {
  var host = server.address().address;
  var port = server.address().port;
  console.log(host, port);
  console.log("啟動(dòng)連接了");
});


//render函數(shù)
import Routes from "../Router";
import { renderToString } from "react-dom/server";
import { StaticRouter, Link, Route } from "react-router-dom";
import React from "react";
import { Provider } from "react-redux";
import { renderRoutes } from "react-router-config";
import routers from "../Router";
import { matchRoutes } from "react-router-config";
export const render = (req, store) => {
  const matchedRoutes = matchRoutes(routers, req.path);
  matchedRoutes.forEach(item => {
    //如果這個(gè)路由對(duì)應(yīng)的組件有l(wèi)oadData方法
    if (item.route.loadData) {
      item.route.loadData(store);
    }
  });
  console.log(store.getState(),Date.now())
  const content = renderToString(
    
      {renderRoutes(routers)}
    
  );
  return `
      
        
          ssr123
        
        
          
${content}
`; };

數(shù)據(jù)注水,脫水,保持客戶端和服務(wù)端store的一致性。

上面返回的script標(biāo)簽,里面已經(jīng)注水,將在服務(wù)端獲取到的數(shù)據(jù)給到了全局window下的context屬性,在初始化客戶端store時(shí)候我們給它脫水。初始化渲染使用服務(wù)端獲取的數(shù)據(jù)~
import thunk from "redux-thunk";
import { createStore, applyMiddleware } from "redux";
import reducers from "./reducers";

export const getClientStore = () => {
  const defaultState = window.context ? window.context.state : {};
  return createStore(reducers, defaultState, applyMiddleware(thunk));
};

export const serverStore = () => {
  return createStore(reducers, applyMiddleware(thunk));
};

這里注意,在組件的componentDidMount生命周期中發(fā)送ajax等獲取數(shù)據(jù)時(shí)候,先判斷下狀態(tài)樹中有沒有數(shù)據(jù),如果有數(shù)據(jù),那么就不要重復(fù)發(fā)送請(qǐng)求,導(dǎo)致資源浪費(fèi)。

多層級(jí)路由SSR

//路由配置文件,改成這種方式
import Home from "./containers/Home";
import Login from "./containers/Login";
import App from "./containers/app";
export default [
  {
    component: App,
    routes: [
      {
        path: "/",
        component: Home,
        exact: true,
        loadData: Home.loadData
      },
      {
        path: "/login",
        component: Login,
        exact: true
      }
    ]
  }
];

入口文件路由部分改成:

server.js

 const content = renderToString(
    
      {renderRoutes(routers)}
    
  );

client.js 

 
      {renderRoutes(routers)}
    

后續(xù)可能有利用loader進(jìn)行CSS的服務(wù)端渲染以及helmet的動(dòng)態(tài)meta, title標(biāo)簽進(jìn)行SEO優(yōu)化等,今天時(shí)間緊促,就不繼續(xù)寫SSR了。

構(gòu)建Electron極度復(fù)雜,超大數(shù)據(jù)的應(yīng)用。
需要用到技術(shù),sqlite,PWA,web work,原生Node.js,react-window,react-lazyload,C++插件等

第一個(gè)提到的是sqlite,嵌入式關(guān)系型數(shù)據(jù)庫,輕量型無入侵性,標(biāo)準(zhǔn)的sql語句,這里不做過多介紹。

PWA,漸進(jìn)性式web應(yīng)用,這里使用webpack4的插件,進(jìn)行快速使用,對(duì)于一些數(shù)據(jù)內(nèi)容不需要存儲(chǔ)數(shù)據(jù)庫的,但是卻想要一次拉取,多次復(fù)用,那么可以使用這個(gè)配置

serverce work也有它的一套生命周期

通常我們?nèi)绻褂?Service Worker 基本就是以下幾個(gè)步驟:

首先我們需要在頁面的 JavaScript 主線程中使用 serviceWorkerContainer.register() 來注冊(cè) Service Worker ,在注冊(cè)的過程中,瀏覽器會(huì)在后臺(tái)啟動(dòng)嘗試 Service Worker 的安裝步驟。

如果注冊(cè)成功,Service Worker 在 ServiceWorkerGlobalScope 環(huán)境中運(yùn)行; 這是一個(gè)特殊的 worker context,與主腳本的運(yùn)行線程相獨(dú)立,同時(shí)也沒有訪問 DOM 的能力。

后臺(tái)開始安裝步驟, 通常在安裝的過程中需要緩存一些靜態(tài)資源。如果所有的資源成功緩存則安裝成功,如果有任何靜態(tài)資源緩存失敗則安裝失敗,在這里失敗的不要緊,會(huì)自動(dòng)繼續(xù)安裝直到安裝成功,如果安裝不成功無法進(jìn)行下一步 — 激活 Service Worker。

開始激活 Service Worker,必須要在 Service Worker 安裝成功之后,才能開始激活步驟,當(dāng) Service Worker 安裝完成后,會(huì)接收到一個(gè)激活事件(activate event)。激活事件的處理函數(shù)中,主要操作是清理舊版本的 Service Worker 腳本中使用資源。

激活成功后 Service Worker 可以控制頁面了,但是只針對(duì)在成功注冊(cè)了 Service Worker 后打開的頁面。也就是說,頁面打開時(shí)有沒有 Service Worker,決定了接下來頁面的生命周期內(nèi)受不受 Service Worker 控制。所以,只有當(dāng)頁面刷新后,之前不受 Service Worker 控制的頁面才有可能被控制起來。

直接上代碼,存儲(chǔ)所有js文件和圖片 //實(shí)際的存儲(chǔ)根據(jù)自身需要,并不是越多越好。
const WorkboxPlugin = require("workbox-webpack-plugin")
new WorkboxPlugin.GenerateSW({
            clientsClaim: true,
            skipWaiting: true,
            importWorkboxFrom: "local",
            include: [/.js$/, /.css$/, /.html$/, /.jpg/, /.jpeg/, /.svg/, /.webp/, /.png/],
        }),

PWA并不僅僅這些功能,它的功能非常強(qiáng)大,有興趣的可以去lavas看看,PWA技術(shù)對(duì)于經(jīng)常訪問的老客戶來說,首屏渲染提升非常大,特別在移動(dòng)端,可以添加到桌面保存。666啊~,在pc端更多的是緩存處理文件~

使用react-lazyload,懶加載你的視窗初始看不見的組件或者圖片。

/開箱即用的懶加載圖片
import LazyLoad from "react-lazyload"
  //這里配置表示占位符的樣式~。
          


記得在移動(dòng)端的滑動(dòng)屏幕或者PC端的調(diào)用forceCheck,動(dòng)態(tài)計(jì)算元素距離視窗的位置然后決定是否顯示真的圖片~

import { forceCheck } from "react-lazyload";
forceCheck()

懶加載組件

import { lazyload } from "react-lazyload";
//跟上面同理,不過是一個(gè)裝飾器,高階函數(shù)而已。一樣需要forcecheck()
@lazyload({
  height: 200,
  once: true,
  offset: 100
})
class MyComponent extends React.Component {
  render() {
    return 
this component is lazyloaded by default!
; } }
大數(shù)據(jù)React渲染,擁有讓應(yīng)用擁有60FPS -非常核心的一點(diǎn)優(yōu)化

List長列表


]

react-virtualized-auto-sizer和windowScroll配合一起使用,達(dá)到頁面復(fù)雜效果+大數(shù)據(jù)渲染保持60FPS。上面的官網(wǎng)里有介紹這些組件~

高計(jì)算量的工作交給web wrok線程
var myWorker = new Worker("worker.js"); 
first.onchange = function() {
  myWorker.postMessage([first.value,second.value]);
  console.log("Message posted to worker");
}

second.onchange = function() {
  myWorker.postMessage([first.value,second.value]);
  console.log("Message posted to worker");
}

這段代碼中變量first和second代表2個(gè)元素;它們當(dāng)中任意一個(gè)的值發(fā)生改變時(shí),myWorker.postMessage([first.value,second.value])會(huì)將這2個(gè)值組成數(shù)組發(fā)送給worker。你可以在消息中發(fā)送許多你想發(fā)送的東西。

在worker中接收到消息后,我們可以寫這樣一個(gè)事件處理函數(shù)代碼作為響應(yīng)(worker.js):

onmessage = function(e) {
  console.log("Message received from main script");
  var workerResult = "Result: " + (e.data[0] * e.data[1]);
  console.log("Posting message back to main script");
  postMessage(workerResult);
}

onmessage處理函數(shù)允許我們?cè)谌魏螘r(shí)刻,一旦接收到消息就可以執(zhí)行一些代碼,代碼中消息本身作為事件的data屬性進(jìn)行使用。這里我們簡單的對(duì)這2個(gè)數(shù)字作乘法處理并再次使用postMessage()方法,將結(jié)果回傳給主線程。

回到主線程,我們?cè)俅问褂胦nmessage以響應(yīng)worker回傳的消息:

myWorker.onmessage = function(e) {
  result.textContent = e.data;
  console.log("Message received from worker");
}

在這里我們獲取消息事件的data,并且將它設(shè)置為result的textContent,所以用戶可以直接看到運(yùn)算的結(jié)果。

注意: 在主線程中使用時(shí),onmessage和postMessage() 必須掛在worker對(duì)象上,而在worker中使用時(shí)不用這樣做。原因是,在worker內(nèi)部,worker是有效的全局作用域。

注意: 當(dāng)一個(gè)消息在主線程和worker之間傳遞時(shí),它被復(fù)制或者轉(zhuǎn)移了,而不是共享。

開啟web work線程,其實(shí)也會(huì)損耗一定的主線程的性能,但是大量計(jì)算的工作交給它也未嘗不可,其實(shí)Node.jsjavaScript都不適合做大量計(jì)算工作,這點(diǎn)有目共睹,尤其是js引擎和GUI渲染線程互斥的情況存在。
充分合理利用ReactFeber架構(gòu)diff算法優(yōu)化項(xiàng)目

requestAnimationFrame調(diào)用高優(yōu)先級(jí)任務(wù),中斷調(diào)度階段的遍歷,由于React的新版本調(diào)度階段是擁有三根指針的可中斷的鏈表遍歷,所以這樣既不影響下面的遍歷,也不影響用戶交互等行為。

使用requestAnimationFrame,當(dāng)頁面處于未激活的狀態(tài)下,該頁面的屏幕刷新任務(wù)會(huì)被系統(tǒng)暫停,由于requestAnimationFrame保持和屏幕刷新同步執(zhí)行,所以也會(huì)被暫停。當(dāng)頁面被激活時(shí),動(dòng)畫從上次停留的地方繼續(xù)執(zhí)行,節(jié)約 CPU 開銷。

一個(gè)刷新間隔內(nèi)函數(shù)執(zhí)行多次時(shí)沒有意義的,因?yàn)轱@示器每 16.7ms 刷新一次,多次繪制并不會(huì)在屏幕上體現(xiàn)出來

在高頻事件(resize,scroll等)中,使用requestAnimationFrame可以防止在一個(gè)刷新間隔內(nèi)發(fā)生多次函數(shù)執(zhí)行,這樣保證了流暢性,也節(jié)省了函數(shù)執(zhí)行的開銷

某些情況下可以直接使用requestAnimationFrame替代 Throttle 函數(shù),都是限制回調(diào)函數(shù)執(zhí)行的頻率

使用requestAnimationFrame也可以更好的讓瀏覽器保持60幀的動(dòng)畫

requestIdleCallback,這個(gè)API目前兼容性不太好,但是在Electron開發(fā)中,可以使用,兩者還是有區(qū)別的,而且這兩個(gè)api用好了可以解決很多復(fù)雜情況下的問題~。當(dāng)然你也可以用上面的api封裝這個(gè)api,也并不是很復(fù)雜。

當(dāng)關(guān)注用戶體驗(yàn),不希望因?yàn)橐恍┎恢匾娜蝿?wù)(如統(tǒng)計(jì)上報(bào))導(dǎo)致用戶感覺到卡頓的話,就應(yīng)該考慮使用requestIdleCallback。因?yàn)閞equestIdleCallback回調(diào)的執(zhí)行的前提條件是當(dāng)前瀏覽器處于空閑狀態(tài)。

圖中一幀包含了用戶的交互、js的執(zhí)行、以及requestAnimationFrame的調(diào)用,布局計(jì)算以及頁面的重繪等工作。

假如某一幀里面要執(zhí)行的任務(wù)不多,在不到16ms(1000/60)的時(shí)間內(nèi)就完成了上述任務(wù)的話,那么這一幀就會(huì)有一定的空閑時(shí)間,這段時(shí)間就恰好可以用來執(zhí)行requestIdleCallback的回調(diào),如下圖所示:

使用preload,prefetch,dns-prefetch等指定提前請(qǐng)求指定文件,或者根據(jù)情況,瀏覽器自行決定是否提前dns預(yù)解析或者按需請(qǐng)求某些資源。

這里也可以webpack4插件實(shí)現(xiàn),目前京東在使用這個(gè)方案~

const PreloadWebpackPlugin = require("preload-webpack-plugin")
 new PreloadWebpackPlugin({
            rel: "preload",
            as(entry) {
              if (/.css$/.test(entry)) return "style";
              if (/.woff$/.test(entry)) return "font";
              if (/.png$/.test(entry)) return "image";
              return "script";
            },
            include:"allChunks"
            //include: ["app"]
          }),
對(duì)指定js文件延遲加載~

普通的腳本

script標(biāo)簽,加上async標(biāo)簽,遇到此標(biāo)簽,先去請(qǐng)求,但是不阻塞解析html等文件~,請(qǐng)求回來就立馬加載

script標(biāo)簽,加上defer標(biāo)簽,延遲加載,但是必須在所有腳本加載完畢后才會(huì)加載它,但是這個(gè)標(biāo)簽有bug,不確定能否準(zhǔn)時(shí)加載。一般只給一個(gè)

寫這篇時(shí)間太耗時(shí)間,而且論壇的在線編輯器到了內(nèi)容很多的時(shí)候,非???,React-native的以及一些細(xì)節(jié),后面再補(bǔ)充
下面給出一些源碼和資料地址:

手寫React優(yōu)化腳手架帶項(xiàng)目

react-ssr的源碼

手寫Node.js原生靜態(tài)資源服務(wù)器

跨平臺(tái)Electron的demo

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/116124.html

相關(guān)文章

  • 如何優(yōu)化你的大型React應(yīng)用原創(chuàng)精讀

    摘要:往往純的單頁面應(yīng)用一般不會(huì)太復(fù)雜,所以這里不引入和等等,在后面復(fù)雜的跨平臺(tái)應(yīng)用中我會(huì)將那些技術(shù)一擁而上。構(gòu)建極度復(fù)雜,超大數(shù)據(jù)的應(yīng)用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React為了大型應(yīng)用而生,Electron和React-native賦予了它構(gòu)建移動(dòng)端跨平臺(tái)App和桌面應(yīng)用的能力,Taro則賦...

    cfanr 評(píng)論0 收藏0
  • 如何優(yōu)化你的大型React應(yīng)用原創(chuàng)精讀

    摘要:往往純的單頁面應(yīng)用一般不會(huì)太復(fù)雜,所以這里不引入和等等,在后面復(fù)雜的跨平臺(tái)應(yīng)用中我會(huì)將那些技術(shù)一擁而上。構(gòu)建極度復(fù)雜,超大數(shù)據(jù)的應(yīng)用。 showImg(https://segmentfault.com/img/bVbvphv?w=1328&h=768); React為了大型應(yīng)用而生,Electron和React-native賦予了它構(gòu)建移動(dòng)端跨平臺(tái)App和桌面應(yīng)用的能力,Taro則賦...

    codecook 評(píng)論0 收藏0
  • 論一個(gè)前端工程師如何快速學(xué)習(xí),成長。準(zhǔn)備自己的35歲 【-原創(chuàng)精讀

    showImg(https://segmentfault.com/img/bVbw3tK?w=1240&h=827); 前端工程師這個(gè)崗位,真的是反人性的 我們來思考一個(gè)問題: 一個(gè)6年左右經(jīng)驗(yàn)的前端工程師: 前面兩年在用jQuery 期間一直在用React-native(一步一步踩坑過來的那種) 最近兩年還在寫微信小程序 下面一個(gè)2年經(jīng)驗(yàn)的前端工程師: 并不會(huì)跨平臺(tái)技術(shù),他的兩年工作都是Reac...

    RdouTyping 評(píng)論0 收藏0
  • The Cost Of JavaScript 2018 精讀

    摘要:目前我們的業(yè)務(wù)項(xiàng)目采用的來進(jìn)行優(yōu)化和首屏性能提升??勺冃孕枰岄_發(fā)人員降低開發(fā)時(shí)的基準(zhǔn)線,來保證每一個(gè)用戶的體驗(yàn)。對(duì)于路由的切分以及庫的引入來說,這一個(gè)原則至關(guān)重要??焖偕梢环菡军c(diǎn)的性能審查報(bào)告。 The Cost Of JavaScript 2018 關(guān)于原文 原文是在Medium上面看到的,Chrome工程師Addy Osmani發(fā)布的一篇文章,這位的Medium上面的自我介紹里...

    lushan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<