zoukankan      html  css  js  c++  java
  • JavaScript中异步编程

    一 关于事件的异步

    事件是JavaScript中最重要的一个特征,nodejs就是利用js这一异步而设计出来的。所以这里讲一下事件机制。

    在一个js文件中,如果要运行某一个函数,有2中手段,一个就是直接调用,比如foo(),第二就是利用事件来触发,这中函数也叫回调函数,比如传递给setTimeout函数和onready属性。

    1.setTimeout函数中的事件异步

    setTimeout本质上也是一种异步事件,当延迟时间到的时候触发该事件,但是有的有的时候(其实也是大部分时候)都不会按照给定的延迟时间执行,先看下面的代码

            var start = new Date();
            setTimeout(function() {
                console.log('settimeout1:',new Date()-start);
            }, 500);
            while (new Date() - start < 1000) {
                console.log('in while');
            }
            document.getElementById('test').addEventListener('click', function(){
                console.log('test:',new Date()-start);
            }, false)
            for(var i=0;i<10000;i++){
                console.log('in for');
            }
            setTimeout(function(){
                console.log('settimeout2: ',new Date()-start);
            },1000);
            /* 10214
            in while
            index.jsp (第 19 行)
            10000
            in for
            index.jsp (第 25 行)
            settimeout1: 2263
            index.jsp (第 16 行)
            settimeout2: 3239
            index.jsp (第 28 行)
            test: 10006
            index.jsp (第 22 行)
            test: 28175
            index.jsp (第 22 行)
            test: 28791
            index.jsp (第 22 行)
            test: 28966
            index.jsp (第 22 行) */

    如果按照正常的理解,延迟函数应该在500毫秒之后打断while循环,而事实上并没有,并且,我在while循环和for循环期间点击div时候并没有立即输出test,给出的解释就是:

    a)事件队列。调用setTimeout函数的时候,会把传入它的回调函数加入到事件队列中去(事件已经初始化并且在内存了),然后继续执行后面的代码,直到再也没有代码可以运行(没有正常的运行流了,不包括事件函数等异步的内容),就会从事件队列里面pop出一个合适的事件来运行。

    b)js是单线程的,事件处理器在线程空闲之前是不会运行的。

    2 普通事件的异步和setTimeout类似

    二 promise对象和deferred对象

    1. promise

    promise是一种解决ajax等异步编程回调函数嵌套太多导致代码晦涩难懂的解决方案,特别是在nodejs中,异步无处不在。不同的框架对promise的实现,一下是jquery中的promise的API。

    这里不讲promise的实现原理,关于原理在另外的篇幅中介绍。

    传统的ajax异步编程是这么写的(jquery1.5之前):

    $.get('url', function(){
        $.get('url1', function(){
            $.get('url2', function(){
    
            }, 'json');
        }, 'json');
    }, 'json');

     这么写代码给开发和维护带来了极大的困难,好在jquery1.5以后引入了promise,就可以这么写了:

     $.ajax( "example.php" )
    .done(function() { alert("success"); })
    .fail(function() { alert("error"); })
    .always(function() { alert("complete"); });

     现在看上去就明显简单多了。

    2.deferred对象

    var nanowrimoing = $.Deferred();
    var wordGoal = 5000;
    nanowrimoing.progress(function(wordCount) {
    var percentComplete = Math.floor(wordCount / wordGoal * 100);
    $('#indicator').text(percentComplete + '% complete');
    });
    nanowrimoing.done(function(){
    $('#indicator').text('Good job!');
    });

    三.worker对象和多线程

    四.异步脚本加载

    1.传统脚本在页面中的位置

    脚本分为两大类:阻塞式和非阻塞式。这里的阻塞是指加载阻塞而不是运行阻塞。

    <!DOCTYPE html>
    <html>
    <head>
    <script src="headScript"></script>
    <script defer src="deferredScript"></script>
    </head>
    <body>
        <script async defer src="chatWidget"></script>
        <script async defer src="asyncScript"></script>
    </body>
    </html>

    上面这部分代码是比较标准的关于脚本在一个页面中的位置,1.其中传统的未加任何修饰的headScript是阻塞式的脚本,由于浏览器从上到下解释执行JavaScript,所以这部分脚本文件在一开始就会被执行,并且在执行完之前是DOM是不会渲染的,但是head标签里面的css会加载。2.有defer属性的脚本会在DOM渲染的同时进行加载,但是会在DOM渲染完毕之后才开始执行,不幸的是,不是所有的浏览器都支持defer属性,所以才会有了jquery(function)这个东西。3.同时带有async属性和defer属性时候,defer会覆盖async,但是单独有async的时候,脚本会在DOM渲染的时候加载并且运行。

    2.可编程的脚本加载

    如果不是一开始就在页面种引入js文件,而是通过用户交互来实现动态的加载js脚本,可以通过编程方式加入。

    浏览器获取服务器脚本有2个方法,ajax获取并且通过eval函数执行,另外一个就是在DOM中插入<script>标签,一般用第二种方法,因为浏览器帮助我们生成HTTP请求以及eval会泄露作用域。

    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.src = '/js/feature.js';
    head.appendChild(script);
    script.onload = function() {
    // 现在可以调用脚本里定义的函数了
    }

     不过,一些老版本的浏览器不支持onloa事件,所以可以使用一些脚本加载库来实现这一功能,如require.js。

  • 相关阅读:
    Object.defineProperty方法 使用
    Linux常用命令--网终设置
    Linux常用命令--文件操作、权限设置
    Linux常用命令
    vue之双绑实现
    【Objective-C学习记录】第二十九天
    【Objective-C学习记录】第二十八天
    【Objective-C学习记录】第二十四天
    【Objective-C学习记录】第二十三天
    【Objective-C学习记录】第二十二天
  • 原文地址:https://www.cnblogs.com/bdbk/p/5170136.html
Copyright © 2011-2022 走看看