zoukankan      html  css  js  c++  java
  • JavaScript异步编程(一) 深入理解JavaScript事件

     JavaScript异步编程

    深入理解JavaScript事件

    ・事件的调度

     JavaScript事件处理器在线程空闲之前不会运行

     线程的阻塞

    var start = new Date();
    
     
    // setTimeout和setInterval的计时精度比期望值差
    
    setTimeout(function(){
    
             var end = new Date();
    
             console.log('Time elapsed', end - start, 'ms');
    
    }, 500);
    
     
    while(new Date - start < 1000) {};

      结果上看出setTimeout没有使用另一线程

      队列

      调用setTimeout时,会有一个延时事件排入队列;

      输入事件的工作方式完全一样,如单机事件发生时,会有一个单击事件排入队列。但是,单击事件处理器要等到当前所有正在运行的代码均结束后才会执行。

    ・异步函数类型

      两大类:I/O函数和计时函数

      异步的I/O函数

      Node.js的出现是为了建立一个在某高级语言之上的事件驱动型服务器框架。

      JavaScript语言可以完美地实现非阻塞式I/O。

      如:

      var ajaxRequest = new XMLRequest();

      ajaxRequest.open(‘GET’, url);

      ajaxRequest.send(null);

      // 只需要附加一个事件处理器,随即返回事件队列

      ajaxRequest.onreadystatechange = function() {

       // …

      }

      因此,开发者需要做的只是定义一个回调就可以了。

      WebKit的console.log是异步的吗?

      var a = {name: '1'};
    
      console.log(a);
    
      a.name = '2';
    
      console.log(a);

      执行后打开控制台结果:

      先打开控制台,然后再执行的结果:

     

      原因:

      Console是浏览器的控制台所提供的对象,只有在控制台打开时才起作用;

      console.log并没有立即拍摄对象快照,只是存储了一个对象的引用;

      异步的计时函数

      可能为了作动画或模拟;

      setTimeout与setInterval(不精确的计时工具)

      以上两个函数的缺陷:即使时延设置为0,在浏览器中的执行频率也大约为200次/秒;

      原因:HTML规范推行的延时/时隔最小值为4毫秒;

      需要更细粒度计时的方案:requestAnimationFrame函数

    ・异步函数的编写

      任何函数只要使用了异步的函数,从上到下都是异步的。

      异步函数的特性:非阻塞

      非阻塞强调了异步函数的高速度

      间或异步的函数

      有些函数某些时候是异步的,但其他时候却不然;

      例:jQuery的同名函数可用于延迟函数直到DOM已经结束加载;

          但DOM如果早已结束了加载,则不存在任何延迟,$的回调将会立即触发;

      // application.js

      $(function() {

           utils.log('Ready');

      });

      // utils.js

      window.utils = {

              log: function() {

                      if(window.console)

                            console.log.apply(console, arguments);

              }

      };

      <script src="application.js" type="text/javascript"> </script>

      <script src="utils.js" type="text/javascript"> </script>

      这段代码运行得很好,但前提是浏览器并未从缓存中加载页面(这会导致DOM 早在脚本运行之前就已加载就绪)。如果出现这种情况,传递给$的回调就会在设置utils.log 之前运行,从而导致一个错误。

      缓存型异步函数

      function runCalculation(formula, callback) {

        if (formula in calculationCache) {

            return callback(calculationCache[formula]);

        };

        if (formula in calculationCallbacks) {

            return setTimeout(function() {

                runCalculation(formula, callback);

            }, 0);

        };

        mathWorker.postMessage(formula);

        calculationCallbacks[formula] = callback;

     }

      公式已经计算完成,于是结果位于calculationCache 中。这种情况下,runCalculation 是同步的。

      公式已经发送给Worker 对象,但尚未收到结果。这种情况下,runCalculation 设定了一个延时以便再次调用自身;重复这一过程直到结果位于calculationCache 中为止。

      异步递归与回调存储

      避免异步递归,尽量采用回调存储。

      返值与回调

      永远不要定义一个潜在同步而返值却有可能用于回调的函数。

      避免使用计时器方法来等待某个会变化的东西。如果同一个函数既返值又运行回调,则请确保回调在返值之后才运行。

    ・异步错误的处理

      大多数JavaScript环境会提供一个有用的堆栈轨迹。

      回调内抛出的错误

    setTimeout(function A() {
        setTimeout(function B() {
            setTimeout(function C() {
                throw new Error('Something terrible has happened!');
            }, 0);
          }, 0);
    }, 0);

     A和B并未出现在堆栈轨迹中,因为这三个函数都是从事件队列直接运行的;

      同理,try/catch语句块不能捕获从异步回调中抛出的错误;

      要记住的是,只能在回调内部处理源于回调的异步错误。

      windows.onerror 处理器返回true,能阻止浏览器的默认错误处理行为。

      避免两层以上的函数嵌套。关键是找到一种在激活异步调用之函数的外部存储异步结果的方式,这样回调本身就没有必要再嵌套了。

  • 相关阅读:
    Ipython qtconsole中文乱码的解决
    PowerCMD代替Windows命令提示符并设置适合变量
    Python学习前的计划
    Ubuntu安装记录
    Linux下C语言开发的一点记录
    os.path.join与中文目录
    Vim学习笔记
    SublimeText3 中Python补全插件在Linux下的问题解决
    Windows下MinGW编译vim7.4
    C语言I博客作业06
  • 原文地址:https://www.cnblogs.com/dreamerjdw/p/6227264.html
Copyright © 2011-2022 走看看