【javascript 進階】異步調用

前言

javascript的中的異步是很重要的概念,特別是ajax的提出,給整個web帶來了很大的影響,今天就介紹下javascript的異步編程。javascript

同步與異步

何爲同步?何爲異步呢?java

同步:說白了就是程序一步一步從下向下執行,沒有什麼別的代碼的跳動,就是按序執行,和在景區裏女生上廁所是排隊是同樣的(每次女廁都是有好多人在排隊)。能夠當作是一個單線程問題。node

異步:異步就是程序能夠跳着執行,開始執行一段程序以後不用等返回結果就執行其餘的代碼,等結果返回以後在對結果進行處理,也就是能夠在有限的時間內辦好幾件事情,提升效率,異步通常狀況是多個線程問題。舉個例子,仍是上廁所的例子,A說須要5分鐘搞定,B就能夠5分鐘以後過來,B能夠在這5分鐘乾點別的事情。jquery

因此說異步能夠提升程序的執行效率,因此異步編程具備必定的好處,可是編寫異步程序卻不是那麼容易的。web

上面是個人理解,下面是摘自別人的文章:ajax

"同步模式"就是上一段的模式,後一個任務等待前一個任務結束,而後再執行,程序的執行順序與任務的排列順序是一致的、同步的;"異步模式"則徹底不一樣,每個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,因此程序的執行順序與任務的排列順序是不一致的、異步的。編程

瀏覽器機制

咱們都知道了,瀏覽器是單線程解析javascript的,也就是說,咱們的瀏覽器原理是是不能搞成異步的,由於就一個線程嘛,如何搞成異步的呢?這就須要模擬異步來實現了,主要須要setTimeout函數。promise

setTimeout和setInterval

setTImeout是指延遲指定的毫秒數後調用函數或計算表達式。看個例子瀏覽器

setTimeout(function(){alert("延遲一秒彈出")},1000);

setInterval方法可按照指定的週期(以毫秒計)來調用函數或計算表達式,就是必定時間以後從新執行一次,例子dom

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中一個重要的部分,咱們仍是要好好的掌握的。

相關文章
相關標籤/搜索