AJAX非同步大解密 (筆記)

Event Queue 觀念重點

Event Queue 就是事件佇列,一次只能執行一件事,好比是買口罩排隊的概念,誰先排就誰先拿,先進先出的概念。

等待條件觸發在 JavaScript 稱為 Event queue。像是 setTimeout, addEventListener, XMLHttpRequest 等等,這些方法在執行時會先將事件放到這地方,並將所有的事件堆疊完成後,才會開始讓 event queue 內的事件被觸發。

JavaScript是單線程語言

JavaScript 是 Single Thread,啟動JavaScript語法時只會啟動一顆CPU單核,一次只能做一件事。

Event Queue利用時間差

讓 JavaScript 感覺好像可以同時做很多事情,其實沒有,只是利用 event queue 產生時間差。

計時器,AJAX等等不是單線程

setTimeout , AJAX , Promise 等等是屬於 WebAPIs,不在 JavaScript 單線程限制範圍內。

Event Queue Demo

Demo 1 / 單線程

1
2
3
4
5
6
7
8
9
10
11
console.log("a");                  //1.先執行 a
function run(){ // run 的函數
console.log("b");
}
run(); //2.執行 run 的函數得到 b
console.log("c"); //3.最後執行 c

//---------------------------------打上以上語法,會依照單一線程陸續出現以下順序
a
b
c

Demo 2 / 非同步(單線程)

1
2
3
4
5
6
7
8
9
10
11
12
console.log("a");                  //1.先執行 a
function run(){ // run 的函數
console.log("b");
}
setTimeout(run,3000) //2.使用計時器會放入Event Queue,過3秒後執行 run 的函數得到 b
console.log("c"); //3.執行 c 完後,再去執行已經放進Event Queue的 b (一次只能執行一件事)

//---------------------------------打上以上語法,出現以下順序,
a
c
undefined //等待計時器
b //過3秒後出現b

Demo 3 / 非同步(WebAPIs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log("a");                  //1.先執行 a
function run(){ // run 的函數
console.log("b");
}
setTimeout(run,3000) //2.將計時器放入第一個event queue,3秒後執行 run 的函數得到 b
var start = Date.now();
while(Date.now() - start <= 5000){ //3.將迴圈放入第二個event queue,執行 5 秒鐘
}
console.log("c"); //4.執行 c ,

//---------------------------------打上以上語法,出現以下順序,
a
c //與b同時出現
undefined //等待計時器
b //與c同時出現

c、b 會同時出現,是因為跑放入第一個queue的計時器b,3秒後執行run函數得到b,b在queue裡待著,
然後再執行第二個queue的迴圈,5秒鐘後,queue裡沒有其他要做的,就把b放出來,就會同步跟c出現。


AJAX 觀念重點

請求回應方式

  • 傳統網頁 :
    請求 > 等待回應 > 請求 > 等待回應 … 一直重複一個請求,在等待一個回應後,才能再請求動作。
  • AJAX網頁 :
    在背景送出請求取得回應,同時還可以繼續在網頁上繼續動作

名稱由來

AJAX原名為 Asynchronous JavaScript and XML,其中XML,是早期比較流行的資料交換格式,
現在是流行JSON格式。

目前常見的底層 (原生語法..等)

  • XMLHttpRequest ( IE7以上支援、jQuery, Axios )
  • fetch ( 較新,HTML5才有、IE11(含)以下Bye了 )

測試用API

AJAX Demo

Demo 1 / 非同步GET請求發送

利用測試的API,得到連結套回程式碼中

利用瀏覽器 Console ,輸入程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log("start");
var xhr = new XMLHttpRequest();
xhr.addEventListener('load',function(){
console.log(this.responseText);
});
xhr.open('GET','測試API產生出來的網址',true); //true啟動非同步
xhr.send();
console.log("end");
-----------------------------------輸入後會得到以下非同步結果
start
end
undefined
message;info

依序處理console,碰到要請求回應的就在背景處理,讓程式碼繼續往下跑,
所以會先出來 start 再來跳過請求處理,出來 end,最後等待讀取完畢出現 message;info

Demo 2 / 同步GET請求發送

1
2
3
4
5
6
7
8
9
10
console.log("start");
var xhr = new XMLHttpRequest();
xhr.open('GET','測試API產生出來的網址',false); //同步
xhr.send();
console.log(xhr.responseText);
console.log("end");
-----------------------------------輸入後會得到以下結果
start
message;info
end

同步會先 start,再來等待中間那段請求產生的文字message;infoend會最後才出現。

建議盡可能都使用非同步處理,因為使用同步可能會等待很多時間處理,可能會影響渲染網頁畫面不完全,而有不好使用體驗。

Demo 3 / 非同步POST請求發送

如果要傳送資料給遠端,將GET改成POST,如果要帶參數傳回去可用FormData()方式處理

1
2
3
4
5
6
7
8
9
10
console.log("start");
var data = new FormData(); //使用參數資料
data.append('id','5'); //寫入參數
var xhr = new XMLHttpRequest();
xhr.addEventListener('load',function(){
console.log(this.responseText);
});
xhr.open('POST','測試API產生出來的網址',true); //非同步
xhr.send(data); //帶入data參數資料
console.log("end");

Demo 4 / 同步POST請求發送

1
2
3
4
5
6
7
8
console.log("start");
var data = new FormData(); //使用參數資料
data.append('id','5'); //寫入參數
var xhr = new XMLHttpRequest();
xhr.open('GET','測試API產生出來的網址',false); //同步
xhr.send(data); //帶入data參數資料
console.log(xhr.responseText);
console.log("end");

Demo 5 / fetch發送GET請求

1
2
3
4
5
fetch("測試API產生出來的網址").then(response => {
return response.json();
}).then(data => {
console.log(data)
})

Demo 6 / fetch發送POST請求

1
2
3
4
5
6
7
8
9
10
var data = new FormData();
data.append('id','5');
fetch("測試API產生出來的網址",{
method:'POST',
body: data
}).then(response => {
return response.json();
}).then(data => {
console.log(data)
})

上課心得

了解 Event Queue 的觀念,知道哪種程式碼類型在排隊處理的先後順序,這樣子寫code過程,比較知道哪段應該要先寫,
利用非同步來那它在背景處理,這樣才能比較有效率。
另外也重新複習 AJAX 的同步與非同步,同時新知道新底層 fetch 的 GET/POST 用法,要繼續多學習了 !
DEMO部分也有用到 VUE 的寫法介紹,但我沒有寫因為我還不會,期待之後學到 VUE ,再來回頭了解體驗了。

延伸參考資料

鐵人賽:一次只能做一件事情的 JavaScript