写点什么

高性能 JavaScriptの五 -- 快响应用户界面

用户头像
空城机
关注
发布于: 2021 年 05 月 22 日
高性能 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 线程来创建两个任务并添加到队列当中两个任务:


  1. 更新按钮样式,表示被点击的 UI

  2. 执行 JavaScript,包含 handleClick 方法中的代码


实际上,handleClick 方法执行中,会添加一个新的 div 元素到<body>末尾,这又引发了一次 UI 变化


大多数浏览器在 JavaScript 运行时会停止把新任务加入 UI 线程的队列中,所以 JavaScript 任务必须尽快结束,以避免对用户体验造成不良影响

浏览器限制

浏览器会限制 JavaScript 任务的运行时间

这种限制是必须的,为了确保某些恶意代码不能通过永不停止的密集操作锁住用户的浏览器或计算机


这种限制分为两种:

  • 调用栈大小限制

  • 长时间运行(long-running)脚本限制


长时间运行脚本限制也会被称为失控脚本定时器

原理是浏览器会记录一个脚本的运行时间,并在达到一定限度时终止它,浏览器向用户显示一个长时间无响应对话框。




chrome 浏览器:

chrome无响应弹窗


退出,网页崩溃



定时器

JavaScript 定时器可以和 UI 线程进行交互,有助于把运行耗时较长的脚本拆分为较短的片段

定时器的精度

JavaScript 定时器的延时通常不会特别精确,相差大约几毫秒,因此定时器不可用于测量实际时间


在 Windows 系统中定时器分辨率为 15.6 毫秒,这是微软故意设置的,它觉得设置精度更低对资源消耗过大,所以一个延时 15.6 毫秒的定时器将根据最后一次系统时间刷新而转换为 0 或 15.


设置定时器延时小于 15 将会导致 IE 浏览器锁定,所以延迟的最小值建议设置为 25 以确保至少有 15 毫秒延迟。 ———— 这就是在写setTimeoutsetInterval定时方法时,几乎都会把延时时间写的超过一定毫秒以上的原因。

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,但是不能用于部署最终站点。

vs code商店

运行 index.html 文件时

运行Live Server


实际应用

Web Workers适用于哪些处理纯数据,或者与浏览器 UI 无关的长时间运行脚本。


一些可以受益与Web Workers的任务:

  • 编码/解码大字符串

  • 复杂数学运算(包括图像或视频处理)

  • 大数组排序


小节

  • JavaScript 的任务最好不要超过 100 毫秒,过长的运行时间会导致 UI 更新出现明显的延迟

  • 定时器可以帮助你拆分长时间运行脚本为一系列的小任务

  • Web Workers是新版浏览器支持的特性,是 JavaScript 的多线程解决方案


Web 应用越复杂,管理 UI 线程就越重要


即使 JavaScript 再重要,也不应该影响用户体验

发布于: 2021 年 05 月 22 日阅读数: 1273
用户头像

空城机

关注

曾经沧海难为水,只是当时已惘然 2021.03.22 加入

业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步

评论

发布
暂无评论
高性能 JavaScriptの五 -- 快响应用户界面