6.1 浏览器UI线程

浏览器UI线程:用于执行JavaScript和更新用户界面的进程。UI线程的工作基于一个简单的队列系统,任务会被保存到队列中直到进程空闲。

--------------------------------------------------------------------
注:如果你对python感兴趣,我这有个学习Python基地,里面有很多学习资料,感兴趣的+Q群:895817687
--------------------------------------------------------------------<html><head><title>Browser UI Thread Example</title></head><body><button onclick="handleClick()">Click Me</button><script type="text/javascript">function handleClick(){var div = document.createElement("div");div.innerHTML = "Clicked!";document.body.appendChild(div);}</script></body></html>

6.1.1 浏览器限制

浏览器限制了JavaScript任务的运行时间,它确保某些恶意代码不能通过永不停止的密集操作锁住用户的浏览器或计算机。此类限制分为两种:调用栈大小限制(第四章讨论过)和长时间运行脚本限制。

对于不同浏览器限制也不一样:

IE:默认500万条语句;
Firefox:默认限制10秒;
Safari:默认限制5秒;
Chrome:没有单独限制,替代做法是依赖其通用崩溃检测系统来处理;
Opera:没有限制,鉴于Opera架构,运行结束时不会导致系统不稳定。

6.1.2 多久才算太久

单个JavaScript操作花费的总时间不应该超过100毫秒。这个数字源自Robert Miller在1968年的研究。如果页面响应超过100毫秒,用户会感到自已与界面失去联系。因此,限制所有的JavaScript任务在100毫秒或更短的时间内完成,才能给用户一个连续的体验。

6.2 使用定时器让出时间片段

尽管尽了最大努力,有时也难免出现复杂的JavaScript任务不能在100毫秒内完成。这时候,最理想的做法是让出UI线程的控制权,使得UI可以更新。
###6.2.1 定时器基础
在JavaScript中可以使用setTimeout()和setInterval()创建定时器。定时器和UI线程的交互方式有助于把运行耗时较长的脚本拆分为较短的片段。

注意:定时器传入的时间参数表示任务被添加到UI线程的时间,而不是一定会在这段时间后执行,它会在队列中等待其他前面所有任务执行完毕才会执行。

    var button = document.getElementById("my-button");button.onclick = function(){oneMethod();setTimeout(function(){document.getElementById("notice").style.color = "red";}, 250);};

注意:定时器代码只有在创建它的函数执行完成之后,才有可能被执行。

    var button = document.getElementById("my-button");button.onclick = function(){oneMethod();setTimeout(function(){document.getElementById("notice").style.color = "red";}, 50); anotherMethod();};

6.2.2 定时器的精度

JavaScript定时器的延迟通常不太精准,相差大约几毫秒。正因为如此,定时器不能用于测量实际时间。设置定时器延迟小于15毫秒会导致IE锁定,所以延迟的最小值建议设为25毫秒,以确保至少有15毫秒延迟。

6.2.3 使用定时器处理数组

在之前讨论的循环优化技术使用后,还不能满足性能要求的时候,下一步优化就是选用定时器。它的基本方法是把循环工作分解到一系列定时器中。
是否可以用定时器取代循环的两个决定性因素:

