11 月 19 - 20 日 Apache Pulsar 社区年度盛会来啦,立即报名! 了解详情
写点什么

你的项目不知如何优化?教你 1 招提高代码使用率

  • 2020-06-05
  • 本文字数:3261 字

    阅读完需:约 11 分钟

你的项目不知如何优化?教你 1 招提高代码使用率

导读:经常有同学感叹不知道怎么优化项目,大家不妨尝试下在项目中引入代码分割的方式提升性能。


Web 应用性能优化的关键

关于 Web 应用性能优化,有一点是毫无疑问的:「页面加载越久,用户体验就越差」。我们几乎可以说 Web 应用性能优化的关键之处就在于: 减少页面初载时,所需加载资源的「数量」和「体积」。


那么当所需加载的资源数量到达多少或资源大小小于多少,我们才可以自信地宣称我们的 Web 应用拥有出色的性能呢?


下面是我给出的一个参考值,该参考值考虑到了移动端与国外等多种访问环境:


  1. 页面初载时,所有未压缩的 JavaScript 脚本大小:<=200KB;

  2. 页面初载时,所有未压缩的 CSS 资源大小:<=100KB;

  3. HTTP 协议下,请求资源数:<=6 个;

  4. HTTP/2 协议下,请求资源数:<=20 个 ;

  5. 90%的代码利用率(也就是说,仅允许 10% 的未使用代码);


或许你会觉得这个标准有点过于苛刻了,是有一点点,但为了创建出高性能的 Web 应用,你的实际资源加载情况应该尽可能靠近这个目标。


如何查看代码利用率

也许你注意到了,我们上一节最后提到的一个指标是「代码利用率」,你可能是第一次听说这个概念,这里我解释一下它的计算方式:


代码利用率 = 你页面中实际被执行的代码 / 你页面中引入的代码 * 100%


你可能会困惑在实际开发中如何得到这个值,别担心,通过使用 Chrome 开发者工具(很遗憾,目前只有 Chrome 支持这一功能),你就可以迅速对你的 Web 应用进行分析,得到当前页面下的代码利用率状态,步骤如下:


  1. 打开 Chrome Dev Tool;

  2. 按下 Cmd + Shift + P or Ctrl + Shift + P ;

  3. 输入 Coverage,并选择第一个出现的选项;



  1. 点击面板上的 reload 按钮,查看整个应用 JavaScript 的代码利用率;



提高代码使用率的关键技术 — 代码分割(code splitting)

什么是「代码分割」(code splitting)?

代码分割是指,将脚本中无需立即调用的代码在代码构建时转变为异步加载的过程。


在 Webpack 构建时,会避免加载已声明要异步加载的代码,异步代码会被单独分离出一个文件,当代码实际调用时被加载至页面。


代码分割的原理

代码分割技术的核心是 「异步加载资源」 ,可喜的是,浏览器允许我们这么做,W3C stage 3 规范:whatwg/loader 对其进行了定义:你可以通过 import() 关键字让浏览器在程序执行时异步加载相关资源。



没错,正如你所看到的, IE 浏览器目前并不支持这一特性,但这并不意味着你的异步加载功能在 IE 浏览会失效(那太可怕了 🤦‍♂️),实际上,Webpack 底层帮你将异步加载的代码抽离成一份新的文件,并在你需要时通过 JSONP 的方式去获取文件资源,因此,你可以在任何浏览器上实现代码的异步加载,并且在将来所有浏览器都实现 import() 方法时平滑过渡,cool!👍


代码分割的类型

代码分割可以分为「静态分割」和「“动态”分割」两种方式, 注意这里打了引号的 “动态”,因为实际上它并不意味着异步调用的代码是 “动态” 生成的,我们之后会看到 Webpack 是如何做到这一点的,在那之前,让我们先看看「静态代码分割」。


静态代码分割


静态代码分割是指:在代码中明确声明需要异步加载的代码。


下面 👇 的代码说明了我们应该如何使用这一技术:


