這一系列的文章為修習 Udemy 的 The Complete JavaScript Course 2022: From Zero to Expert! 這堂課時所做的筆記。
認識「非同步(asynchronous)」之前,先來認識什麼是「同步(synchronous)」。
同步(synchronous)
當我們說程式碼為同步(synchronous)時,指的是它會「逐行」執行。所以,當其中一行程式碼所需的執行時間比較長,那就會導致後面所有的程式碼都要等待它執行完畢才能接續執行,造成「阻塞(blocking)」。
例如:alert()
會產生彈跳視窗,而在使用者還沒按下關閉鈕前,無法繼續執行後面的程式碼。
這概念有點像是,公共廁所只有一間時,長長人龍在廁所外等待的慘況。無論再怎麼急,都得耐心等候廁所裡面的人出來,下一個人才能進去,對吧?
同步聽起來好像有點糟欸(內急憋不住啊...),該怎麼解決 blocking 的問題呢?交給「非同步(asynchronous)」來處理!
非同步(asynchronous)
與同步的概念相反,非同步程式碼不會等待前一行程式碼執行完成才繼續往下執行。例如:
console.log("1: start");
setTimeout(() => {
console.log("2: timer");
}, 3000);
console.log("3: end");
- 如果按照我們前面介紹的同步觀念來思考的話,預想這段程式碼的執行結果會是這樣:
1: start
2: timer
3: end - 但實際結果是這樣的:
1: start
3: end
2: timer
驚不驚訝啊~所以我們會說 setTimeout()
是「非同步」的任務。
. . .
你在說什麼我聽不懂 一下說JS裡面有同步,一下又說它也有非同步 @@
所以,JS到底是屬於同步還是非同步啦?
簡單一句話,JS是具有「同步」性質的程式語言,但在瀏覽器的協助下,它可以達到非同步的效果。
我們都知道JS是單執行緒(single-threaded)的程式語言,也就是一次只能做一件事情(廁所只有一間,請好好排隊),不過在瀏覽器裡的 JS 有了 web API 的協助,便可以把「非同步」任務丟給 web API 協助處理(太好了!新建了一間廁所),JS 引擎就可以繼續執行自己該做的事情啦。
我們再來重新看看這段程式碼,說故事囉:
console.log("1: start");
setTimeout(() => {
console.log("2: timer");
}, 3000);
console.log("3: end");
JS 引擎開始從頭逐行執行程式碼...
- 首先遇到了
console.log("1: start")
。OK我處理!印出 1: start。 - 再來碰到了
setTimeout(...)
。欸欸欸這是 web API 的工作啊,我丟! - web API 正在處理
setTimeout(...)
。 - 好忙好忙我繼續工作,碰到
console.log("3: end")
。OK我處理!印出 3: end。 - web API 處理完
setTimeout(...)
後,把裡面由 JS 負責的console.log("2: timer")
丟回去給 JS 引擎。 - 印出 2: timer。
非同步可以提升執行效率,解決 blocking 的問題!
想想嘛,如果一切都是同步進行,那麼像是載入資料這類需要耗費較多時間的任務,將會導致blocking。使用者可能每執行一個動作,就要等個好幾秒(等到資料成功載入後)才能繼續下個動作。肯定會氣炸的吧 💢
結論
請善加利用非同步(都給你了這個酷法寶還不用嗎!),像是透過 Ajax 來完成非同步請求就能解決載入資料時造成 blocking 的問題。
欸... 可是要怎麼用?😅
下集待續。