美文网首页
JavaScript性能提升之——提升响应速度

JavaScript性能提升之——提升响应速度

作者: SLEBEE | 来源:发表于2017-05-21 15:11 被阅读0次

    首先呢,这里说的响应速度,是指页面UI的响应速度,对一个用户界面来说,评判快的标准是什么?

    用户觉得快才是快

    优化UI线程

    说到底产品最终都是给用户使用的,不论你对自己的产品做了什么优化,在用户手里好用就是好用,快就是快,不是靠你开发者说这说那用了什么技术啊来判定的。那么在网页中,怎么才会显得快呢?

    提高用户界面的响应速度一般有两种方式:

    • 提升代码质量来提升响应速度;
    • 让用户觉得你快。

    说到提升响应速度,我们得先来说一下浏览器的UI线程。

    浏览器UI线程

    这个东西呢就是用来执行JavaScript和更新用户界面的进程啦。

    UI线程是基于一个简单的队列系统的,所有的任务(UI更新、执行JavaScript)都会被放到任务队列中,任务会被保存到队列中直到进程空闲,一旦空闲,队列中的下一个任务就会被重新提取出来运行。也就是说对浏览器来说,页面上出现的所有事情,执行js、重绘页面这些都要一件件来做。

    引用一下 《You Don't Know JavaScript:Types & Grammar,Async &Performance》书中的一段伪代码来解释下这个概念:

    //eventLoop是一个用作队列的数组
    var eventLoop = [];
    var event;
    
    //'永远'执行
    while(true){
      if(eventLoop.length>0){
        event = eventLoop.shift();
        try{
          event();
        }
        catch(err){
          reportError(err);
        }
      }
    }
    

    结合这段概念代码,实际上我们的页面产生的所有操作,读取、解析资源、渲染页面、重绘,执行js等等这些任务全部都会在队列里排队执行。
    当UI线程处于执行任务期间,如果用户在这个时候与之交互,会出现UI没有即时更新,更有可能出现UI的更新任务不会被创建,在我们平时看来就是点击了没反应,连按钮都没一点反馈变化,这种时候就是UI线程处于繁忙状态。

    出现这种情况的时候很可能是因为你的js运行时间过长了,现在的浏览器有些会有限制运行时间,超过时间会弹出提示框。这种情况我觉得还是遇到的次数挺多的= =;

    相当多的历史研究中有提到过,单个js的操作花费时间不应该超过100ms。

    我们自己使用网页的时候也会有感觉,我点了这个按钮过了一会才有反应,完全就给了人一种这网站很慢的感觉。

    使用定时器让出UI线程

    虽然说单个js任务应该在100毫秒内完成,但是有时候有些任务确实要花费较长时间,这个时候可以使用定时器来让出UI线程使用权,我们在看别人代码的时候应该也有见过设置一个setTimeout任务但是延迟又设置的很低的用法,这就是使用定时器来让出UI线程。

    首先要明确的一点是,定时器并不会一执行把你要延迟的任务加入到事件循环队列中,它只是设置定时器到时后,再把你要延迟的这个任务加入到队列中,这也是定时器精度可能不高的原因,因为如果你到时间的时候刚好前面还有很多任务没有被执行完,那你这个只能等啦。

    用定时器取代循环

    说那么多,什么情况下可以用定时器来做代码块拆分运行优化呢,很常见的js运行时间过长的例子是循环,有些循环处理函数过于复杂或者循环源的大小过大,我们就可以使用,但是这也是有前提的,使用定时器取代循环要满足两个条件:处理过程无需同步,数据无需按顺序处理。
    满足这两个条件之后,我们可以写一个简单的函数来处理:

    function processArray(items,process,callback){
      var todos = item.concat();
      setTimeout(function(){
        process(tudos.shift());
        if(tudos.length>0){
          setTimeout(arguments.callee,25);
        }else{
          callback(items);
        }
      })
    }
    

    只要调用这个函数并传入数组,处理方法与完成的循环完成的回调函数,这样做会使原本的循环时间变成,但是每次循环后都会让出UI线程(上面定时器让出UI线程有说明),不至于说让整个长时间的循环一直占着UI线程而锁定浏览器,虽然实际上的处理时间变长了,但是对用户来说却会觉得更快了。

    这种定时器的用法还可以用于分割任务,一个运行时间过长的函数可以试着能不能拆分成多个函数,然后用类似上面的方式来加快UI响应速度。

    要注意的是,同时创建多个重复的定时器会产生所有定时器一起抢占UI线程而产生性能问题,最好使用一个定时器每次执行多次操作而不要同时创建多个

    使用Web Worker

    这个功能属于提供js能以类似多线程的方式来运行的功能,不过实际上并不是。

    首先要知道的是,HTML5的Web Worker这个特性属于宿主功能,即浏览器提供的功能,本身和JavaScript语言没关系,JS本身并没有任何支持多线程执行的功能。

    浏览器环境可以提供多个JavaScript引擎实例并各自运行独立的线程上。利用web worker,我们就可以将程序划分多块来并发运行。

    Web Worker通常被用于以下几个方面:

    • 处理密集型数学计算
    • 大数据集排序
    • 数据处理(压缩、音频分析、图像处理等)
    • 高流量网络通信
      from《You Don't Know JavaScript:Types & Grammar,Async &Performance》

    实例化一个Worker很简单: var worker1 = new Worker('http://aa.com/b.js')// 这个url要指向js文件位置;

    当这个文件被加载到一个Worker之后,浏览器就会启动一个独立的线程来运行这个Worker。

    web worker中使用大多数的标准javascript特性,包括

    • Navigator
    • XMLHttpRequest
    • Array, Date, Math, and String
    • WindowTimers.setTimeout and WindowTimers.setInterval

    完整的Web Worker用法可以参考https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Functions_and_classes_available_to_workers

    注意,Worker之间以及他们和主程序之间不会共享任何作用域或者资源,他们之间的联系依靠的是一个基本的事件消息机制来互相联系

    Web Worker之间的数据传递

    Worker与网页通过事件接口来通信

    • 网页代码使用postMessage()给Worker传递数据
    • Worker可以通过注册 message事件来接收网页传递过来的数据 worker.onmessage = function(event){},传递进来的数据可以通过event.data访问到。
      这是唯一的网页与Worker通信途径

    Web Worker的使用场景与浏览器的支持比较有限,就现在来说,常用的场景还是在处理比较大的数据,或者处理与UI无关的长时间运行脚本,比如转换大量的字符串啦,大数据集的搜索排序之类啦。

    页面元素的响应处理

    这个的话其实主要是从用户体验的角度来“欺骗性的”提高用户对网站速度的印象,怎么说呢

    当用户与程序交互的时候,程序要立即给出响应

    核心就是上面这句话,立即给出响应不表示你的程序要立即处理完任务,而是要立即做出一个反馈,这个反馈一般会是改变触发交互元素的外观,最常见的就是给可交互按钮添加各种状态,未被触发、触发中、触发后最好都要有个外观变化,这对用户来说是最直观的,无论触发交互的时候任务是否完成,都要立即给予对应的状态来给用户知道我的操作成功了,正在处理,处理好了,不给予反馈的交互过程很容易会让用户认为出了什么问题。

    相关文章

      网友评论

          本文标题:JavaScript性能提升之——提升响应速度

          本文链接:https://www.haomeiwen.com/subject/ruryxxtx.html