import Listener from './listeners.js'const getModal = () => import('./src/modal.js') Listener.on('didSomethingToWarrentModalBeingLoaded', () => {  // Async fetching modal code from a separate chunk  getModal().then((module) => {    const modalTarget = document.getElementById('Modal')    module.initModal(modalTarget)  })})const getModal = () => import('./src/modal.js') Listener.on(  'didSomethingToWarrentModalBeingLoaded',  () => {    // Async fetching modal code from a separate chunk    getModal().then(      (module) => {        const modalTarget = document.getElementById('Modal')            module.initModal(modalTarget)        })  })
复制代码


正如你所看到的:每当你调用一个声明了异步加载代码的变量时,它总是返回一个 Promise 对象。


⚠️ 注意:在 Vue 中,可以直接使用 import() 关键字做到这一点,而在 React 中,你需要使用 react-loadable 去完成同样的事。


最后,让我们谈谈何时使用静态代码分割技术,这一技术适合以下的场景:


1. 你正在使用一个非常大的库或框架: 如果在页面初始化时你不需要使用它,就不要在页面初载时加载它;


2. 任何临时的资源: 指不在页面初始化时被使用,被使用后又会立即被销毁的资源,例如模态框,对话框,tooltip 等(任何一开始不显示在页面上的东西都可以有条件的加载);


3. 路由: 既然用户不会一下子看到所有页面,那么只把当前页面相关资源给用户就是个明智的做法;


好了,现在你掌握了静态代码分割技术,现在让我们看看什么是「“动态代”代码分割」技术。


动态代码分割


动态代码分割是指:在代码调用时根据当前的状态,「动态地」异步加载对应的代码块。


下面 👇 的代码说明了它具体是如何被实现的:


const getTheme = (themeName) => import(`./src/themes/${themeName}`)// using `import()` 'dynamically'if (window.feeling.stylish) {  getTheme('stylish').then((module) => {    module.applyTheme()  })} else if (window.feeling.trendy) {  getTheme('trendy').then((module) => {    module.applyTheme()  })}
复制代码


看到了吗,我们 “动态” 的声明了我们要异步加载的代码块,这是怎么做到的?!


答案出乎意料的简单,Webpack 会在构建时将你声明的目录下的所有可能分离的代码都抽象为一个文件(这被称为 contextModule 模块),因此无论你最终声明了调用哪个文件,本质上就和静态代码分割一样,在请求一个早已准备好的,静态的文件。


下面是一些使用 “动态” 代码分割技术的场景:


  1. A/B Test:你不需要在代码中引入不需要的 UI 代码;

  2. 加载主题:根据用户的设置,动态加载相应的主题;

  3. 为了方便 :本质上,你可以用静态代码分割代替「动态」代码分割,但是后者比前者拥有更少的代码量;


魔术注释

魔术注释是由 Webpack 提供的,可以为代码分割服务的一种技术。通过在 import 关键字后的括号中使用指定注释,我们可以对代码分割后的 chunk 有更多的控制权,让我们看一个例子:


// index.jsimport (  /* webpackChunkName: “my-chunk-name” */  './footer')
复制代码


同时,也要在 webpack.config.js 中做一些改动:


// webpack.config.js{  output: {    filename: “bundle.js”,    chunkFilename: “[name].lazy-chunk.js”  }}
复制代码


通过这样的配置,我们可以对分离出的 chunk 进行命名,这对于我们 debug 而言非常方便。


Webpack Modes

除了上面提到过得 webpackChunkName 注释外,Webpack 还提供了一些其他注释让我们能够对异步加载模块拥有更多控制权,例如下方这个例子:


import (  /* webpackChunkName: “my-chunk-name” */  /* webpackMode: lazy */  './someModule')
复制代码


webpackMode 的默认值为 lazy 它会使所有异步模块都会被单独抽离成单一的 chunk,若设置该值为 lazy-once,Webpack 就会将所有带有标记的异步加载模块放在同一个 chunk 中。


Prefetch or Preload

通过添加 webpackPrefetch 魔术注释,Webpack 令我们可以使用与 <link rel=“prefetch”> 相同的特性。让浏览器会在 Idle 状态时预先帮我们加载所需的资源,善用这个技术可以使我们的应用交互变得更加流畅。


import(  /* webpackPrefetch: true */  './someModule')
复制代码


⚠️ 注意:你确保你的代码在未来一定会用到时,再开启该功能。


小结

至此,我们讲解了所有有关 Code Splitting 的知识,并告诉你了一些神奇的「魔法注释」让你对分割后的代码有更多的掌控,希望你能将上面的技术灵活运用在你的项目中,开发出更加激动人心,如丝般顺滑的应用!


Good Luck!🙌


本文转载自公众号淘系技术(ID:AlibabaMTT)。


原文链接


https://mp.weixin.qq.com/s?__biz=MzAxNDEwNjk5OQ==&mid=2650407508&idx=1&sn=b57f3886f2edd8ff31abf7560af59e58&chksm=8396ca4cb4e1435a2a1b5e37fbe9b372f1322e982a1a236e078deece4833de351c8dc9cd5eb4&scene=27#wechat_redirect


2020-06-05 10:061300

评论

发布
暂无评论
发现更多内容

在线文本转2-36任意进制工具

入门小站

工具

[ CloudWeGo 微服务实践 - 06 ] 服务发现(2)

baiyutang

golang 微服务 11月日更

Android C++ 系列:JNI数组操作

轻口味

android 11月日更

微信朋友圈复杂度分析

思辰

架构实战营

从0-1教你利用服务器做属于自己的个人博客

坚果

git 博客 服务器 nodejs 11月日更

CSS响应式布局之REM(二)

Augus

CSS 11月日更

超详细攻略!手把手教你如何在windows下搭建openLooKeng开发环境

openLooKeng

大数据 计算引擎

解锁WiFi密码,我只用了60行代码....

Jackpop

如何从 JavaScript 中的数组中删除空元素?

devpoint

JavaScript filter 11月日更

极复杂编码,下载《原神》角色高清图、中日无损配音,爬虫 16 / 120 例

梦想橡皮擦

11月日更

什么是开源软件和自由软件,你真的了解吗

耳东@Erdong

开源软件 11月日更 自由软件

iOS开发:程序打包提示Ignoring file XXX missing required architecture arm7 in file XXX错误

三掌柜

11月日更

开源应用中心|最好用的5款开源论坛软件,你知道吗?

开源 博客 开源软件 论坛

毕业总结

babos

#架构实战营

dart系列之:dart语言中的内置类型

程序那些事

flutter dart 程序那些事 11月日更

Vue进阶(幺陆玖):JS 垃圾回收机制

No Silver Bullet

Vue GC 11月日更

鸿洋:拖不得了,Android11真的要来了,最全适配实践指南奉上

android 程序员 移动开发

Scrum Master们,难道每天都在摸鱼

华为云开发者联盟

摸鱼 敏捷教练 开发团队 Scrum Master 领导

MySQL 默认隔离级别是RR,为什么阿里这种大厂会改成RC?

Hollis

模块九—电商秒杀系统

babos

#架构实战营

Hazelcast在openLooKeng中的应用(Cache篇)

openLooKeng

大数据 cache 计算引擎 openLooKeng

【Promise 源码学习】第一篇 - Promise 简介

Brave

源码 Promise 11月日更

基于软件分析的智能化开发新型服务与技术

华为云开发者联盟

程序员 开发 漏洞 软件分析 智能开发

外包学生管理系统的架构

胡颖

Java 自定义注解(二)

程序员架构进阶

Java 注解 11月日更

linux之我常用的20条命令( 之三)

入门小站

Linux

架构实战营模块三作业

孙志强

架构实战营

【Flutter 专题】15 图解 ListView 异步加载数据与 Loading 等待

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 11月日更

Elastic-Job的执行原理及优化实践

OPPO数智技术

Java 架构 分布式 后端

vivo 全球商城:商品系统架构设计与实践

vivo互联网技术

软件架构 架构设计 商城项目

【LeetCode】只出现一次的数字 IIIJava题解

Albert

算法 LeetCode 11月日更

你的项目不知如何优化?教你 1 招提高代码使用率_移动_李斌(空堂)_InfoQ精选文章