Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

异步化以提高用户体验

  同步操作最大的弊病就是会让整个页面卡死,在Firefox上甚至会卡死进程,所以高耗时的同步操作毫无用户体验可谈论,于是很多情况下我们就需要让原本同步的代码异步化。其实这个思想在之前解决Chrome创建元素的性能问题时我们就已经使用过了。
  昨天的文章中,我们直接使用了Worker来解决Firefox上的进程卡死问题,但Worker的局限性很大。首先是兼容性问题,虽然Chrome和Firefox对它支持的很好,但是IE直到10才支持,所以要兼容IE9-就没法使用它了。然后,Worker与主线程之间的通信只能传递可复制的对象,这意味着在Worker中无法处理DOM。总之依然存在很多Worker无法解决的问题,我们需要其它思路。
  愚公是怎么移山的呢?他不是一次就把山给移走,人还得吃饭、睡觉、性生活,要不然哪来“子子孙孙无穷匮也”?生活与移山是并行的,或者说愚公是在异步移山。但是愚公既不会穿越平行宇宙,也不会多重影分身,怎么制造出的异步?这只是我们把时间分割的程度不同而已。所有事情确实都是在不同的时间点上单独完成的,但如果以较大的时间段为单位这些事情就都是连续的了。在Windows编程中也有类似的情况。比如VB本身是单线程的,它在处理复杂的同步运算时可以使用一个叫做DoEvents的方法来让窗体不至于卡死。这东西就是我们需要的,它写成C大概是这样
void DoEvents(){
  MSG msg;
  while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
}
  可以看到这个方法就是在把尚未处理的消息都处理掉,在耗时的大循环代码中插入DoEvents就可以得到类似异步的效果了。我们并不是让程序一次就把所有工作做完,而是劳逸结合地做一部分后处理其它的消息。那么回到JavaScript上呢?我们没有能左右消息队列的权限。但是我们可以把当前消息中剩余没做完的事情包装成一个新的消息放入消息队列的末尾后终止当前消息,这样就可以让引擎先处理现有的其它消息后再处理我们的消息。实际上就是用JavaScript模拟了DoEvents,当然这么做会对性能本身有一定的影响。这个概念就像一个进度条,如果不实现进度条,用户就不知道程序是否在工作,但是实现了进度条本身就会影响性能。它的取舍是个需要斟酌的地方,什么时候该对代码异步化应该视具体的需求决定。
  最后是对一个排序算法使用异步化的例子: 0<br/>
<input type="button" id="sync" value="同步排序" />
<input type="button" id="async" value="异步排序" />
<script>
//排序算法
var sort_sync=function(a,f){
  a=a.slice(0);
  var s=[0,a.length-1],p=0,l,r,i,j,v;
  //function cycle(){ /*包装消息*/
    //var c=0; /*统计计算量*/
    while(s.length>p){
      l=i=s[p++],r=j=s[p++],v=a[i];
      while(i<j){
        while(a[j]>=v&&i<j)j--;
        a[i]=a[j];
        while(a[i]<=v&&i<j)i++;
        a[j]=a[i];
      };
      a[i]=v;
      if(i-1>l)s.push(l,i-1);
      if(i+1<r)s.push(i+1,r);
      /*当计算量达到一定规模之后就放入消息队列的末尾,并终止当前消息*/
      //if((c+=(r-l))>1E5)return setTimeout(cycle);
    };
    f(a);
  //};setTimeout(cycle);
},sort_async=eval( //去掉sort_sync函数代码里面的“//”并生成新函数
  "["+sort_sync.toString().replace(/\/\//g,"")+"]"
)[0];

onload=function(){
  //狂奔的计时器
  var text=document.body.firstChild;
  setInterval(function(){text.data++;},1);
  //生成测试数据
  var data=[];
  for(var i=0;i<2E6;i++)data.push(Math.random());
  //同步排序
  sync.onclick=function(e){
    var t=new Date;
    sort_sync(data,function(s){
      console.log(new Date-t+" <- 同步排序耗时");
    });
  };
  //异步排序
  async.onclick=function(e){
    var t=new Date,value=async.value;
    async.disabled=1,async.value="排序中···";
    sort_async(data,function(s){
      console.log(new Date-t+" <- 异步排序耗时");
      async.value=value;
      async.disabled=0;
    });
  };
};
</script>
网名:
34.203.213.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^