1:处理过程是否必须同步?
2:数据是否必须按顺序处理?
如果这两个答案都是:否,那么代码将适用于定时器分解任务。

    function processArray(items, process, callback){var todo = items.concat(); // 克隆原数组setTimeout(function(){process(todo.shift()); // 取得数组的下一个元素并进行处理if (todo.length > 0){ // 如果还有需要处理的元素,创建新的定时器setTimeout(arguments.callee, 25); // arguments.callee该值指向当前运行的匿名函数} else {callback(items);}}, 25);}
    // 使用var items = [123, 789, 323, 778, 232, 654, 219, 543, 321, 160];function outputValue(value){console.log(value);}processArray(items, outputValue, function(){console.log("Done!");});

注意:使用定时器的副作用是处理数组的总时长增加了,但为了避免锁定浏览器给用户带来不好的体验,这种取舍是必要的。

6.2.4 分割任务

我们通常会把一个复杂的任务分解成一系列子任务。

    function saveDocument(id){// 保存文档openDocument(id)writeText(id);closeDocument(id);// 将成功信息更新至页面updateUI(id);}
    function multistep(steps, args, callback){var tasks = steps.concat(); // 克隆数组setTimeout(function(){// 执行下一个任务var task = tasks.shift();task.apply(null, args || []);// 检查是否还有其他任务 if (tasks.length > 0){setTimeout(arguments.callee, 25);} else {callback();}}, 25);}
    // 使用function saveDocument(id){var tasks = [openDocument, writeText, closeDocument, updateUI];multistep(tasks, [id], function(){alert("Save completed!");});}

6.2.5 记录代码运行时间

有时每次只执行一个任务的效率不高。如果每次定时器只处理一项,且每项之间产生25毫秒的延迟,这对性能来说是个浪费。如果每个定时器能批处理多个任务,那么效率就上来了。
还记得前面讨论过JavaScript连续运行100毫秒,不会影响用户体验。建议把这个数字减半,不让JavaScript代码持续运行50毫秒,这样确保代码永远不会影响用户体验。

    function timedProcessArray(items, process, callback){var todo = items.concat(); // 克隆原始数组setTimeout(function(){var start = +new Date(); // +可以把Date转换成数字,方便计算do {process(todo.shift());} while (todo.length > 0 && (+new Date() - start < 50));if (todo.length > 0){setTimeout(arguments.callee, 25);} else {callback(items);} }, 25);}

该函数增加了一个do-while循环,保证一个定时器里任务总耗时不超过50毫秒,既增加了效率有不影响用户体验。

6.2.6 定时器与性能

定时器会让JavaScript的代码整体性能发生翻天覆地的变化,但过度使用也会对性能造成负面影响。保证同一时间只有一个定时器存在,才能避免定时器导致的性能问题。

6.3 Web Workers

自JavaScript诞生以来,还没有办法在浏览器UI线程外运行代码。Web Workers改变了这一状况,它引入了一个接口,能使代码运行且不占用浏览器UI线程时间。

6.3.1 Worker运行环境

由于Web Workers没有绑定UI线程,意味着它们不能访问浏览器的许多资源。Web Workers从外部线程中修改DOM会导致用户界面出现错误,但是每个Web Worker都有自己的全局运行环境:

1:一个navigator对象,只包含四个属性:appName,appVersion,userAgent,和platform;
2:一个location对象(和window里的一样,只是所有属性都是只读的);
3:一个self对象指向全局worker对象;
4:一个importScripts()方法,使工人线程可以加载外部 JavaScript 文件;
5:所有ECMAScript对象,诸如Object,Array,Data,等等;
6:XMLHttpRequest构造器;
7:setTimeout()和setInterval()方法;
8:close()方法可立即Worker运行。
由于Web Workers有着不同的全局运行环境,因此无法从JavaScript代码中创建。需要创建一个完全独立的JavaScript文件,包含了需要在Worker中运行的代码。然后引入这个文件:

var worker = new Worker(“code.js”);

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

6.3.2 与Worker通信

Worker与网页代码通过事件接口进行通信。网页代码通过postMessage()方法给Worker传递数据;Worker有一个onmessage事件处理器接收信息,并可以用自己的postMessage()方法把数据传回网页代码。

    // 网页代码var worker = new Worker("code.js");worker.onmessage = function(event){alert(event.data);};worker.postMessage("Nicholas");// code.js内部代码self.onmessage = function(event){self.postMessage("Hello, " + event.data + "!");};

注意:消息系统是网页和Worker通信的唯一途径。

6.3.3 加载外部文件

Worker通过importScripts()方法加载外部JavaScript文件,该方法接收一个或多个JavaScript文件URL作为参数。

    // code.js内部代码importScripts("file1.js", "file2.js");self.onmessage = function(event){self.postMessage("Hello, " + event.data + "!");};

6.3.4 实际应用

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

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

性能优化:任何超过100毫秒的处理过程,都应考虑Worker方案而不是定时器方案。前提是浏览器支持Web Workers。

《高性能JavaScript》第六章 快速响应的用户界面相关推荐

  1. Javascript第六章JavaScript字面量加数组创建对象第三课

    Javascript第六章JavaScript用new创建对象第一课 https://blog.csdn.net/qq_30225725/article/details/89304586 Javasc ...

  2. Javascript第六章JavaScript中构造器创建对象第二课

    Javascript第六章JavaScript用new创建对象第一课 https://blog.csdn.net/qq_30225725/article/details/89304586 Javasc ...

  3. Javascript第六章JavaScript用new创建对象第一课

    Javascript第六章JavaScript用new创建对象第一课 https://blog.csdn.net/qq_30225725/article/details/89304586 Javasc ...

  4. 《高性能JavaScript》第九章 构建并部署高性能JavaScript应用

    本章使用到的技术可能已经过时,主要理解其思想.本章的目的是了解如何有效地组织并部署基于JavaScript的Web应用的一些必要知识. 1:Apache Ant:是一个软件构建自动化工具: 2:合并多 ...

  5. 《高性能JavaScript》第二章 数据存取

    JavaScript四种数据存储位置: 1:字面量:字面量只代表自身,不存储在特定位置.JavaScript中的字面量有:字符串.数字.布尔值.对象.数组.函数.正则表达式,以及null和undefi ...

  6. 《高性能JavaScript》第一章 加载和执行

    1.1 脚本位置 描述 将所有 原因 UI渲染和JavaScript运行共用一个线程, 反例 ----------------------------------------------------- ...

  7. 高性能mysql 第六章_第六章 查询性能优化

    1. 为什么查询速度会慢 如果把查询看作是一个任务,那么它由一系列子任务组成,每个子任务都会消耗一定的时间.如果要优化,无非是减少子任务数量,或者减少子任务的执行次数. 查询声明周期:生成计划,执行, ...

  8. Javascript第六章基本包装类型第八课

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  9. Javascript第六章世上最全常用RegExp正则表达式及表单验证源码第七课

    元字符: 很多不太懂正则的朋友,在遇到需要用正则校验数据时,往往是在网上去找很久,结果找来的还是不很符合要求.所以我最近把开发中常用的一些正则表达式整理了一下,在这里分享一下.给自己留个底,也给朋友们 ...

最新文章

  1. 谈谈服务雪崩、降级与熔断
  2. 如何基于RocketMQ设计一套全链路消息不丢失方案?
  3. GAN不只会造假:捕获数据中额外显著特征,提高表征学习可解释性
  4. 富文本HTML编辑器UEditor
  5. 如何通俗理解计算机视觉、计算机图形、图像处理之间的区别与联系
  6. 信息学奥赛C++语言:移数问题
  7. 组织JSON数据、JSON转换
  8. mysql keepalive_mysql主从之keepalive+MySQL高可用
  9. CentOS7编译安装ntp
  10. AcWing1064.骑士(状压DP)题解
  11. RequestsLibrary库入门介绍
  12. 设计模式之(Composite)组合模式
  13. 历年计算机二级考试Java真题 JAVA笔试试题及答案(部分套题)
  14. MySQL配置+SQLyog安装教程
  15. hackerrank初级篇之Mini-Max Sum
  16. 计算机应用说课稿,中职计算机说课稿
  17. 数字证书的创建与使用(采用java)
  18. signature=cdae83b1c2034e2244a378f624349dfb,恶意软件分析 URL链接扫描 免费在线病毒分析平台 | 魔盾安全分析...
  19. 欧拉角、万向节死锁理解
  20. 鲁大师性能测试要装什么软件吗,鲁大师怎么给电脑跑分?赶快看看你的电脑性能如何吧!...

热门文章

  1. springboot开启redis共享session设置过期时间
  2. 用idea插件将一个spring boot项目部署到docker容器里运行
  3. oracle asm和文件系统,Oracle工具之--ASM与文件系统及跨网络传输文件
  4. ElasticSearch-7.10版本最新万字长文教程【距离搞懂ELK核心你只差这一片文章】
  5. 《移动项目实践》实验报告——Android组合控件
  6. 《服务外包概论》实验报告——版本管理与控制工具的综合应用
  7. JavaScript——判断undefined解决方案
  8. 《Java程序设计》实验报告——Java的对象与类
  9. Hat’s Words
  10. 获取inout框中未改变值的数据_数据分析10——数据分析的基本过程(02)