javascript的中的異步是很重要的概念,特別是ajax的提出,給整個web帶來了很大的影響,今天就介紹下javascript的異步編程。javascript
何爲同步?何爲異步呢?java
同步:說白了就是程序一步一步從下向下執行,沒有什麼別的代碼的跳動,就是按序執行,和在景區裏女生上廁所是排隊是同樣的(每次女廁都是有好多人在排隊)。能夠當作是一個單線程問題。node
異步:異步就是程序能夠跳着執行,開始執行一段程序以後不用等返回結果就執行其餘的代碼,等結果返回以後在對結果進行處理,也就是能夠在有限的時間內辦好幾件事情,提升效率,異步通常狀況是多個線程問題。舉個例子,仍是上廁所的例子,A說須要5分鐘搞定,B就能夠5分鐘以後過來,B能夠在這5分鐘乾點別的事情。jquery
因此說異步能夠提升程序的執行效率,因此異步編程具備必定的好處,可是編寫異步程序卻不是那麼容易的。web
上面是個人理解,下面是摘自別人的文章:ajax
"同步模式"就是上一段的模式,後一個任務等待前一個任務結束,而後再執行,程序的執行順序與任務的排列順序是一致的、同步的;"異步模式"則徹底不一樣,每個任務有一個或多個回調函數(callback),前一個任務結束後,不是執行後一個任務,而是執行回調函數,後一個任務則是不等前一個任務結束就執行,因此程序的執行順序與任務的排列順序是不一致的、異步的。編程
咱們都知道了,瀏覽器是單線程解析javascript的,也就是說,咱們的瀏覽器原理是是不能搞成異步的,由於就一個線程嘛,如何搞成異步的呢?這就須要模擬異步來實現了,主要須要setTimeout函數。promise
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對象是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中一個重要的部分,咱們仍是要好好的掌握的。