每一個故事都有由來。前兩天在看 gulp
的時候,看到了它有個 promise
的玩意兒,而後的而後,這兩天就掉進了 javascript
的異步和回調的坑裏面去了。
其間搜索了 javascript promise
,看到了一堆好文章。大概給個 List 吧。javascript
看得昏天黑地,大概也理清楚了一點,作個小總結。html
上面這些文章寫得都挺好,但大部分都是上來直接說怎麼異步回調,js的異步有哪些方法。這適合高級選手。我剛開始連啥是異步,啥是回調都不太清楚,這些方法天然也比較難理解。因此仍是打好基礎,先弄清楚異步、回調這些基本概念比較好。java
先看個例子。gulp
javascriptfoo(); bar();
同步
的(synchronous),即按照書寫的順序執行。在上述例子中,bar 方法會在 foo 方法執行完以後,再執行。異步
(asynchronous)與同步相對,即在前一個方法未執行完時,就開始運行後一個方法。在上述例子中,先執行 foo 方法,foo 方法沒執行完,就開始執行 bar 方法。從異步的概念中能夠發現,程序異步運行,能夠提升程序運行的效率,沒必要等一個程序跑完,再跑下一個程序,特別當這兩個程序是無關的時候。兩個程序在必定時間內,能夠是同時運行的。寫服務器的時候應該會碰到不少這樣的例子。能夠想象,若是服務器的程序都是同步的,那併發什麼的就不存在了吧。segmentfault
這一點是我本身簡單的理解。promise
阻塞
就是說一個程序沒運行完,它後面的程序是沒法運行的。非阻塞
則相反,一個程序若是由於各類緣由(網絡、代碼量等)沒運行完的時候,其餘的程序也是能夠繼續運行的。這一點也是我本身的簡單理解。服務器
單線程
是指程序運行只有一個通道,不一樣的方法須要排隊執行。多線程
的功能,至關於開了幾個通道運行程序,使得程序能夠在不一樣的線程中運行,不會相互影響。從上述基本概念中能夠發現,異步若是發生在多線程語言中,會十分天然且符合邏輯。異步本質上應該就是多線程語言的產物。由於只有在多線程語言中才可以實現程序之間相互不干擾,不產生阻塞。網絡
有了上面的一些基本概念,那麼下面來講說正題,JS中的異步。
咱們都知道 JS 是一個單線程的語言,永遠只有一個通道在運行程序。那麼既然它是個單線程又如何會有異步呢?
JS 中所謂的異步,應該被稱爲僞異步(pseudo asynchronous)。這是由於 JS 語言中的異步,會產生阻塞,並會相互干擾。多線程
setTimeout
咱們來看一下 setTimeout 如何模擬 JS 中的異步。併發
javascriptvar foo = function(){ console.log('foo begins'); setTimeout(function(){ console.log('foo finishes'); },1000); }; var bar = function(){ console.log('bar executed'); } foo(); bar();
上述過程執行的時候,會打印出
foo begins
bar executed
foo finishes
因此,在上述代碼塊中,在前一方法(foo)執行時,後一方法(bar)也能夠執行。符合異步的基本概念,程序並不按順序執行。
說是模擬是由於,你能夠把 console.log('foo begins');
理解成會運行 1 秒的一個代碼行,運行完後,會跳出foo finishes
。而中間這 1 秒運行的時候,後面的 bar 方法也是能夠運行的。這樣就模擬了一個異步的效果。
咱們將上述代碼塊稍作修改
javascriptvar foo = function(){ console.log('foo begins'); setTimeout(function(){ console.log('foo finishes'); },1000); }; var bar = function(){ while(){ } } foo(); bar();
你會發現 1 秒以後 foo finishes
並無被打印出來。這是由於 bar 方法是個死循環,使得 js 引擎假死,致使了 foo 方法也沒有被運行完。若是是多線程的異步,假死的應該是運行 bar 方法的線程,而 foo 方法仍然會按預期打印出 foo finishes
。固然了,其實這個死循環也只是模擬 bar 方法塊程序運行的時間將很長。實際上,若是 bar 方法運行的時間超過了 1 秒,比方說是 5 秒,那麼 foo finishes
也將在 5 秒以後被打印出來。這個本質上取決於 JS 單線程程序塊按隊列執行的特性。
因此 JS 中的異步並不能像普通的異步同樣,實現非阻塞和不干擾。
雖然 JS 中的異步有其先天的缺陷,可是這種異步的思想,仍然能被 JS 程序開發人員所借鑑。畢竟,異步是能夠大大提升程序運行效率的。
也正是因爲 JS 自己是單線程程序的關係,因此 JS 中異步的實現,並不能像其餘語言同樣,簡單地多開個線程就能夠解決。
目前我看的集中方法主要有回調、事件類方法、promise等。
先說說回調是什麼吧。回調
(callback)這種名詞就跟函數
(function)同樣,乍一看是比較難懂的,至少我是這樣的。
根據sf上這個問答的解釋,能夠明確,把一個函數做爲參數傳入到另外一個函數中,那麼這個做爲參數的函數就叫作回調函數。如:
javascriptvar foo = function(callback){ // foo method callback(); }; foo(bar);
其中,bar 就是一個回調函數。固然了,按我我的的理解,應該說是 bar 是 foo 的回調函數。
時間問題,具體的實現方式和理解還沒好好看,往後再作細細梳理。上述理解若有偏頗,歡迎討論指正。