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

資訊專欄INFORMATION COLUMN

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

codecook / 3197人閱讀

摘要:往往純的單頁(yè)面應(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則賦予了它一次編寫(xiě),生成多種平臺(tái)小程序和React-native應(yīng)用的能力,這里特意說(shuō)下 Taro,它是國(guó)產(chǎn),文檔寫(xiě)得比較不錯(cuò),而且它的升級(jí)速度比較快,有issue我看也會(huì)及時(shí)解決,他們的維護(hù)人員還是非常敬業(yè)的!

,

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

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

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

react-ssr的源碼

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

跨平臺(tái)Electron的demo

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

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

原生瀏覽器環(huán)境中使用React框架,比較常見(jiàn)的是制作單頁(yè)面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)聽(tīng)端口號(hào)3000成功")
    }
})

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

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

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

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

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

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

class app extends React.PureComponent{

    ///////
}

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

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

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

單向數(shù)據(jù)流不可變數(shù)據(jù),通過(guò)immutable.js這個(gè)庫(kù)實(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ǔ),通過(guò)is比較,每次map生成的都是唯一的 ,它們比較的是codehash的值,性能比通過(guò)遞歸或者直接比較強(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í)就是淺比較,只不過(guò)對(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ù)來(lái)源控制組件刷新,偶爾還需要在shouldComponentUpdate中對(duì)比nextProps和this.props 以及this.state以及nextState.

路由懶加載+code-spliting,加快首屏渲染,也可以減輕服務(wù)器壓力,因?yàn)楹芏嗳丝赡茉L問(wèn)你的網(wǎng)頁(yè)并不會(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)頁(yè)一般不是很復(fù)雜,這里再介紹一個(gè)方面,那就是,能不用redux,dva等集中狀態(tài)管理的狀態(tài)就不上狀態(tài)樹(shù),實(shí)踐證明,頻繁更新?tīng)顟B(tài)樹(shù)對(duì)用戶體驗(yàn)來(lái)說(shuō)是影響非常大的。這個(gè)異步的過(guò)程,更耗時(shí)。遠(yuǎn)不如支持通過(guò)props等方式進(jìn)行組件間通信,原則上除了很多組件共享的數(shù)據(jù)才上狀態(tài)樹(shù),否則都采用其他方式進(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)。

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

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

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

以下是一個(gè)最簡(jiǎn)單的服務(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)聽(tīng)")? } })
只要客戶端訪問(wèn)localhost:3000就可以拿到數(shù)據(jù)頁(yè)面訪問(wèn)
服務(wù)端渲染核心,保證代碼在服務(wù)端運(yùn)行一次,將reduxstore狀態(tài)樹(shù)中的數(shù)據(jù)一起返回給客戶端,客戶端脫水,渲染。 保證它們的狀態(tài)數(shù)據(jù)和路由一致,就可以說(shuō)是成功了。必須要客戶端和服務(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īng)顟B(tài)樹(shù)中有沒(mé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ù)寫(xiě)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ù)庫(kù),輕量型無(wú)入侵性,標(biāo)準(zhǔn)的sql語(yǔ)句,這里不做過(guò)多介紹。

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

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

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

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

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

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

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

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

直接上代碼,存儲(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)常訪問(wèn)的老客戶來(lái)說(shuō),首屏渲染提升非常大,特別在移動(dòng)端,可以添加到桌面保存。666啊~,在pc端更多的是緩存處理文件~

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

/開(kāi)箱即用的懶加載圖片
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";
//跟上面同理,不過(guò)是一個(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渲染,擁有讓?xiě)?yīng)用擁有60FPS -非常核心的一點(diǎn)優(yōu)化

List長(zhǎng)列表


]

react-virtualized-auto-sizer和windowScroll配合一起使用,達(dá)到頁(yè)面復(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中接收到消息后,我們可以寫(xiě)這樣一個(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)行使用。這里我們簡(jiǎ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)移了,而不是共享。

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

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

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

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

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

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

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

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

假如某一幀里面要執(zhí)行的任務(wù)不多,在不到16ms(1000/60)的時(shí)間內(nèi)就完成了上述任務(wù)的話,那么這一幀就會(huì)有一定的空閑時(shí)間,這段時(shí)間就恰好可以用來(lái)執(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)求回來(lái)就立馬加載

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

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

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

react-ssr的源碼

手寫(xiě)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/105905.html

相關(guān)文章

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

    摘要:往往純的單頁(yè)面應(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è)面應(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則賦...

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

    showImg(https://segmentfault.com/img/bVbw3tK?w=1240&h=827); 前端工程師這個(gè)崗位,真的是反人性的 我們來(lái)思考一個(gè)問(wèn)題: 一個(gè)6年左右經(jīng)驗(yàn)的前端工程師: 前面兩年在用jQuery 期間一直在用React-native(一步一步踩坑過(guò)來(lái)的那種) 最近兩年還在寫(xiě)微信小程序 下面一個(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)目采用的來(lái)進(jìn)行優(yōu)化和首屏性能提升。可變性需要讓開(kāi)發(fā)人員降低開(kāi)發(fā)時(shí)的基準(zhǔn)線,來(lái)保證每一個(gè)用戶的體驗(yàn)。對(duì)于路由的切分以及庫(kù)的引入來(lái)說(shuō),這一個(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)論

閱讀需要支付1元查看
<