首页
统计
墙纸
留言
Search
1
PVE8优化
19 阅读
2
mysql创建数据库
12 阅读
3
jenkins根据分支、文件夹打包
12 阅读
4
vue-cli注册全局方法
7 阅读
5
开心的加班
7 阅读
web前端
Vue
CSS
javascript
React
那些年爬过过的坑
ES6
TypeScrippt
ES7
javascript图灵 - 总结
Node
面试总结
React-Native
Web优化
基础
AngularJS
拍摄
Flutter
Dart
Docker
Linux
mysql
PVE
登录
/
注册
Search
标签搜索
vue+elementui
Cicaba
累计撰写
146
篇文章
累计收到
13
条评论
首页
栏目
web前端
Vue
CSS
javascript
React
那些年爬过过的坑
ES6
TypeScrippt
ES7
javascript图灵 - 总结
Node
面试总结
React-Native
Web优化
基础
AngularJS
拍摄
Flutter
Dart
Docker
Linux
mysql
PVE
页面
统计
墙纸
留言
搜索到
11
篇与
的结果
2019-07-15
JavaScript的算法和流程控制性能优化
如同其他编程语言,代码的写法和算法会影响JavaScript的运行时间,与其他语言的不同的是,JavaScript的可用资源有限,因此优化技术更为重要,这个学习笔记主要是从JavaScript的循环、条件语句、递归这三个方面的一些奇淫技巧来优化JavaScript的性能。循环for、while和do-while循环性能特性相似,for-in相比前三者慢由于每次迭代操作会同时搜索实例或者原型属性,for-in循环的每次迭代都会产生更多的开销,因此比其他循环类型要慢,对比相同迭代次数的循环,for-in循环最终只有其他类型速度的1/7,因此,除非你明确需要迭代一个属性数量未知的对象,否则应该避免使用for-in循环。还有不要使用for-in来循环数组成员。 改善循环性能的最佳方式是减少每次迭代的运算量和减少循环迭代次数。forEach(),此方法是ECMA-262引入的一新的原生数组方法,此方法遍历一个数组的多有成员,并且在每个成员上面执行一个函数。//基于函数的迭代方法 item.forEach(function(value,index,array){ process(value); }) //方便!!但是慢,这个要考虑。条件语句通常来说,switch总是比if-else快,并不总是最佳解决方案使用if-else还是switch,基于测试条件的数量来判断:条件数量越大,越倾向于使用switch(考虑到代码的易读性),反之if-else更易读。事实证明,大多数情况下switch比if-else运行得要快,但只有当条件数量很大时候才快得明显。优化if-else,确保最可能出现的放在首位优化的目标是使最小化到达正确分支所需判断的条件数量,最简单的就是确保最可能出现的放首位。还有一种减少判断次数的方法是把if-else组成一系列的嵌套的if-else语句。当你使用查找表时候,必须完全抛弃条件判断语句,这个过程变成数组项查询或者对象成员查询。优点:不用写任何条件判断语句,既是候选值增加时,也几乎不会产生额外的性能开销。在判断调节较多的时候,使用查找表比if-else和swich更快//将返回值存入数组 var results=[result0,result1,result2,result3,result4,result5, result6,result7,result8,result09] //返回当前结果 return results[value];递归浏览器的调用栈大小限制了递归算法在JavaScript中的应用,栈溢出错误会导致其他代码中断运行。如果你遇到栈溢出错误,可以将方法改为迭代算法,或使用Memoization来避免重复计算。合并字符串拼接字符串是编程中最常见的操作了,我们先来总结一下 JavaScript 中连接字符串的方法:++=Array.prototype.join()String.prototype.concat()ES6 新增的模板字符串当拼接少量较短字符串,以上这些方法速度都差不多。但随着需要连接的字符串的长度和数量的增加,一些方法开始展现出优势。待连接字符串是变量如果要拼接的字符串中有以变量形式存在的字符串,优先使用 ES6 中的模板字符串。将变量名包裹在 ${} 中,然后使用反引号(` )包裹变量和普通字符串:`${username}学会了开车.`+ 和 +=我们首先必需弄明白一点,在 JavaScript 中字符串一经初始化值便是不可改变的。下面是一个拼接字符串的常见操作:str += 'now' + 'old';上面代码在运行时,会历经以下四个步骤:在内存中创建一个临时字符串拼接后的字符串 nowold被赋值给该临时字符串临时字符串与 str 当前的值进行连接将上一步的拼接结构赋值给 str为了避免产生临时字符串造成额外的性能开销,我们可以这样做:str += 'now'; str += 'old'; 如果使用下面这种方式,我们能获得更显著的性能提升:str = str + 'now' + 'old'; // 等价于 str = ((str + 'now') + 'old');注意,上面代码中如果赋值号右侧表达式中的 str 不是处在最左侧,那么将得不到优化效果,这与浏览器合并字符串时分配内存的方法有关。大多数浏览器都会尝试为表达式左侧的字符串分配更多的内存,然后简单地将第二个字符串拷贝至它的末尾。如果在一个循环中,基础字符串位于最左侧的位置,就可以避免重复拷贝一个逐渐变大的基础字符串。合并数组项Array.prototype.join() 方法将数组中地所有元素合并成一个字符串,它接收一个参数作为每项之间的分隔符。如果传入参数为空字符,那么我们就可以使该方法将所有数组项连接为一个字符串。然而,现实情况是,在大多数浏览器中,数组项合并比其他字符串连接方法更慢。String.prototype.concat()包装类型 String 的原生方法 String.prototype.concat() 能够接受任意数量的参数,并将每一个参数附加到所调用的字符串上,这是最灵活的字符串合并方法。遗憾的是,在多数情况下,使用 cancat() 方法比使用简单的 + 和 += 稍慢。总结:如果要合并的字符串中存在变量,那么使用模板字符串;否则,仅使用简单的 + 操作符合并字符串,并将基础字符串置于表达式最左侧。
2019年07月15日
1 阅读
0 评论
0 点赞
2019-07-15
Ajax优化
Ajax是高性能JavaScript的基础,它可以通过延迟下载体积较大的资源文件来使页面加载更快,它通过异步的方式在客户端和服务器之间传递数据,从而避免页面资源一窝蜂的下载。它甚至可以只用一个HTTP请求就获得整个页面的资源。选择合适的传输方式和最有效的数据格式,可以显著改善用户和网站的交互体验。我们这里主要讨论从服务器接收发数据速度最快的技术,以及最为有效的数据编码格式。常用的向服务器请求数据的技术XMLHttpRequest(XML)使用规范var url = '/data.php'; var params = [ 'id=9798', 'limit=20' ]; var req = new XMLHttpRequest(); req.onreadystatechange = function() { if (req.readyState === 4) { //获取响应的头信息 var responseHeaders = req.getAllResponseHeaders(); //获取数据 var data = req.responseText; //数据处理 } } req.open('GET', url + '?' + params.join('&'), true); //设置请求头信息 req.setRequestHeader('X-Request-With', 'XMLHttpRequest'); req.send(null); //发送一个请求当使用XHR请求数据时候,对于那些不会改变服务器状态,只会获取数据的请求,应该使用GET。经GET请求的数据会被缓存起来,如果需要多次请求统一数据,它会有助于提高性能。 只有当请求URL加上参数长度接近或者超过2048个字符时候,才应该使用POST获取数据,这是因为IE限制了URL长度,过长请求会被截断。动态脚本注入这种方法克服了XHR的最大限制:它能跨域请求。你不需要实例化一个专用对象,而可以使用JavaScript创建一个新的脚本标签,并设置它的属性为不同域的URL,但是和XHR相比,动态脚本注入提供的控制是有限的,你不能设置请求头信息,传递参数也只能使用GET,不能设置请求的超时处理和重试,也就是说失败了你也不一定知道。你必须等到所有数据都返回你才可以访问它们。你不能请求头信息,也不能把整个响应信息作为字符串来处理。还有必须是可执行的JavaScript源码,而且必须封装在一个回调函数中。var scriptElement=document.createElement('script'); scriptElement.src='http://any-domain.com/javascript/data.js'; document.getElementByTagName('head')[0].appendChild(scriptElement); function jsonCallback(jsonString){ var data=eval('('+jsonString+')'); //处理数据... } //在上面那个例子里,data.js必须把数据封装在jsonCallback函数里面: jsonCallback({"status":1,"color":["#fff","#000","f00"]}); //尽管有很多限制,但是这项技术的速度非常快。Multipart XHRMXHR允许客户端只使用一个HTTP请求就可以从服务端向客户端传送多个资源,它通过在服务端将资源(CSS文件,HTML片段,JavaScript代码,或base64编码的图片)打包成一个双方约定的字符串并发送到客户端,然后用JavaScript代码处理这个长字符串,并根据它的mime-type类型和传入其他头信息解析出每个资源。 但是以这种技术获得的资源不能够被浏览器缓存 ,但是某些情况下MXHR依然能显著提高页面的整体性能。发送数据给服务器XMLHttpRequest数据可以使用GET或POST的方式传回来,包括任意数量的HTTP头信息,当使用XHR发送数据给服务器时候,使用GET会更快,只需要发送一个数据包,POST至少两个数据包,一个装载头信息,一个装载POST正文。POST更适合发送大量数据到服务器。var url = '/data.php'; var params = [ 'id=9798', 'limit=20' ]; var req = new XMLHttpRequest(); req.onerror=function(){ //出错 }; req.onreadystatechange = function() { if (req.readyState === 4) { //成功 } } req.open('POST',url, true); req.setRequstHeader('Content-Type','application/x-www-form-urlencoded'); req.setRequstHeader('Content-Length',params.length); req.send(params.join('&')); Beacons(图片信标)这项技术非常类似动态脚本注入。使用JavaScript创建一个新的Image对象,并把src属性设置为服务器上传脚本的URL。该URL包含我们通过GET传回的键值对数据。请注意并没有创建img元素或把它插入DOM。var url='/status_tracker.php'; var params=[ 'step=2', 'time=123241223' ]; (new Image()).src=url+'?'+params.join('&');服务器会接收数据并保存下来,它无需向客户端发送任何回馈信息,因为没有图片会实际显示出来,这是往服务器回传信息最有效的方式。它的性能消耗很小,而且服务器的错误完全不会影响客户端。如果你需要返回大量数据给客户端,那么请使用XHR,如果你只关心发送数据给服务器(可能需要极少的返回信息),那么请使用图片信标。数据格式的选择通常来说数据格式越轻量越好,JSON和字符串分割的自定义格式是最好的。如果数据集很大并且对解析时间有要求,那么请从如下两种格式中做出选择。JSON-P格式:使用动态脚本注入获取他把数据当作可以执行的JavaScript而不是字符串,解析速度极快。它能够跨域使用,但涉及敏感数据的时候不应该使用它。字符分割的自定义格式:使用XHR或动态脚本注入获取,用split()解析。这种技术解析大数据集比JSON-P略快,而且通常文件尺寸更小。Ajax性能总结一旦选择了最合适和数据传输技术和数据格式,那么你就得开始考虑其他优化技术了:减少请求数,可以通过合并JavaScript和CSS文件,或者使用MXHR。缩小页面的加载时间,页面主要内容加载完成后,用Ajax获取那些次要的文件。确保你的代码错误不会输出给用户,并在服务端处理错误。知道何时使用成熟的Ajax类库,以及编写自己的底层Ajax代码。
2019年07月15日
2 阅读
0 评论
0 点赞
2019-07-05
CSS优化
1.内联首屏关键CSS大家应该都习惯于通过link标签引用外部CSS文件。但需要知道的是,将CSS直接内联到HTML文档中能使CSS更快速地下载。而使用外部CSS文件时,需要在HTML文档下载完成后才知道所要引用的CSS文件,然后才下载它们。所以说,内联CSS能够使浏览器开始页面渲染的时间提前,因为在HTML下载完成之后就能渲染了。既然内联CSS能够使页面渲染的开始时间提前,那么是否可以内联所有的CSS呢?答案显然是否定的,这种方式并不适用于内联较大的CSS文件。因为初始拥塞窗口存在限制(TCP相关概念,通常是 14.6kB,压缩后大小),如果内联CSS后的文件超出了这一限制,系统就需要在服务器和浏览器之间进行更多次的往返,这样并不能提前页面渲染时间。因此,我们应当只将渲染首屏内容所需的关键CSS内联到HTML中。不过内联CSS有一个缺点,内联之后的CSS不会进行缓存,每次都会重新下载。不过如上所说,如果我们将内联后的文件大小控制在了14.6kb以内,这似乎并不是什么大问题。2.异步加载CSSCSS会阻塞渲染,在CSS文件请求、下载、解析完成之前,浏览器将不会渲染任何已处理的内容。有时,这种阻塞是必须的,因为我们并不希望在所需的CSS加载之前,浏览器就开始渲染页面。那么将首屏关键CSS内联后,剩余的CSS内容的阻塞渲染就不是必需的了,可以使用外部CSS,并且异步加载。3.有选择地使用选择器大多数朋友应该都知道CSS选择器的匹配是从右向左进行的,这一策略导致了不同种类的选择器之间的性能也存在差异。相比于#box-content-h3,显然使用#box .content h3时,浏览器生成渲染树(render-tree)所要花费的时间更多。因为后者需要先找到DOM中的所有h3元素,再过滤掉祖先元素不是.content的,最后过滤掉.content的祖先不是#box的。试想,如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高。优化方案保持简单,不要使用嵌套过多过于复杂的选择器。通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。4.减少使用昂贵的属性在浏览器绘制屏幕时,所有需要浏览器进行操作或计算的属性相对而言都需要花费更大的代价。当页面发生重绘时,它们会降低浏览器的渲染性能。所以在编写CSS时,我们应该尽量减少使用昂贵属性,如box-shadow/border-radius/filter/透明度/:nth-child等。
2019年07月05日
1 阅读
0 评论
0 点赞
2019-07-05
HTML优化
JavaScript中使用document.write生成页面内容会效率较低,可以找一个容器元素,比如指定一个div,并使用innerHTML来将HTML代码插入到页面中。当link标签的href属性为空、script标签的src属性为空的时候,浏览器渲染的时候会把当前页面的URL作为它们的属性值,从而把页面的内容加载进来作为它们的值。为文件头指定Expires。使内容具有缓存性,避免了接下来的页面访问中不必要的HTTP请求。重构HTML,把重要内容的优先级提高。Post-load(次要加载)不是必须的资源。利用预加载优化资源。合理架构,使DOM结构尽量简单。利用LocalStorage合理缓存资源。尽量避免CSS表达式和滤镜。尝试使用defer方式加载Js脚本。新特性:will-change,把即将发生的改变预先告诉浏览器。新特性Beacon,不堵塞队列的异步数据发送。不同之处:网络缓慢,缓存更小,不令人满意的浏览器处理机制。尽量多地缓存文件。使用HTML5 Web Workers来允许多线程工作。为不同的Viewports设置不同大小的Content。正确设置可Tap的目标的大小。使用响应式图片。支持新接口协议(如HTTP2)。未来的缓存离线机制:Service Workers。未来的资源优化Resource Hints(preconnect, preload, 和prerender)。使用Server-sent Events。设置一个Meta Viewport。
2019年07月05日
3 阅读
0 评论
0 点赞
2019-07-04
JavaScript的DOM编程性能优化
DOM是Document Object Model的缩写,中文叫做文档对象模型,是一个与语言无关的,用户操作XML和HTML文档的应用程序接口。在浏览器中,主要与HTML文档打交道,在Web应用中也经常需要检索XML文档,DOM API用于访问文档中的数据。我们把DOM和JavaScript各自想象成一个岛屿,它们直接用收费桥梁连接,ECMAScript每次访问DOM,都要经过这个桥,并交纳“过桥费”,过的桥越多交的费用也越多,因此要想减少费用就得少过桥,我们这里就来如何来优化这个问题最小化DOM访问次数,尽可能在JavaScript端处理访问DOM元素是有代价的–前面提到的过桥费。修改元素则更加昂贵,因为它会导致浏览器重新计算页面的集合变化。也就是说访问DOM次数越多,代码的运行速度就越慢,因此一般的经验法则是:减少DOM的访问次数,把运算尽量留在ECMAScript这一段处理。 //最坏的情况是在循环中访问和修改元素 //尤其是对HTML元素集合循环操作。 //方法一 function innerHTMLLoop() { for (var count = 0; count < 15000; count++) { document.getElementById('here').innerHTML += 'a'; } } //方法二 function innerHTMLLoop() { var content = ''; for (var count = 0; count < 15000; count++) { content += 'a'; } document.getElementById('here').innerHTML += content; } //显然方法二的实现要好很多多次访问DOM节点,使用局部变量存储它的引用这些方法返回值是一个集合document.getElementByName()document.getElementByClassName()document.getElementByTagName()下面属性也同样返回HTML集合document.imagesdocument.linksdocument.formsdocument.forms[0].elements这些集合是一些昂贵的东西,一般来说,对于任何类型的DOM访问,当同一个DOM属性或方法需要多次访问时候,最好把一个局部变量缓存此成员。当遍历一个集合时,首先优化原则是把集合存储在局部变量中,并把length缓存在循环外部,然后使局部变量访问这些需要多次访问的元素。使用速度最快的API浏览器提供了一个名为querySelectorAll()的原生DOM方法,这种方法自然比使用JavaScript和DOM来遍历查找元素要快很多。//查找id="menu"的元素中的所有a元素 //我们习惯做法 var elements=document.getElementById('menu').getElementsByTagName('a'); //建议做法 var elements=document.querySelectAll('#menu a');还有一个遍历方法–querySelector()来获取第一个匹配的节点。留意重绘和重排DOM树:表示页面结构渲染树:表示DOM节点如何显示一旦DOM和渲染树构建完成,浏览器就开始显示(绘制)页面元素了,当DOM的变化影响的元素的几何属性(宽或高),比如修改边框宽度或给段落增加元素,导致行数增加–浏览器需要重新计算元素的集合属性,同样其他元素的几何属性和位置也会因此受到影响,浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程就称为“重排(reflow)”。完成重排后,浏览器重新绘制受影响的部分到屏幕中,这个过程就叫做重绘(repaint)重排和重绘操作都是代缴昂贵的操作,应当减少发生,为了减少发生次数,应当合并DOM和样式的修改,然后一次性处理掉。还可以通过缓存布局信息的方法:尽量减少布局信息的获取次数,获取后把它赋值给局部变量,然后再操作局部变量。减少在循环内进行DOM操作,在循环外部进行DOM缓存//优化前代码 var _li = $("<li>"), _dom = $("<div>"), timer = null; for (var i = 0; i < 50; i++) { //随机生成50个li,插入到ul列表中 $(".list-ul").append(_li.clone()); }//优化后代码 var _li = $("<li>"), _dom = $("<div>"), _lis = document.getElementsByTagName("li"), timer = null, _arr = []; for (var i = 0; i < 50; i++) { //随机生成50个li,存入到数组中 _arr.push(_li.clone()); } //将生成好的全部li一次性append到ul中 $(".list-ul").append(_arr);优化前的代码中,对于 $(".list-ul") 元素进行了50次的append,即进行了50次的DOM操作。而对于优化后的代码,在append操作前,先将所有 存入数组中,最后只进行了一次append,因此性能会有所提高。操作DOM前,先把DOM节点删除或隐藏list.style.display = "none"; for (var i=0; i < items.length; i++){ var item = document.createElement("li"); item.appendChild(document.createTextNode("Option " + i); list.appendChild(item); } list.style.display = "";display属性值为none的元素不在渲染树中,因此对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行多次DOM操作,可以先将其隐藏,操作完成后再显示。这样只在隐藏和显示时触发2次重排,而不会是在每次进行操作时都出发一次重排。
2019年07月04日
5 阅读
0 评论
0 点赞
2019-06-20
动态创建script标签
使用动态创建的标签元素来下载并执行代码var script = document.createElement('script'); script.type = "text/javascript"; script.src = "file.js"; document.querySelector("head").appendChild(script);这种方式加载脚本好处。无论何时启动下载,文件的下载和执行过程不会阻塞页面其他进程。缺点:你无法处理脚本加载失败。使用XHR对象下载JS代码注入页面var xhr = new XMLHttpRequest(); xhr.open("get", "script1.js", true); xhr.onreadystatechange = function(){ if (xhr.readyState == 4){ if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){ var script = document.createElement ("script"); script.type = "text/javascript"; script.text = xhr.responseText; document.body.appendChild(script); } } }; xhr.send(null); 此代码向服务器发送一个获取 script1.js 文件的 GET 请求。onreadystatechange 事件处理函数检查readyState 是不是 4,然后检查 HTTP 状态码是不是有效(2XX 表示有效的回应,304 表示一个缓存响应)。如果收到了一个有效的响应,那么就创建一个新的<script>元素,将它的文本属性设置为从服务器接收到的 responseText 字符串。这样做实际上会创建一个带有内联代码的<script>元素。一旦新<script>元素被添加到文档,代码将被执行,并准备使用。 这种方法的主要优点是,您可以下载不立即执行的 JavaScript 代码。由于代码返回在<script>标签之外(换句话说不受<script>标签约束),它下载后不会自动执行,这使得您可以推迟执行,直到一切都准备好了。另一个优点是,同样的代码在所有现代浏览器中都不会引发异常。 此方法最主要的限制是:JavaScript 文件必须与页面放置在同一个域内。
2019年06月20日
2 阅读
0 评论
0 点赞
2019-05-24
table表头固定
HTML部分<div style="width: 800px;"> <div class="table-head"> <table> <colgroup> <col style="width: 80px;" /> <col /> </colgroup> <thead> <tr><th>序号</th><th>内容</th></tr> </thead> </table> </div> <div class="table-body"> <table> <colgroup><col style="width: 80px;" /><col /></colgroup> <tbody> <tr><td>1</td><td>我只是用来测试的</td></tr> <tr><td>2</td><td>我只是用来测试的</td></tr> <tr><td>3</td><td>我只是用来测试的</td></tr> <tr><td>4</td><td>我只是用来测试的</td></tr> <tr><td>5</td><td>我只是用来测试的</td></tr> <tr><td>6</td><td>我只是用来测试的</td></tr> <tr><td>7</td><td>我只是用来测试的</td></tr> <tr><td>8</td><td>我只是用来测试的</td></tr> <tr><td>9</td><td>我只是用来测试的</td></tr> <tr><td>10</td><td>我只是用来测试的</td></tr> <tr><td>11</td><td>我只是用来测试的</td></tr> <tr><td>12</td><td>我只是用来测试的</td></tr> <tr><td>13</td><td>我只是用来测试的</td></tr> <tr><td>14</td><td>我只是用来测试的</td></tr> <tr><td>15</td><td>我只是用来测试的</td></tr> </tbody> </table> </div> </div>Css部分.table-head{padding-right:17px;background-color:#999;color:#000;} .table-body{width:100%; height:300px;overflow-y:scroll;} .table-head table,.table-body table{width:100%;} .table-body table tr:nth-child(2n+1){background-color:#f2f2f2;}
2019年05月24日
1 阅读
0 评论
0 点赞
2019-04-01
Web worker
Web workerWeb Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。这样的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。Worker 线程一旦新建成功,就会始终运行,不会被主线程上的活动(比如用户点击按钮、提交表单)打断。这样有利于随时响应主线程的通信。但是,这也造成了 Worker 比较耗费资源,不应该过度使用,而且一旦使用完毕,就应该关闭。Web Worker 有以下几个使用注意点。(1)同源限制分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。(2)DOM 限制Worker 线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的 DOM 对象,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。(3)通信联系Worker 线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。(4)脚本限制Worker 线程不能执行alert()方法和confirm()方法,但可以使用 XMLHttpRequest 对象发出 AJAX 请求。(5)文件限制Worker 线程无法读取本地文件,即不能打开本机的文件系统(file://),它所加载的脚本,必须来自网络。基本用法1 主线程主线程采用new命令,调用Worker()构造函数,新建一个 Worker 线程。var worker = new Worker('work.js');Worker()构造函数的参数是一个脚本文件,该文件就是 Worker 线程所要执行的任务。由于 Worker 不能读取本地文件,所以这个脚本必须来自网络。如果下载没有成功(比如404错误),Worker 就会默默地失败。然后,主线程调用worker.postMessage()方法,向 Worker 发消息。worker.postMessage('Hello World');worker.postMessage({method: 'echo', args: ['Work']});worker.postMessage()方法的参数,就是主线程传给 Worker 的数据。它可以是各种数据类型,包括二进制数据。接着,主线程通过worker.onmessage指定监听函数,接收子线程发回来的消息。worker.onmessage = function (event) { console.log('Received message ' + event.data); doSomething(); } function doSomething() { // 执行任务 worker.postMessage('Work done!'); }上面代码中,事件对象的data属性可以获取 Worker 发来的数据。Worker 完成任务以后,主线程就可以把它关掉。worker.terminate();2 Worker 线程Worker 线程内部需要有一个监听函数,监听message事件。self.addEventListener('message', function (e) { self.postMessage('You said: ' + e.data); }, false);上面代码中,self代表子线程自身,即子线程的全局对象。因此,等同于下面两种写法。// 写法一this.addEventListener('message', function (e) { this.postMessage('You said: ' + e.data); }, false);// 写法二addEventListener('message', function (e) { postMessage('You said: ' + e.data); }, false);除了使用self.addEventListener()指定监听函数,也可以使用self.onmessage指定。监听函数的参数是一个事件对象,它的data属性包含主线程发来的数据。self.postMessage()方法用来向主线程发送消息。根据主线程发来的数据,Worker 线程可以调用不同的方法,下面是一个例子。self.addEventListener('message', function (e) { var data = e.data; switch (data.cmd) { case 'start': self.postMessage('WORKER STARTED: ' + data.msg); break; case 'stop': self.postMessage('WORKER STOPPED: ' + data.msg); self.close(); // Terminates the worker. break; default: self.postMessage('Unknown command: ' + data.msg); }; }, false);上面代码中,self.close()用于在 Worker 内部关闭自身。3 Worker 加载脚本Worker 内部如果要加载其他脚本,有一个专门的方法importScripts()。importScripts('script1.js');该方法可以同时加载多个脚本。importScripts('script1.js', 'script2.js');4 错误处理主线程可以监听 Worker 是否发生错误。如果发生错误,Worker 会触发主线程的error事件。worker.onerror(function (event) { console.log([ 'ERROR: Line ', e.lineno, ' in ', e.filename, ': ', e.message ].join('')); });// 或者worker.addEventListener('error', function (event) { // ...});Worker 内部也可以监听error事件。5 关闭 Worker使用完毕,为了节省系统资源,必须关闭 Worker。// 主线程worker.terminate();// Worker 线程self.close();API1 主线程浏览器原生提供Worker()构造函数,用来供主线程生成 Worker 线程。var myWorker = new Worker(jsUrl, options);Worker()构造函数,可以接受两个参数。第一个参数是脚本的网址(必须遵守同源政策),该参数是必需的,且只能加载 JS 脚本,否则会报错。第二个参数是配置对象,该对象可选。它的一个作用就是指定 Worker 的名称,用来区分多个 Worker 线程。// 主线程var myWorker = new Worker('worker.js', { name : 'myWorker' });// Worker 线程self.name // myWorkerWorker()构造函数返回一个 Worker 线程对象,用来供主线程操作 Worker。Worker 线程对象的属性和方法如下。Worker.onerror:指定 error 事件的监听函数。Worker.onmessage:指定 message 事件的监听函数,发送过来的数据在Event.data属性中。Worker.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。Worker.postMessage():向 Worker 线程发送消息。Worker.terminate():立即终止 Worker 线程。2 Worker 线程Web Worker 有自己的全局对象,不是主线程的window,而是一个专门为 Worker 定制的全局对象。因此定义在window上面的对象和方法不是全部都可以使用。Worker 线程有一些自己的全局属性和方法。self.name: Worker 的名字。该属性只读,由构造函数指定。self.onmessage:指定message事件的监听函数。self.onmessageerror:指定 messageerror 事件的监听函数。发送的数据无法序列化成字符串时,会触发这个事件。self.close():关闭 Worker 线程。self.postMessage():向产生这个 Worker 线程发送消息。self.importScripts():加载 JS 脚本。实例:Worker 线程完成轮询有时,浏览器需要轮询服务器状态,以便第一时间得知状态改变。这个工作可以放在 Worker 里面。function createWorker(f) { var blob = new Blob(['(' + f.toString() +')()']); var url = window.URL.createObjectURL(blob); var worker = new Worker(url); return worker; } var pollingWorker = createWorker(function (e) { var cache; function compare(new, old) { ... }; setInterval(function () { fetch('/my-api-endpoint').then(function (res) { var data = res.json(); if (!compare(data, cache)) { cache = data; self.postMessage(data); } }) }, 1000) }); pollingWorker.onmessage = function () { // render data } pollingWorker.postMessage('init');上面代码中,Worker 每秒钟轮询一次数据,然后跟缓存做比较。如果不一致,就说明服务端有了新的变化,因此就要通知主线程。
2019年04月01日
1 阅读
0 评论
0 点赞
2018-11-12
script标签加载
阻塞式脚本每一个script标签,下载和执行都会阻塞页面的渲染.多个script标签加载, 会依次下载执行,后者都必须等待前者下载并执行.非阻塞式脚本延迟脚本加载在HTML4中script标签扩展了也defer属性, 该属性以支持主流浏览器. 有defer属性的script标签,会在浏览器解析到script标签时开始下载, 不会立即执行.会在月面加载完成后执行.即window.onload事件处理之前被执行.asyncasync="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)动态加载script既使用dom操作在页面动态添加script标签. 建议添加在页面的head标签里(这样更为安全, ie在body为加载完时, 可能会抛出一个"操作终止"的错误信息),在script标签添加到页面时开始下载并且执行.不会阻塞页面.在script标签接收完成时会触发一个onload事件,IE着为onreadystatechange(用script.readyState判断不同阶段.主要使用loaded,complete判断)var loadScript = function(url,callback){ var script = document.createElement('script'); script.type = "text/javascript"; if(script.readyState){//IE script.onreadystatechange = function(){ if(script.readyState == 'loaded' || script.readyState == 'complete'){ script.onreadystatechange = nuul;//阻止重复调用 callback(); } } }else{ script.onload = function(){ callback(); } } script.src = url; document.getElementByTagName('head')[0].appendChild(script) }
2018年11月12日
2 阅读
0 评论
0 点赞
2018-09-11
节流函数和函数去抖
//节流函数(预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。) //该方法主要利用两次函数执行的时间差判断 function throttle(action, delay) { var last = 0; //上次执行的时间 return function() { var curr = +new Date(); ///获取当前时间 if (curr - last > delay) { //如果两次函数执行的时间间隔大于指定的值,即可执行 action.apply(this, arguments) //执行时把对应的参数传递下去 last = curr //保存上次执行的时间 }; }; } //去抖函数(当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间,如此往复,直到不再调用该动作,函数才会执行。) //该方法利用的是延迟调用,在指定时间内如果再次执行,那么上次的定时器将被清理,直到指定时间内不再调用,函数才会被执行! function debounce(action, idle) { var last = null; return function() { var ctx = this; var args = arguments; clearTimeout(last); last = setTimeout(function() { action.apply(ctx, args) }, idle); } }通常时间设为16.7sm,由于主流的屏幕刷新率都在60hz,因此渲染一帧的事件就必须控制在16.7ms内才能保证不掉帧。也就是说每一次渲染都要在 16.7ms
2018年09月11日
2 阅读
0 评论
0 点赞
1
2