JS—異步、回調、高階函數

併發與並行

  • 併發是指兩個或多個事件鏈隨時間發展交替執行,以至於從更高的層次來看,就像是同時運行(但在任意時刻只處理一個事件)
  • 併發的關鍵是你有處理多個任務的能力,不一定同時。
  • 並行的關鍵是你有同時處理多個任務的能力。
  • 併發和並行都可以是很多個線程,就看這些線程能不能同時被(多個)cpu執行,如果可以就說明是並行,而併發是多個線程被(一個)cpu 輪流切換着執行。
  • 區別:是否【同時】

併發與並行

  • 單線程事件循環是併發的一種形式
  • 併發的實現方式:多進程,多線程,事件循環
  • 我的理解是:併發是多個邏輯流交替執行,看起來像是同時運行,其實任意時刻只能處理一個;而並行是真正的同時執行。

同步與異步

  • 同步和異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)
  • 同步,就是在發出一個調用時,在沒有得到結果之前,該調用就不返回。但是一旦調用返回,就得到返回值了。
  • 異步則是相反,調用在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會立刻得到結果。而是在調用發出後,被調用者通過狀態、通知來通知調用者,或通過回調函數處理這個調用。

阻塞與非阻塞

  • 阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態
  • 阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之後纔會返回。
  • 非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。
  • 我的理解:異步阻塞是沒有必要的;ajax請求最好不要設置爲同步,chrome瀏覽器會警告

阻塞與非阻塞,同步與異步知乎鏈接
阻塞與非阻塞與是否同步異步無關

事件循環

  • 機制:while(true)每輪循環取出事件隊列中的隊頭事件執行,事件隊列(先進先出)。
  • setTimeout()是設定一個定時器,當定時器到時後,環境會把回調函數放到事件循環中。如果此時事件隊列中有多個事件,那麼該回調就會等待,所以setTimeout定時器的精度可能不高,只能確保回調函數不會在指定的時間間隔之前運行。
  • AJAX請求:JS程序發出ajax請求,從服務器端獲取數據,並設置了回調函數。發出請求的時候,JS引擎會通知宿主環境,讓其完成了網絡請求,拿到數據後執行該回調函數。然後,瀏覽器會設置偵聽來自網絡的響應,拿到數據後,將該回調函數插入到事件循環。
  • 競態條件:函數執行順序的不確定性(來自於插入事件隊列順序的不確定性)
  • 競態條件可能會導致結果的不確定性,所以需要通過協調交互順序來解決這種情況。
  • 併發協作:JS中我的理解是:將大任務分解爲多個小任務,分別利用異步機制插入到事件隊列中,例如可利用setTimeout(f,0)將小任務插入到事件隊列中,如果事件隊列目前有待執行的事件就可以先執行,以此來避免大任務阻塞事件隊列中其他任務的執行。

JavaScript單線程與異步

  • why單線程:作爲瀏覽器腳本語言,JavaScript的主要用途是與用戶互動,以及操作DOM。這決定了它只能是單線程,否則會帶來很複雜的問題。
  • why異步:我的理解:瀏覽器應用決定了會有很多網絡請求,會有很多不可控的速度因素,瀏覽器是直接和用戶交互,用戶交互體驗很重要,所以不能阻塞,但同步非阻塞處理起來會很麻煩,因爲同步需要編寫代碼去檢測任務是否執行成功。所以就用異步,異步是通信機制決定了調用在發出之後就可以直接返回。
  • 所有同步任務執行完畢,系統就會循環讀取事件隊列。
  • 阮一峯的鏈接:http://www.ruanyifeng.com/blo...
  • 深入理解事件循環
  • 深入事件循環

回調

  • 回調是JS中最基礎的異步模式
  • 回調地獄:1)難以編寫,大腦的思維方式不適應面向回調的異步代碼。2)爲了處理可能出現的各種情況,只能在回調的每個步驟中硬編碼,造成代碼的複雜與重複,難以重用和維護。
  • 信任問題:控制反轉,即把自己程序的一部分執行控制交給了某個第三方。

高階函數

  • JS作爲一門完整的面向對象的編程語言,借鑑了函數式語言的特性,比如閉包、高階函數等。
  • 高階函數: 函數可作爲參數被傳遞,函數可作爲返回值輸出。
  • 函數作爲參數被傳遞:

1)回調函數,即將變化部分的代碼封裝爲函數,將函數作爲參數傳遞。本來可以將變化的部分抽離出來,形成兩個函數,但實際上這兩個函數有依賴關係,所以只能參數調用,放到同一個函數中執行。
2)Array.prototype.sort 可以傳入函數作爲排序規則。

異步控制檯

  • JS調試最好使用斷點,因爲console.log()是由宿主環境添加到JS中,控制檯I/O處理可能會有延時。

《你不知道的javascript中卷》第二部分異步和性能 1.1 異步控制檯部分:

並沒有什麼規範或一組需求指定console.* 方法族如何工作——它們並不是JavaScript 正式
的一部分,而是由宿主環境(請參考本書的“類型和語法”部分)添加到JavaScript 中的。因此,不同的瀏覽器和JavaScript 環境可以按照自己的意願來實現,有時候這會引起混淆。

尤其要提出的是,在某些條件下,某些瀏覽器的console.log(..) 並不會把傳入的內容立即輸出。出現這種情況的主要原因是,在許多程序(不只是JavaScript)中,I/O 是非常低速的阻塞部分。所以,(從頁面/UI 的角度來說)瀏覽器在後臺異步處理控制檯I/O 能夠提高性能,這時用戶甚至可能根本意識不到其發生。

例如在mousemove監聽函數中console.log,是不會打印出內容的(mousemove觸發太頻繁,而console.log屬於I/O操作,瀏覽器爲了性能考慮,會將這種頻繁I/O放到後臺運行)。

解決方案: 如果斷點調試不方便的話,可以將需要打印的內容,掛載到window對象,mousemove完成後再打印出來看。

更多博客: https://github.com/Lmagic16/blog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章