高性能 JavaScriptの五 -- 快响应用户界面
Posted 空城机
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高性能 JavaScriptの五 -- 快响应用户界面相关的知识,希望对你有一定的参考价值。
快速响应的用户界面
你愿意体验一个交互流畅的网页,还是愿意体验一个点击后卡一会儿才响应的页面(如在学校抢课时网页)?
好的JavaScript编写方式能够提升页面交互响应的速度,以下知识可进行了解与应用
浏览器UI线程
用于执行javascript和更新用户界面的进程通常被称为 “浏览器UI线程”
UI线程的工作基于一个简单的队列系统,任务会被保存到队列中直到进程空闲。 一旦空闲,队列中下一个任务就被重新提取出来并运行。
例子分析:
<button onclick="handleClick()">按钮</button>
<script>
function handleClick() {
var div = document.createElement("div");
div.innerText = "点击了按钮";
document.body.appendChild(div)
}
</script>
这是一个点击按钮,触发handleClick方法的例子
当按钮被点击时,会触发UI线程来创建两个任务并添加到队列当中
两个任务:
- 更新按钮样式,表示被点击的UI
- 执行JavaScript,包含handleClick方法中的代码
实际上,handleClick方法执行中,会添加一个新的div元素到末尾,这又引发了一次UI变化
大多数浏览器在JavaScript运行时会停止把新任务加入UI线程的队列中,所以JavaScript任务必须尽快结束,以避免对用户体验造成不良影响
浏览器限制
浏览器会限制JavaScript任务的运行时间
这种限制是必须的,为了确保某些恶意代码不能通过永不停止的密集操作锁住用户的浏览器或计算机
这种限制分为两种:
- 调用栈大小限制
- 长时间运行(long-running)脚本限制
长时间运行脚本限制也会被称为失控脚本定时器
原理是浏览器会记录一个脚本的运行时间,并在达到一定限度时终止它,浏览器向用户显示一个长时间无响应对话框。
chrome浏览器:
定时器
JavaScript 定时器可以和UI线程进行交互,有助于把运行耗时较长的脚本拆分为较短的片段
定时器的精度
JavaScript定时器的延时通常不会特别精确,相差大约几毫秒,因此定时器不可用于测量实际时间。
在Windows系统中定时器分辨率为15.6毫秒,这是微软故意设置的,它觉得设置精度更低对资源消耗过大,所以一个延时15.6毫秒的定时器将根据最后一次系统时间刷新而转换为0 或 15.
设置定时器延时小于15将会导致IE浏览器锁定,所以延迟的最小值建议设置为25以确保至少有15毫秒延迟。
———— 这就是在写setTimeout
和setInterval
定时方法时,几乎都会把延时时间写的超过一定毫秒以上的原因。
Web Workers
自JavaScript诞生以来,一直是单线程的方式。 但是其实JavaScript也有多线程
存在了,这就是Web Workers的功劳啦!
参考链接来喽:
通过使用Web Workers,Web应用程序可以在独立于主线程的后台线程中,运行一个脚本操作。
好处想必大家也都可以理解,Web Workers API引入了一个接口,能使代码运行且不占用浏览器UI线程的时间。每个新的worker都在自己的线程中运行代码,这意味着Worker运行代码不仅不会影响浏览器UI,也不会影响其他Worker中运行的代码。
Worker运行环境
Worker 接口是 Web Workers API
的一部分,指的是一种可由脚本创建的后台任务,任务执行中可以向其创建者收发信息。要创建一个 Worker ,只须调用 Worker(URL) 构造函数,函数参数 URL
为指定的脚本。Worker 也可以创建新的 Worker,当然,所有 Worker 必须与其创建者同源
- 由于
Web Workers
没有绑定UI线程,这也就意味这它们不能访问浏览器的许多资源了 - JavaScript和UI共享同一进程的部分原因是它们之间互相频繁的访问,因此任务失控会导致糟糕的用户体验
Web Workers
从外部线程修改DOM会导致用户界面出错,但是每个Web Workers
都有自己的全局运行环境- 一个navigator对象,只包括四个属性:appName、appVersion、userAgent和platform
- 一个location对象(与window.location相同,不过所有属性都是只读)
- 一个self对象,指向全局worker对象
- 一个importScripts() 方法,用来加载Worker所用到的外部JavaScript文件
- 所有的ECMAScript对象,诸如:Object、Array、Date等
- XMLHttpRequest构造器
- setTimeout()和setInterval()方法
- 一个close()方法,能够立刻停止Worker运行
由于 Web Workers
是不同的全局运行环境,所以需要我们创建一个完全独立的js文件,里面是在Worker中运行的代码。然后在主流程中 new Worker(Web Workers
代码路径)
var worker = new Worker('code.js')
此代码一旦执行,将创建一个新的线程和一个新的Worker运行环境。该文件会被异步下载,知道文件下载并执行完成后才启动此worker
示例
基础示例:
结构
html中
<body>
<button onclick="clickHandle()"> 点击 </button>
<script>
let worker = new Worker('code.js')
console.log(worker)
function clickHandle() {
// 往worker对象发送一个对象数据
worker.postMessage({
msg: '发送数据进入'
})
}
</script>
</body>
code.js中
console.log("worker启动了!")
// 接收传送的数据
onmessage = function(e) {
console.log(e)
}
达到的效果
注意
这里我使用的软件是vs code,如果大家直接这样打开HTML是会找不到web worker的js文件,这是因为上面提到的同源策略的影响。
可能会报下面的错误
所以需要使其运行在服务器中,这里为了方便简化,我推荐使用一款叫做Live Server的插件。
这款插件具有实时加载功能的小型服务器,可以使用它来破解html/css/javascript,但是不能用于部署最终站点。
运行index.html文件时
实际应用
Web Workers
适用于哪些处理纯数据,或者与浏览器UI无关的长时间运行脚本。
一些可以受益与Web Workers
的任务:
- 编码/解码大字符串
- 复杂数学运算(包括图像或视频处理)
- 大数组排序
小节
- JavaScript的任务最好不要超过100毫秒,过长的运行时间会导致UI更新出现明显的延迟
- 定时器可以帮助你拆分长时间运行脚本为一系列的小任务
Web Workers
是新版浏览器支持的特性,是JavaScript的多线程解决方案
Web应用越复杂,管理UI线程就越重要
即使JavaScript再重要,也不应该影响用户体验
以上是关于高性能 JavaScriptの五 -- 快响应用户界面的主要内容,如果未能解决你的问题,请参考以下文章
从0开始的TypeScriptの五:webpack打包typescript
从0开始的TypeScriptの五:webpack打包typescript