JavaScript 非同步執行 (Ascynchronous)




同步執行 ( Scynchronous )

如果我有很多個任務,同步就是讓每個任務按照順序依序進行,後面的任務必須等待前面的任務執行完成後才會執行。

以生活例子比喻的話,假如我在買電影,我要等到前面所有排隊的人買完之後才能輪到我,而排在我後面的人也要等到我完成買電影票這個動作之後,才能輪到他們。

以程式碼來說明的話,同步執行就表示程式會依照所寫的程式碼一行一行去執行,而順序都是前一個動作執行完才會去接著執行下一個動作。同步程式的設計模式看起來會比較比較直覺,常見的程式語言像是C、C++、Java皆是採用同步模式。

假設有一個同步程式如下:

1
2
3
4
5
6
7
8
9
10
11
12
function func1() {
console.log('func1');
}
function func2() {
console.log('func2');
}
function func3() {
console.log('func3');
}
func1(1); // "func1"
func2(2); // "func2"
func3(3); // "func3"

我們可以發現程式是照順序一行一行進行輸出。

非同步執行 ( Ascynchronous )

像是在買電影的時候,如果前面排隊的人處理很久,就會造成後面所有人買電影票的時間拉長。

由於同步執行的設計模式,使得程式必須等待前一個步驟完成後才能繼續執行,如果前一個動作沒有完成就會無法進行下一個動作而造成阻塞。

而非同步模式則相反,後面的任務不用等待前面的任務完成,各自執行各自的任務。

當你去百貨公司吃飯的時候,你不需要等待其他人點完餐和吃完飯後才輪到你點餐,每個人都可以在拿到餐點的時候就可以吃了,並不需要等待其他人先吃完。如果你點的是一份較花時間的牛排,那我只點一杯飲料就可以優先拿到,而不需要等到你的餐點完成後才輪到我。

如果是以同步的方式去讀取資料,就會在資料回傳之前會持續進行等待的動作,直到確定資料已經讀取完成後才繼續進行下一個動作。

以非同步的方式讀取資料的話,在資料回傳之前我可以先做其他的事情,等待資料回傳後再進行通知。

讓我們用 setTimeout 來示範非同步執行:

1
2
3
4
5
6
7
8
// Say "Hello."
console.log("Hello.");
// Say "Goodbye" two seconds from now.
setTimeout(function() {
console.log("Goodbye!");
}, 2000);
// Say "Hello again!"
console.log("Hello again!");

由於 setTimeout 並不會暫停程式的執行,所以會立即執行後面的動作,等待時間到了才會呼叫並執行函式裡面的內容。

所以輸出的結果依序為:

  • Say “Hello”.

  • Say “Hello again!”

  • 程式等待兩秒鐘

  • Say “Goodbye!”

AJAX Requests

這個範例使用 jQuery 的 Ajax 來進行操作,我們在 button 上加入一個 click 事件,當使用者點擊後會送出 request ,請求成功後會呼叫 callback 並把結果存入 data

1
2
3
4
5
6
7
8
9
10
11
12
$(document).ready(function(){
$("button").click(function(){
let data;

$.ajax({url: "demo_test.txt", success: function(result){
$("#div1").html(result);
data = result;
}});

console.log(data);
});
});

由於程式並不會等待取回資料後才繼續執行,而是會先執行 console.log(data) ,所以不管怎樣程式都會印出 undefined

我們可以透過 callback functions 來讓程式依照我們想要的順序執行,不知道什麼是 callback 的請參考之前的文章。

JavaScript Callback Function

非同步和同步

傳統的網頁在使用者提交資料後(亦即對伺服器發出請求),必須等到伺服器回應並重新整理頁面後,才能繼續進行下一個動作,這段期間內使用者無法對該頁面進行任何的存取。而非同步請求允許使用者在發出請求到伺服器回應的期間內繼續使用頁面(例如:繼續操作網頁、輸入資料),等到完成回應,網頁僅對部份資訊進行更新,藉以達到更有效的即時互動,非同步的核心精神在於減少等待,讓執行緒同時處理更多作業藉以提升產能。

如果網站是採取同步執行的設計模式,當我請求某一個網頁資料時,在資料回傳後才能進行下一個步驟,中途如果網頁無法回應或是阻塞住了,整個網站就會卡住。

若網站是採取非同步執行,等待資料回傳的同時還是能進行其他應用,假使資料無法成功存取也不會影響到其他正常功能的操作。

參考文獻

  1. https://www.pluralsight.com/guides/introduction-to-asynchronous-javascript

  2. https://www.ithome.com.tw/node/74544

  3. https://ithelp.ithome.com.tw/articles/10197312

  4. https://blog.xuite.net/autosun/study/33280250-%5BJS%5D+Ajax+%E5%BB%BA%E7%AB%8B%E9%9D%9E%E5%90%8C%E6%AD%A5%E8%AB%8B%E6%B1%82%EF%BC%88%E4%B8%80%EF%BC%89