JavaScript中分解任务

我们通常将一个任务分解成一系列子任务。如果一个函数运行时间太长,那么查看它是否可以分解成一系列能够短时间完成的较小的函数。可将一行代码简单地看作一个原子任务,多行代码组合在一起构成一个独立任务。某些函数可基于函数调用进行拆分。例如:
      function saveDocument(id){
            openDocument(id)
            writeText(id);
            closeDocument(id);
            updateUI(id);
      }
      如果函数运行时间太长,它可以拆分成一系列更小的步骤,把独立方法放在定时器中调用。你可以将每个函数都放入一个数组,然后使用前一节中提到的数组处理模式:

      function saveDocument(id){
            var tasks = [openDocument, writeText, closeDocument, updateUI];
            setTimeout(function(){
                  var task = tasks.shift();
                  task(id);
                  if (tasks.length > 0){
                        setTimeout(arguments.callee, 25);
                  }
            }, 25);
      }
      这个版本将每个方法放入任务数组,然后在每个定时器中调用一个方法。从根本上说,现在它成为数组处理模式,只有一点不同:处理函数就包含在数组项中。正如前面一节所讨论的,此模式也可封装重用:
      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);
      }
      multistep()函数接收三个参数:用于执行的函数数组,为每个函数提供参数的参数数组,当处理结束时调用的回调函数。函数用法如下:
      function saveDocument(id){
            var tasks = [openDocument, writeText, closeDocument, updateUI];
            multistep(tasks, [id], function(){
                  alert("Save completed!");
            });
      }
      注意传给multistep()的第二个参数必须是数组,它创建时只包含一个id。正如数组处理那样,使用此函数的前提条件是:任务可以异步处理而不影响用户体验或导致依赖代码出错。
      (一)限时运行代码
      有时每次只执行一个任务效率不高。考虑这样一种情况:处理一个拥有1'000个项的数组,每处理一个项需要1毫秒。如果每个定时器中处理一个项,在两次处理之间间隔25毫秒,那么处理此数组的总时间是(25 + 1) × 1'000 = 26'000 秒,也就是26 秒。如果每批处理50个,每批之间间隔25毫秒会怎么样呢?整个处理过程变成(1'000 / 50) × 25 + 1'000 = 1'500毫秒,也就是1.5秒,而且用户也不会察觉界面阻塞,因为最长的脚本运行只持续了50毫秒。通常批量处理比每次处理一个更快。
      如果你记住JavaScript可连续运行的最大时间是100毫秒,那么你可以优化先前的模式。我的建议是将这个数字削减一半,不要让任何JavaScript代码持续运行超过50毫秒,只是为了确保代码永远不会影响用户体验。
      可通过原生的Date 对象跟踪代码的运行时间。这是大多数JavaScript分析工具所采用的工作方式:
      var start = +new Date(),
      stop;
      someLongProcess();
      stop = +new Date();
      if(stop-start < 50){
            alert("Just about right.");
      } else {
            alert("Taking too long.");
      }
      由于每个新创建的Data 对象以当前系统时间初始化,你可以周期性地创建新Data对象并比较它们的值,以获取代码运行时间。加号(+)将Data 对象转换为一个数字,在后续的数学运算中就不必再转换了。这一技术也可用于优化以前的定时器模板。
      processArray()方法通过一个时间检测机制,可在每个定时器中执行多次处理:
      function timedProcessArray(items, process, callback){
            var todo = items.concat();
            setTimeout(function(){
                  var start = +new 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循环,它在每个数组项处理之后检测时间。定时器函数运行时数组中存放了至少一个项,所以后测试循环比前测试更合理。在Firefox 3中,如果process()是一个空函数,处理一个1'000个项的数组需要38 – 34毫秒;原始的processArray()函数处理同一个数组需要超过25'000毫秒。这就是定时任务的作用,避免将任务分解成过于碎小的片断。
      (二)定时器与性能
      定时器使你的JavaScript代码整体性能表现出巨大差异,但过度使用它们会对性能产生负面影响。使用定时器序列,同一时间只有一个定时器存在,只有当这个定时器结束时才创建一个新的定时器。以这种方式使用定时器不会带来性能问题。
      当多个重复的定时器被同时创建会产生性能问题。因为只有一个UI线程,所有定时器竞争运行时间。Google Mobile的Neil Thomas 将此问题作为测量性能的方法进行研究,针对iPhone和Android上运行的移动Gmail程序。
      Thomas发现低频率的重复定时器——间隔在1 秒或1 秒以上——几乎不影响整个网页应用的响应。这种情况下定时器延迟远超过使UI 线程产生瓶颈的值,因此可安全地重复使用。当多个重复定时器使用更高的频率(间隔在100到200毫秒之间),Thomas发现移动Gmail程序明显变慢,反应较差。Thomas研究的言外之意是,要在你的网页应用中限制高频率重复定时器的数量。同时,Thomas建议创建一个单独的重复定时器,每次执行多个操作。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JavaScript 是一种广泛使用的编程语言,常用于 Web 开发。它可以在客户端浏览器运行,为网站添加交互性和动态效果。 JavaScript 是一种脚本语言,这意味着它不需要编译器来将代码转换成可执行文件。相反,它是一种解释性语言,直接在浏览器执行。 要在网页使用 JavaScript,可以将 JavaScript 代码包含在 HTML 文件的 `<script>` 标签。这样,当网页被加载时,浏览器会执行这些 JavaScript 代码,并且可以与用户交互、修改网页内容等。 JavaScript 是一种功能强大、灵活和易于学习的编程语言,它具有丰富的库和框架,可用于各种不同的开发场景。它支持面向对象编程、函数式编程和事件驱动编程等多种编程范式,可以满足各种不同类型的应用程序开发需求。 ### 回答2: JavaScript是一种脚本语言,主要用于在网页上添加交互和动态功能。它需要一个JavaScript解析器来执行代码。 在网页上,JavaScript代码通常包含在`<script>`标签,这个标签可以放在HTML文件的头部、尾部或者其他位置。当浏览器加载HTML文件时,会解析并执行其JavaScript代码。 JavaScript的运行过程涉及到以下几个步骤: 1. 解析:当浏览器加载HTML文件时,会解析其JavaScript代码。解析器会逐行扫描代码,将代码分解为可执行的单元。 2. 编译:解析器将JavaScript代码转换为机器能够执行的代码。这个过程会将代码转化为抽象语法树(AST),然后将AST编译成字节码或机器码。 3. 执行:一旦代码被编译为可执行的形式,解析器会按照代码的先后顺序执行一行一行的代码。代码的变量、函数和对象等都会被创建、初始化和处理。 JavaScript的执行是单线程的,即一次只能执行一个任务。这意味着在执行JavaScript代码时,其他任务会被阻塞,直到当前任务执行完毕。为了避免阻塞浏览器的UI渲染,JavaScript引入了事件循环机制,通过异步编程实现非阻塞的执行。 总结起来,JavaScript的运行是通过解析器解析和编译代码,然后按照代码的先后顺序执行,并通过事件循环机制实现异步执行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值