【翻译&摘抄】React 应用性能调优

compression

页面加载一个很大的瓶颈就是 JS bundle 提及太大,下载它话费了很多时间。

我们应该使用 Gzip 来压缩一下:通过 Node/Express 的服务端很容易实现 Gzip;只需要安装 compression 模块并将它作为一个 Express 中间件使用就可以了。

const express = require('express');
const compression = require('compression');

const app = express();

// 将 compression 作为一个 Express 中间件
app.use(compression());

LocalStorage 缓存

使用 local-storage 可以把所有的状态变更都存储到浏览器上,并在用户数据返回的时候对这个本地状态进行补充。首屏的数据可能是旧的,但是没关系!真实的数据很快就能加载回来,并且这会使得首次加载的体验非常快。

解决方案使用了 Redux,首先需要保证 Redux 状态变化的时候更新 localStorage:

import { LOCAL_STORAGE_REDUX_DATA_KEY } from '../constants';
import { debounce } from '../utils'; // generic debounce util

// 当页面首次加载时,redux actions 会迅速被 dispatch
// 每个节目都要获取它们的剧集,所以最小的 action 数量是 2n (n 是节目的数量)
// 不需要太过于频繁的更新 localStorage,可以做 debounce
// 如果传入 null 则抹去数据,用来在登录登出时消除持久状态
const updateLocalStorage = debounce(
  value =>
    value !== null
      ? localStorage.setItem(LOCAL_STORAGE_REDUX_DATA_KEY, value)
      : localStorage.removeItem(LOCAL_STORAGE_REDUX_DATA_KEY),
  2500
);


// store 更新时,将相关部分存储到 localStorage 中
export const handleStoreUpdates = function handleStoreUpdates(store) {
  // 忽略 modals 和 flash 消息,他们不需要被存储
  const { modals, flash, ...relevantState} = store.getState();

  updateLocalStorage(JSON.stringify(relevantState));
}

// 在退出登录时用来清除数据的一个函数
export const clearReduxData = () => {
  // 立即清除存储在 localStorage 中的数据
  window.localStorage.removeItem(LOCAL_STORAGE_REDUX_DATA_KEY);

  // 因为删除是同步的,而持久化数据是异步的,因此这里会导致一个微妙的 bug:
  // 存储的数据会被删除,但是稍后又会被填充上
  // 为了解决这个问题,我们会传入一个 null,来终止当前队列所有的更新

  updateLocalStorage(null);

  // 我们需要触发异步和同步的操作。
  // 同步操作保证数据可以立刻被删除,所以如果用户点击退出后立刻关闭页面,数据也能被删除
};

下一步,需要让 Redux store 订阅这个函数,并用前一次会话的数据对它进行初始化。

const localState = JSON.parse(
  localStorage.getItem(LOCAL_STORAGE_REDUX_DATA_KEY) || '{}'
);

const store = configureStore(history, localState);

store.subscribe(() => {
  handleStoreUpdates(store);
});

注,subscribe 方法的一点讲解:

使用方法:store.subscribe(listener)

作用是添加一个变化监听器。
每当 dispatch action 的时候就会执行,state 树中的一部分可能已经变化。
你可以在回调函数里调用 getState() 来拿到当前 state

在内容已经出现的情况下,页面仍在继续变化,这是一种非常流行的技术,可以让页面更快地展现,并且当新的内容可用时,页面发生更新。

懒加载

在大型桌面窗口上,每屏也许只能看到几张图片,但是在页面加载的时候却会一次性获取全部。
值得庆幸的是,有一个很棒的库 react-lazyload 提供了非常便利的懒加载功能。代码示例如下:

import LazyLoad from 'react-lazyload';

// In some render method somewhere:
<LazyLoad once height={UNITS_IN_PX[6]} offset={50}>
  <img
    srcSet={`...omitted`}
    sizes={`...omitted`}
  />
</LazyLoad>

服务端渲染

可以考虑的一个途径是,在服务端渲染一个 “shell” —— 一个有正确布局的占位图,只是没有数据。

但是会一个问题,因为客户端已经通过 localStorage 获取前一次会话的数据了,并且它使用这个数据进行了初始化。但是此时服务端是不知情的,所以我需要处理客户端与服务器之间的标记不匹配。

虽然我可以通过 SSR 将我的首次有效渲染时间减少半秒,但是在那时整个网站都是不能交互的;当一个网站看起来已经准备好了但其实不是的时候,让人觉得非常奇怪。
另外,SSR 也会增加复杂性,并且降低开发速度。性能很重要,但是足够好就够了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值