最近開發了一個適用於iOS上的混合開發庫,支持JavaScript
的開發,開發完之後對於JavaScript
中的一些特性有了更加深刻的瞭解。也就有了這篇文章,後續還會陸續寫一些其餘的關於JavaScript
的文章。javascript
異步編程
通常跟多線程
有關,而咱們都知道JavaScript
是單線程執行的,那何來異步
之說?java
事實上,但凡在
JS
中執行的代碼都是單線程執行的。c++
然而,咱們日常開發JavaScript
的時候常常會提到異步編程
的概念,並且在實際的開發過程當中也常常會用到異步編程
。那先說下咱們是怎麼用的,從最簡單的setTimeout
提及,而後一步一步的說到ES8中的async
和await
。編程
setTimeout(function(){
console.log('timeout');
},1000);
複製代碼
執行上面的代碼1秒後輸出timeout
。下面換一種方式,使用setInterval
來實現。瀏覽器
var interval = setInterval(function () {
console.log('timeout');
clearInterval(interval);
}, 1000);
複製代碼
上面兩種方式實現的效果是同樣的,都是在等待1秒後執行function
中的代碼。多線程
看到上面的代碼,但凡寫過其餘語言的好比:c++、java、OC等的,都知道這其實就是一個定時器,而setTimeout
稍微特殊點,只會執行一次,而setInterval
可以執行屢次,直到顯示取消爲止。異步
舉上面的例子主要是說明,在JavaScript中,setTimeout
和setInterval
能夠實現相似異步的效果。async
不一樣的語言對於定時器的實現方式有可能不同,甚至同一種語言,提供多種不一樣的定時器API,就拿
Objectiv-c
來講,起碼有三種方式實現定時器的效果,可是無論什麼語言,用什麼方式來實現,工做原理差很少,異步編程
就是當
定時器
獲取到某個信號
的時候,在建立該定時器的線程中插入任務。這樣的過程能夠理解爲線程調度。由於定時信號
不必定在你回調的線程上觸發的,該信號
有可能直接由硬件中斷
產生,也有多是軟件模擬
產生,可是在使用的時候都會在建立的線程得到回調。ui
所以,定時器本質上仍是單線程的,跟異步編程
不要緊。我舉個例子你就明白了
var t1 = new Date();
setTimeout(function(){
var t2 = new Date();
console.log('diff:'+(t2-t1));
},1000);
while (new Date() - t1 < 2000) {
}
複製代碼
上面的代碼你以爲是輸出1000
呢?仍是2000
?
實際的代碼輸出是diff:2000
,具體是2000多少要看實際狀況。舉這樣的例子說明什麼呢,正是說明setTimeout
仍是串行執行的,你能夠理解爲見縫插針
方式。所以setTimeout
壓根就算不上異步
。
一個殘酷的現實是,javascript
中不存在真的異步
,一切異步
都是假象。
全部的JS代碼都是在同一個線程上執行的,所以不存在多線程的概念,也就不存在真正的異步編程。
其實某些瀏覽器支持
worker
API,算是真的多線程。可是本篇不作介紹。
既然本篇的主題是異步編程
,那麼就算是假象,也得繼續了。
我記得JS的異步編程的概念被提出來是從XMLHttpRequest
(Ajax)開始的,而這裏的異步指的只是實際的http請求
是在非JS線程執行的,而請求完畢
後的回調仍是在JS線程執行的。這樣看起來是異步的,可是咱們要注意到,http異步請求
不是在JS線程上執行的,而是由瀏覽器負責的,跟JS不要緊。可是,正是由於有了這樣的模型,才使得一些本來沒法實現的功能變得可能。