javascript中同步和非同步

扶欄笑看花滿園發表於2020-09-23
  • js是一門單執行緒的語言,不像Java,類繼承Thread再來個thread.start就可以開闢一個執行緒。js就像一條單一流水線,同一個時間只能做一個任務。

  • 同步和非同步的差別在於這條流水線上各個流程的執行順序不同

  • 最基礎的非同步是setTimeout和setInterval函式,很常見,但很少有人知道這就是非同步。

  • <script type="text/javascript">
    	setTimeout(function(){
    		console.log("1")
    	},0);
    	console.log("2");
    </script>
    

    輸出順序是

    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-4CEjkG46-1600846066722)(C:\Users\Beryl Zhang\AppData\Roaming\Typora\typora-user-images\image-20200923134823916.png)]

    任務佇列,依次存放setTimeout中的function,在執行程式的時候,瀏覽器會預設setTimeout以及ajax請求這一類的方法都是耗時程式(儘管可能不耗時),將其加入一個佇列中,該佇列是一個儲存耗時程式的佇列,在所有不耗時程式執行過後,再來依次執行該佇列中的程式。儘管setTimeout的time延遲時間為0,其中的function也會被放入一個佇列中,等待下一個機會執行,當前不需要加入佇列中的程式必須在佇列的程式完成之前完成。

  • js是單執行緒,意味著所有的任務需要排隊,等一個任務結束,才會執行後一個任務。如果前一個任務耗時很長,後一個任務就不得不一直等著。於是有了任務佇列

    如果排隊是因為計算量大,CPU忙不過來,倒也算了,但是很多時候CPU是閒著的,因為IO裝置(輸入輸出裝置)很慢(比如Ajax操作從網路讀取資料),不得不等著結果出來,再往下執行。於是JavaScript語言的設計者意識到,這時主執行緒完全可以不管IO裝置,**掛起處於等待中的任務,先執行排在後面的任務。**等到IO裝置返回了結果,再回過頭,把掛起的任務繼續執行下去。

  • 所有任務可以分為兩種

    • 同步任務(synchronous),指的是在主執行緒上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務

      • 如果在函式返回結果的時候,呼叫者能夠拿到預期的結果(就是函式計算的結果),那麼這個函式就是同步的。即使比較慢也會等他執行完。

        console.log('hello');

    • 非同步任務(asynchronous),指的是不進入主執行緒,而進入任務佇列(task queue)的任務,只有等主執行緒任務執行完畢,任務佇列開始通知主執行緒,請求執行任務,該任務才會進入主執行緒執行

      • 在函式返回的時候,呼叫者還不能立即得到預期結果,而是將通過一定手段得到(例如回撥函式),例如ajax操作。呼叫者不必主動等待,當被呼叫者得到結果之後會通過回撥函式主動通知呼叫者。
  • 非同步執行機制

    1. 所有的同步任務都在主執行緒上執行,形成一個執行棧(execution context stack)
    2. 主執行緒之外,還存在一個任務佇列task queue。只要非同步任務有了執行結果,就在任務佇列之中放置一個事件。
    3. 一旦執行棧中的所有同步任務執行完畢,系統就會讀取任務佇列,看看裡面有哪些事件,對應的非同步任務結束等待狀態進入執行棧開始執行。
    4. 主執行緒不斷重複上面的第三步。
  • IO裝置完成一項任務,就在任務佇列中新增一個事件,表示相關的非同步任務可以進入執行棧了,主執行緒讀取任務佇列,就是讀取裡面有哪些事件。

  • 任務佇列中的事件,除了IO裝置的事件以外,還包括一些使用者產生的事件(比如滑鼠點選、頁面滾動等),比如 $(selectot).click(function),這些都是相對耗時的操作。只要指定過這些事件的回撥函式,這些事件發生時就會進入任務佇列,等待主執行緒讀取。

  • 回撥函式,就是那些會被主執行緒掛起來的程式碼,$(selectot).click(function)中的function就是一個回撥函式。非同步任務必須指定回撥函式(callback),當主執行緒開始執行非同步任務,就是執行對應的回撥函式。例如ajax的success,complete,error也都指定了各自的回撥函式,這些函式就會加入任務佇列中等待執行。

  • js是單執行緒是因為瀏覽器在執行時只開一個js直譯器,有兩個執行緒操作DOM瀏覽器就暈了。瀏覽器不是單執行緒的,一些IO操作,定時器的計時和事件監聽是由其他執行緒完成的。

相關文章