【你不知道的JavaScript】(04)Web Worker+性能测试

本文章仅针对我自己在看书过程中对一些不太清楚的知识点进行查漏补缺——《你不知道的JavaScript(中卷)》第二部分异步和性能中的第五章”程序与性能“、第六章”性能测试与调优“

Web Worker

为什么需要Worker

如果开发者在浏览器中有一些密集型的任务处理,浏览器是基于JavaScript语言的,而JS是单线程,是不是意味着我们在处理密集型任务时会阻塞浏览器,给用户带来不好的体验呢?

不是的。虽然JS是单线程的,但浏览器这样的环境可以提供多个JS引擎实例,各自运行在自己的线程上。程序中每一个独立的多线程部分被称为一个Web Worker

有什么特点

Worker 之间以及它们和主程序之间,不会共享任何作用域或资源,不需要考虑多线程编程的问题,只通过基本的事件消息机制相互联系

从 JavaScript 主程序(或另一个 Worker)中,可以这样实例化一个Worker,收发消息

var w1 = new Worker( "http://some.url.1/mycoolworker.js" );

w1.addEventListener( "message", function(evt){
  // evt.data
} );

w1.postMessage( "something cool to say" );

URL 应该指向一个 JavaScript 文件的位置,这个文件将被加载到一个 Worker 中,然后浏览器启动一个独立的线程,让这个文件在这个线程中作为独立的程序运行

可以执行网络操作(Ajax、WebSockets)以及设定定时器。

可以访问几个重要的全局变量和功能的本地复本,包括navigator 、location 、JSON 和 applicationCache

可以通过 importScripts(..) 向 Worker 加载额外的 JavaScript脚本,但脚本加载是同步的,会阻塞接下来Worker的执行,直到文件加载和执行完成

共享Worker

如果你的站点或 app 允许加载同一个页面的多个 tab,那你可能非常希望通过防止重复专用 Worker 来降低系统的资源使用。在这一方面最常见的有限资源就是 socket 网络连接,因为浏览器限制了到同一个主机的同时连接数目。当然,限制来自于同一客户端的连接数也减轻了你的资源压力在这种情况下,创建一个整个站点或 app 的所有页面实例都可以共享的中心 Worker 就非常有用了

这称为 SharedWorker ,可通过下面的方式创建

var w1 = new SharedWorker( "http://some.url.1/mycoolworker.js" );
// 在共享Worker内部
w1.addEventListener("connect", function (evt) {
  // 这个连接分配的端口
  var port = evt.ports[0];
  port.addEventListener("message", function (evt) {
    // ..
    port.postMessage();
    // ..
  });
  // 初始化端口连接
  port.start();
});

SIMD

单指令多数据(SIMD)是一种数据并行 方式,与Web Worker 的任务并行 (task parallelism)相对,因为这里的重点实际上不再是把程序逻辑分成并行的块,而是并行处理数据的多个位。

通过 SIMD,线程不再提供并行。取而代之的是,现代 CPU 通过数字“向量”(特定类型的数组),以及可以在所有这些数字上并行操作的指令,来提供 SIMD 功能。

性能测试

不准确的性能测试方案

var start = (new Date()).getTime(); // 或者Date.now()
// 进行一些操作
var end = (new Date()).getTime();
console.log( "Duration:", (end - start) );
  1. 测试的环境或者说平台精度不高

如果测试的结果是0ms,用户可能会认为执行时间小于1ms,但其实有的平台精度没有达到1ms,而是以更大的递归间隔更新定时器,比如IE早期版本精度只有15ms

  1. 测试环境可能会过度优化

JavaScript 引擎找到了什么方法来优化你这个独立的测试用例

  1. for循环后取平均的错误思想

迭代 100 次,即使只有几个(过高或过低的)的异常值也可以影响整个平均值

要确保把异常因素排除,你需要大量的样本来平均化。你还会想要知道最差样本有多慢,最好的样本有多快,以及最好和最差情况之间的偏离度有多大

Benchmark.js

Benchmark.js是一个统计学上有效的性能测试工具

jsperf.com

如果想要得到可靠的测试结论,需要在很多不同的环境(桌面浏览器、移动设备,等等)中测试汇集测试结果

比如,针对同样的测试高端桌面机器的性能很可能和智能手机上Chrome 移动设备完全不同。而电量充足的智能手机上的结果可能也和同一个智能手机但电量只有 2% 时完全不同,因为这时候设备将会开始关闭无线模块和处理器

jsperf使用 Benchmark.js 库来运行统计上精确可靠的测试,并把测试结果放在一个公开可得的 URL上

尾调用

尾调用(TCO)就是一个出现在另一个函数“结尾”处的函数调用

ES6要求引擎实现TCO

function foo(x) {
  return x;
}
function bar(y) {
  return foo( y + 1 ); // 尾调用
}
function baz() {
  return 1 + bar( 40 ); // 非尾调用
}
baz(); // 42

调用一个新的函数需要额外的一块预留内存来管理调用栈,称为栈帧

如果支持 TCO 的引擎能够意识到 foo(y+1) 调用位于尾部 ,这意味着 bar(..) 基本上已经完成了,那么在调用 foo(..) 时,它就不需要创建一个新的栈帧,而是可以重用已有的 bar(..) 的栈帧。这样不仅速度更快,也更节省内存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值