在JavaScript的學習過程當中,同步與非同步是兩個讓人非常頭痛的概念,對於初學者來說尤其如此。簡單來說,當兩件或兩件以上的事情同時發生的時候,這就叫同步;當他們並非同時發生的時候,這就叫異步。
這兩個概念雖然看起來很簡單,但是實際理解起來卻需要花一番功夫。我們需要透過實際操作,來了解什麼情況是同步,什麼情況是非同步。
你可能認為,普通的JavaScript函數,都是同步的。當你在使用setTimeout()和AJAX的時候,你可能也會認為他們是同步的,是不是?如果我告訴你,這兩個函數在某些時候也可以非同步,你相信嗎?
要想解釋清楚原因,我們需要Mr X來幫忙。
場景1:Mr X嘗試使用同步性
條件:
1 Mr X是一個能解決複雜問題的人,能夠執行任何被指派的任務。
2 要和他聯繫,唯一的方式就是打電話。
3 無論你遇到了什麼問題或是任務,要想找Mr X幫忙,你就要打電話給他。
4 Mr X會給你提供回答,或是立刻完成任務,並且在完成之後通知你。
5 在Mr X的幫助下,你完成了任務,然後出去看電影。
在這個過程中,你和Mr X完成的,就是同步溝通。
你提問的時候,他在聽;他給答案的時候,你也同時在聽。
場景2:Mr X不喜歡同步性
由於Mr X的能力實在太高,越來越多的人開始找他尋求幫助。於是,你打電話給他的時候,卻老是佔線。你沒辦法向他提問,他更無法幫你回答問題。
那麼Mr X能如何應對這種情況?
1 Mr X僱用一個助手Mr M,並且配備一台答錄機。
2 Mr M的工作,就是聽答錄機上的留言,然後把問題總結出來交給Mr X。
3 這樣一來,當你打電話給Mr X的時候,你所聽到的不再是佔線的忙音,而是把問題留在答錄機上,等待Mr X回電。
4 在解答問其他人的問題之後,Mr X給你回電,告訴你解決方法。
那麼問題來了,這個過程是同步溝通還是非同步溝通?
可以說,兩者兼有。當你在答錄機留言的時候,Mr X並沒有在聽,所以這是非同步溝通。
但是當他回電的時候,你們兩個之間進行的,就是同步溝通了。
現在你應該已經理解溝通時的同步和非同步了。現在再來談談JavaScript的同步與非同步。
JavaScript – 一種非同步的程式語言
當有人說JavaScript是一種非同步語言的時候,他的意思就是,整體來說,在使用JavaScript的時候,你需要對它進行留言,在給它打電話的時候,你聽到的不會是忙音。
JavaScript中的函數呼叫從來都不是直接發生的,它們是透過訊息留言來完成的。
JavaScript使用的是訊息佇列,新進來的訊息(或事件)被暫存在這裡。 event-loop不斷的對這些訊息進行處理,將它們發送到呼叫堆疊(call stack)中,在這裡,相應的訊息函數被堆積為用於執行的框架(函數的自變數和因變數)。
呼叫堆疊包含著第一個被呼叫的函數的框架,還有在這個函數之上透過巢狀呼叫被呼叫的其他函數的框架。
當一個訊息加入佇列,它會一直等待,直到呼叫堆疊中前邊的訊息框架被處理完成之後。前面的訊息被處理之後,event-loop會將其從佇列中移除,然後把目前訊息的對應框架加入到呼叫堆疊中。
這個訊息再一次開始等待,指導呼叫堆疊清空了它的對應框架,然後被從佇列中移除。
看看下面的程式碼:
function foo(){}function bar(){ foo(); }function baz(){ bar(); } baz();
這裡被運行的函數為baz(),位於程式碼段最後一行,它會作為一個訊息加入佇列中,當event-loop揀選了它的時候,呼叫堆疊在執行的過程中開始堆疊 baz(), bar(), 和 foo()的架構。
在函數的執行完畢之後,它們的框架會從呼叫堆疊中被移除出去,而訊息依然在佇列中等待,直到baz()在堆疊中被彈出。
記住,JavaScript中的函數呼叫從來都不是直接完成的,而是透過訊息完成的。
那些具體的非同步方法是怎麼回事?
目前為止,我已經接觸到了一些API,例如setTimeout()和AJAX,它們都被特別顯示為非同步方法。怎麼回事?
有一個非常重要的事情,那就是了解那些東西是同步發生,以及那些東西是異步發生的。在事件和event-loop的幫助下,JavaScript能夠對訊息進行非同步處理,但這並不意味著JavaScript裡的所有東西都是非同步的。
我之前說過,在呼叫堆疊清空對應框架之前,訊息是不會離開佇列的。舉個例子,就像是你沒拿到答案之前,是不會出去看電影的——這個時候發生的事情就是同步的:你站在那裡等著任務完成,親眼看到任務完成之後才會離開。
以上就是JavaScript的同步與非同步的內容,更多相關內容請關注PHP中文網(www.php.cn)!