前端js性能优化(三)

时间:2021-08-29 03:45:50

UI界面

浏览器让一个单线程共用于执行js和更新UI界面,因此这两种操作无法同时进行。

浏览器UI线程

用于执行js和更新UI的进程通常被成为浏览器UI线程。
UI线程的工作基于一个简单的队列系统,任务会被保存到队列中直到进程空闲。一旦空闲,队列中的下一个任务就会被重新提取出来并运行。这些任务要么是js代码,要么是执行UI更新(包括重绘和重排)。这两种任务是相互阻塞的。

浏览器限制

浏览器限制了js任务的运行时间。这确保了某些恶意代码不能通过一些操作来锁住用户的浏览器或计算机。

此类限制分为两种:调用栈大小限制和长时间运行脚本限制。

长时间运行脚本限制的原理是浏览器会记录一个脚本的运行时间,并在达到一定限度时终止它。

创建一个定时器(setTimeout或setInterval)会造成UI线程暂停,如同它从一个任务切换到下一个任务。因此,定时器代码会重置所有相关的浏览器限制,包括长时间运行脚本。这一特性使得定时器成为长时间运行js代码的理想方案。

Web Workers

Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。

web workers可以带来巨大的性能提升,因为每个新的worker都在自己的线程中运行代码。这意味着worker运行代码不仅不会影响浏览器UI,也不会影响其他worker中运行的代码。

worker 运行环境

由于web workers没有绑定UI线程,这也意味着他们不能访问浏览器的许多资源。web workers从外部线程中修改DOM会导致用户界面出现错误。
但是每个web worker都有自己的全局运行环境,其功能只是js特性的一个子集,worker运行环境由如下部分组成:

  • navigator对象:包含appName、appVersion、user Agent、platform这四个属性
  • location对象
  • self对象:指向全局worker对象
  • importsScripts()方法:用来加载worker所用到的外部js文件
  • 所有的ECMAScript对象,如Object、Array、Date等
  • XMLHttpRequest构造器
  • setTimeout和setInterval方法
  • close()方法:能立即停止worker运行

由于worker有着不同的全局运行环境,因此无法从js代码中创建它。
你需要创建一个完全独立的js文件,其中包含了需要在worker中运行的代码。
然后调用 Worker() 构造函数,指定一个要在 worker 线程内运行的脚本的 URI

var worker = new Worker("code.js");

此代码一旦执行,将会为这个文件创建一个新的线程和一个新的worker运行环境。
该文件会被异步下载,直到文件下载并执行完成后才会启动此worker。

与worker通信

worker与网页代码通过事件接口进行通信。

  • 网页通过postMessage()方法给worker传递数据。它接收一个参数,即需要传递给worker的数据。
  • worker通过onmessage事件处理器来接收信息
var worker = new Worker("code.js");
worker.onmessage = function(event){
alert(event.data);
}
worker.postMessage("hello")

worker通过触发message事件来接收数据。

worker也可以通过她自己的PostMessage方法把信息回传给页面:

self.onmessage = function(event){
self.postMessage("hi"+event.data+ "!")
}

message系统是网页和worker通信的唯一途径。

只有特定类型的数据可以使用postMessage()传递:基本类型值、Object、Array的实例。
这些有效数据会被序列化,传入或传出worker,然后反序列化。

加载外部文件

worker通过importsScripts()方法加载外部js文件,该方法接收一个或多个js文件URL作为参数。
importsScripts()的调用过程是阻塞式的,直到所有文件加载并执行完成之后,脚本才会继续运行。由于worker在UI线程之外运行,因此这种阻塞并不会影响UI响应。

importScripts('foo.js', 'bar.js');      /* 引入两个脚本 */

实际应用

Web workers适用于那些处理纯数据,或者与浏览器UI无关的长时间运行脚本。可能是以下这些任务:

  • 编码/解码大字符串
  • 复杂数学运算(包括图像或视频处理)
  • 大数组排序

Ajax性能指南

缓存数据

最快的ajax请求就是没有请求。有两种主要的方法可以避免发送不必要的请求:

  • 在服务器端,设置HTTP头信息以确保响应会被浏览器缓存
  • 在客户端,把获取到的信息存储到本地,从而避免再次请求

设置HTTP头信息

如果你希望Ajax响应能够被浏览器缓存,那么你必须使用GET方式发出请求,并且在响应中设置缓存相关的头部信息,如Expires。

本地数据存储

除了依赖浏览器处理缓存之外,还可以直接把从服务器接收到的数据储存到一个对象中,以URL为键值作为索引。以后每次请求的时候首先检查本地是否有内容,如果有的话就不发送请求了。

构建与部署

在构建时可以从以下几个方面进行优化:

  • 合并多个js文件
  • 压缩js文件

在运行时也可以进行一些处理优化:

  • js的HTTP压缩
    当浏览器发送请求时,通常会发送一个Accept-EncodingHTTP头来告诉服务器它支持哪种编码转换类型。这个信息主要用来压缩文档以获得更快的下载。
    如果服务器在请求中看到这个信息头,会选择最合适的编码方法,并通过Content-EncodingHTTP头通知浏览器。
    gzip是目前最流行的编码方式,通常能减少70%的下载量。gzip压缩主要适用于文本,其他像图片或者pdf文件不应该使用gzip压缩。

  • 缓存js文件
    设置expires头或者使用HTML5离线应用缓存。

  • 使用CDN
    CDN是在互联网上按离地位置分布计算机网络,通过向地理位置最近的用户传输内容,CDN能极大地减少网络延时。