1. 程式人生 > 其它 >javascript中非同步和同步的區別是什麼

javascript中非同步和同步的區別是什麼

區別:在同步中,發出一個功能呼叫時,必須一件一件事做,等前一件做完了才能做下一件事;而在非同步中,當一個非同步過程呼叫發出後,呼叫者在沒有得到結果之前,就可以繼續執行後續操作。

javascript語言是一門“單執行緒”的語言,

不像java語言,類繼承Thread再來個thread.start就可以開闢一個執行緒。

所以,javascript就像一條流水線,僅僅是一條流水線而已,要麼加工,要麼包裝,不能同時進行多個任務和流程。

“同步”——一下就讓人想到“一起”這個詞;

“非同步”呢,從字面來講,好像是在不同的(異)的ways上do something,

那首先想到的詞可能是“一邊...一邊...”,比如‘小明一邊吃雪糕一邊寫作業’,這完全沒毛病,雪糕吃完了,作業也寫完了,這就是非同步?那就大錯特錯了!

其實同步和非同步,

無論如何,做事情的時候都是隻有一條流水線(單執行緒),

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

最基礎的非同步是setTimeout和setInterval函式,

很常見,但是很少人有人知道其實這就是非同步,

因為它們可以控制js的執行順序。我們也可以簡單地理解為:

可以改變程式正常執行順序的操作就可以看成是非同步操作。如下程式碼:

1

2

3

4

5

6

7

8

9

10

11

console.log( "1" );

setTimeout(function() {

console.log( "2" )

}, 0 );

setTimeout(function() {

console.log( "3" )

}, 0 );

setTimeout(function() {

console.log( "4" )

}, 0 );

console.log( "5" );

輸出順序是什麼呢?

可見,儘管我們設定了setTimeout(function,time)中的等待時間為0,結果其中的function還是後執行。

儘管setTimeout的time延遲時間為0,

其中的function也會被放入一個佇列中,等待下一個機會執行,

當前的程式碼(指不需要加入佇列中的程式)必須在該佇列的程式完成之前完成,

因此結果可能不與預期結果相同。

這裡說到了一個“佇列”(即任務佇列),

該佇列放的是什麼呢,放的就是setTimeout中的function,

這些function依次加入該佇列,

即該佇列中所有function中的程式將會在該佇列以外的所有程式碼執行完畢之後再以此執行,

這是為什麼呢?因為在執行程式的時候,瀏覽器會預設setTimeout以及ajax請求這一類的方法都是耗時程式(儘管可能不耗時),
將其加入一個佇列中,該佇列是一個儲存耗時程式的佇列,在所有不耗時程式執行過後,再來依次執行該佇列中的程式。

又回到了最初的起點——javascript是單執行緒。 單執行緒就意味著,所有任務需要排隊,前一個任務結束,才會執行後一個任務。
如果前一個任務耗時很長,後一個任務就不得不一直等著。
於是就有一個概念——任務佇列。如果排隊是因為計算量大,CPU忙不過來,倒也算了,

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

於是,所有任務可以分成兩種,

一種是同步任務(synchronous),另一種是非同步任務(asynchronous)。 同步任務指的是,在主執行緒上排隊執行的任務,
只有前一個任務執行完畢,才能執行後一個任務; 非同步任務指的是,不進入主執行緒、而進入"任務佇列"(task queue)的任務,只有等主執行緒任務執行完畢,"任務佇列"開始通知主執行緒,請求執行任務,該任務才會進入主執行緒執行。
具體來說,非同步執行機制如下:

所有同步任務都在主執行緒上執行,形成一個執行棧(execution context stack)。

主執行緒之外,還存在一個"任務佇列"(task queue)。只要非同步任務有了執行結果,就在"任務佇列"之中放置一個事件。

一旦"執行棧"中的所有同步任務執行完畢,系統就會讀取"任務佇列",看看裡面有哪些事件。那些對應的非同步任務,於是結束等待狀態,進入執行棧,開始執行。

主執行緒不斷重複上面的第三步。

只要主執行緒空了,就會去讀取"任務佇列",這就是JavaScript的執行機制。這個過程會不斷重複。

"任務佇列"中的事件,除了IO裝置的事件以外,

還包括一些使用者產生的事件(比如滑鼠點選、頁面滾動等等),

比如$(selectot).click(function),這些都是相對耗時的操作。

只要指定過這些事件的回撥函式,這些事件發生時就會進入"任務佇列",等待主執行緒讀取。

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