zoukankan      html  css  js  c++  java
  • 【javascript 进阶】异步调用

    前言

    javascript的中的异步是很重要的概念,特别是ajax的提出,给整个web带来了很大的影响,今天就介绍下javascript的异步编程。

    同步与异步

    何为同步?何为异步呢?

    同步:说白了就是程序一步一步从下向下执行,没有什么别的代码的跳动,就是按序执行,和在景区里女生上厕所是排队是一样的(每次女厕都是有好多人在排队)。可以看成是一个单线程问题。

    异步:异步就是程序可以跳着执行,开始执行一段程序之后不用等返回结果就执行其他的代码,等结果返回之后在对结果进行处理,也就是可以在有限的时间内办好几件事情,提高效率,异步一般情况是多个线程问题。举个例子,还是上厕所的例子,A说需要5分钟搞定,B就可以5分钟之后过来,B可以在这5分钟干点别的事情。

    所以说异步可以提高程序的执行效率,所以异步编程具有一定的好处,但是编写异步程序却不是那么容易的。

    上面是我的理解,下面是摘自别人的文章:

    "同步模式"就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

    浏览器机制

    我们都知道了,浏览器是单线程解析javascript的,也就是说,我们的浏览器原理是是不能搞成异步的,因为就一个线程嘛,如何搞成异步的呢?这就需要模拟异步来实现了,主要需要setTimeout函数。

    setTimeout和setInterval

    setTImeout是指延迟指定的毫秒数后调用函数或计算表达式。看个例子

    setTimeout(function(){alert("延迟一秒弹出")},1000);

    setInterval方法可按照指定的周期(以毫秒计)来调用函数或计算表达式,就是一定时间之后重新执行一次,例子

    setInterval(function(){alert("一秒弹一次")},1000);

    对应的取消方法是clearTimeout和clearInterval,用法很简单。

    用上面的两个方法模拟所谓的“异步调用”事实上是通过将代码段插入到代码的执行队列中实现的,因为javascript是单线程执行的,程序按序执行下来时,等浏览器有时间了就等一定的时间将setTimeout中的代码添加到执行队列中,通过例子说明吧

    1 setTimeout(function(){console.log("延迟一秒打印我")},1000);
    2 console.log("打印出我");

    当执行1行代码时,浏览器将里面的function(){console.log("延迟一秒打印我")}代码添加到了执行队列,并且延迟1秒之后执行,之后就到了第2行代码,打印了结果"打印出我",过了一秒之后打印出"延迟一秒打印我"。可以看出第1行代码执行了之后,并没有执行完,而是执行了第2行代码,1秒之后再执行setTimeout中的函数,就这样模拟异步函数调用,其实说白了并不是真正的异步函数调用,事实上所谓的异步只是一个假象,同样是运行在一个线程上。

    假如现在在执行异步调用的时候,浏览器一直没有时间,那么就不用进行调用了,例子

    1 setTimeout(function(){console.log("延迟一秒打印我")},1000);
    2 while(true){}//模拟一直很忙
    3 console.log("打印出我");

    上段代码啥都不会打印出来,因为代码function(){console.log("延迟一秒打印我")}插入之后,它要等1秒之后才能执行,但是浏览器一直都在忙,所以即使到了1秒钟之后,代码也不会被执行。

    异步编程

    一般来说,异步编程有四种方式,分别为回调函数方式,事件监听方式,发布-订阅方式和Promise方式,下面分别介绍这些方式。

    回调函数

    所谓回调函数,就是将函数作为参数传到需要回调的函数内部再执行,·例子,例如f1是很耗时的程序,f1执行完之后执行f2,如果是普通的这样

    f1();
    f2();

    f2需要很长的时间才能执行,为了提高效率,我们使用回调函数的方式还模拟异步调用,这样f1(f2),怎样实现呢?其实就是利用setTimeout来实现

    1 function f1(func){
    2   setTimeout(function(){
    3                         //f1代码
    4                          func();                
    5                 },0);  
    6 }
    7 function f2(){}
    8 f1(f2);

    自己弄个例子吧

    function f1(func){
      setTimeout(function(){
                for(var i=0;i<10000;i++){
                      console.log(i);
                    }
                func();
               },0);      
    }
    function f2(){
       console.log("f2");
    }
    f1(f2);
    console.log("程序末尾");

    结果:程序末尾 1 2 ...10000 f2 

    程序f1执行结束之后执行f2,f1执行的时候不影响后面程序的执行,所以先显示“程序末尾”,然后是1.2.3.。。。。,最后是回调函数f2的结果。

    ajax和nodejs主要就是通过回调函数这样方式实现的异步调用,简单介绍一下

    ajax

     1 var xmlhttp = new XMLHttpRequest();
     2 xmlhttp.open("POST","url", true);
     3 xmlhttp.onreadystatechange = function(){
     4     if(xmlhttp.readyState == 4){
     5         if(xmlhttp.status == 200){
     6             console.log(xmlhttp.responseXML);
     7        }
     8     }
     9 }
    10 xmlhttp.send();

    nodejs

    1 fs.readdir(".", function (err, filenames) {
    2     var i;
    3     for (i = 0; i < filenames.length; i++) {
    4         console.log(filenames[i]);
    5     }
    6 });

    事件监听

    javascript的事件驱动模式是重要的概念,代码的执行和顺序没有关系,而是与事件的何时发生有关系。javascript原生的绑定事件就是这个概念,例如

    dom.onclick = function(){
      console.log("click");  
    }

    jquery就是类似这样的,都是事件绑定,这是演示,

    function f2(){}
    f1.on("complete",f2);
    f1.trigger("complete");

    订阅-发布

    简单说:两种角色,订阅者和发布者,订阅者可以订阅事件,发布者发布事件消息,发布者发布消息只能通知到订阅改消息的订阅者,未订阅的不同接收到消息。专业解释:存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。

    自己弄个订阅-发布模式,大家看看,勿喷啊

     1 (function(window,undefined){
     2     var topics = {};
     3     var queue = {
     4         publish : function(topic,args){
     5             if(!topics[topic]){
     6                 return;
     7             }
     8             var funcs = topics[topic],
     9                 len = funcs.length;
    10             for(var i=0;i<len;i++){
    11                 funcs[i](args);
    12             }
    13             return this;
    14         },
    15         subscribe :function(topic,func){
    16             if(!topics[topic]){
    17                 topics[topic] = [];
    18             }
    19             topics[topic].push(func);
    20         }
    21     }
    22     window.AllenQueue = queue;
    23 })(window);

    用法:

    AllenQueue.subscribe("done",function(){console.log("done")});
    AllenQueue.publish("done")

    其实我觉得时间监听就是订阅发布模式,这两个应该是一样的,事件机制就是订阅发布的实例。

    Promise

    promise对象是CommonJS工作组提供的一种规范,用于异步编程的统一接口。promise对象通常实现一种then的方法,用来在注册状态发生改变时作为对应的回调函数。promise模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled)、已完成(resolved)和拒绝(rejected)。以CommonJS Promise/A 标准为例,promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回另一个promise对象,以便于形成promise管道,这种返回promise对象的方式能够支持开发人员把异步操作串联起来,如then(resolvedHandler, rejectedHandler)。resolvedHandler 回调函数在promise对象进入完成状态时会触发,并传递结果;rejectedHandler函数会在拒绝状态下调用。

    Jquery在1.5的版本中引入了一个新的概念叫Deferred,就是CommonJS promise A标准的一种衍生。可以在jQuery中创建$.Deferref的对象。同时也对发送ajax请求以及数据类型有了新的修改,参考JQuery API。

    例子如下

    1 function f1(){
    2     var dfd = $.Deferred();
    3     setTimeout(function () {
    4       // f1的任务代码
    5       dfd.resolve();
    6     }, 500);
    7     return dfd.promise;
    8 }
    9 f1().then(f2)

    这个暂时就这样,以后我们会单独详细说说这个promise的。

    小结

    异步调用是javascript中一个重要的部分,我们还是要好好的掌握的。

  • 相关阅读:
    【JavaScript】实现队列Queue
    【Leetcode刷题篇】1.两数之和(JS)
    【48个原生JS网页小demo】1.信息切换
    【JavaScript】原生实现call bind apply
    【JavaScript】Interview(精简版)
    【JavaScript】4种常见的内存泄露
    【JavaScript】原型和原型链
    论自作音乐播放器涉及知识点总结
    Android横竖屏切换继续播放视频
    Android上传头像代码,相机,相册,裁剪
  • 原文地址:https://www.cnblogs.com/allenxing/p/3642602.html
Copyright © 2011-2022 走看看