繼上一篇,介紹了js中的函式與非同步環境會造成的callback Hell的前因後果,最終需要Promise來解決這個問題的過程後,此篇要記錄怎麼使用Promise物件。
Promise物件
Promise物件包含兩個東西,一個叫reslove
另一個叫reject
。
當該Promise執行成功的話,就會去呼叫reslove
,失敗的話,就會去執行reject
的內容。
Promise物件創建的方法
書中有提供兩種,其實意思差不多
函式運算式用new來創建
1 | const FirstPromise = new Promise((resolve, reject) => { |
函式回傳new Promise物件
1 | function FirstPromise() { |
then - 解決同步問題,依序執行函式
以上這個範例,可以看到我們利用創三個Promise物件,並利用then
,來依序執行這三個非同步的函式內容。
Promise.all 和 Promise.race - 解決非同步問題
若今天我們不在乎函式們的執行順序,只在乎他們有沒有執行完畢的話我們就可以使用 Promise.all 或 Promise.race。
Promise.all 和 Promise.race相異之處
Promise.all: 會等到所有的函式都執行完resolve之後,才會去執行then的內容。
Promise.race: 只要其中一個函式執行完它的resolve後,就會去執行then的內容,但是,其他還沒執行完的函式並不會被取消,也是一樣會被執行喔。
Promise.all 和 Promise.race相同之處
只要有其中一個函式回傳reject的話,就會中止執行其他的函式。
Promise.all範例
Promise.race範例
async/await - 讓Promise寫法更簡潔
這個寫法是可以讓Promise寫法更簡潔。
代替then寫法
我們想要依序處理非同步函式,之前我們是用then來達成,那這邊我們使用async/await來達成。
step1.
先創建一些Promise物件
step2.
創一個async function
並在這個函式裡面,使用await
來呼叫在step1創建的Promise物件,最後,程式就會依照await
呼叫的順序,
來依序執行這些Promise物件,達到跟then
一樣的效果囉。
以上這個範例,就可以看出來我們利用async/await 來控制這些非同步函式的執行順序囉。
用在Promise.all
可以看到,Done的內容,會在Promise.all裡面的函式都resolve後,才出現。
setTimeout 與 setInterval的使用
setTimeout
這個功能是延遲一段時間之後,只執行一次該function內的內容。
setInterval
這個功能是延遲一段時固定間之後,執行該function內的內容,並循環這樣的操作。
clearTimeout(timeID) 與 clearInterval(timeID)
它們倆個都會回傳一個timerID,那我們就可以透過這些timerID來將這些相對應的setTimeout和setInterval的功能取消掉。
1 | let timerID = window.setTimeout(function(){ |
但是,要特別注意一下,clearTimeout要在你設定的Timeout時機以內取消掉他才有用喔,不然等它執行之後才取消的話,clearTimeout就沒啥用。
JS單執行緒 與 同步、非同步之間的關係
JavaScript是「單執行緒」的語言,就代表它同一時間只能做一項任務。
那這樣的話,怎麼還會有同步和非同步的概念的出現呢?
這是因為,JS的設計者把要執行的任務分成同步和非同步的任務。
而setTimeout
和ajax(將口罩地圖的api接近來的行為)
這些功能,就是非同步的任務。
這邊要再複習一下,Promise物件是主要用來控制非同步的任務的作用順序。
主執行緒 和 Event Queue
JS一開始會把所有任務,不管它是同步還是非同步都會先把它們都放在主執行緒裡面排序好,當程式開始執行主行緒裡面的任務時,
當它一遇到非同步的任務,就會跳過不執行,並將該非同步任務放到Event Queue裡面。
等到主行緒裡面的任務都執行完畢之後,才接著繼續執行Event Queue裡面的callback function。
以上這個範例你可以看到,就算我們將setTimeout的延遲時間設定為0秒,但最終,還是最後才執行它的內容,由此可以看出來他是被放在event queue裡面,最後才被執行。
js主執行緒機制會導致非同步函式延遲
那因為js有以上這種會將非同步函式放在event queue的特性,當主執行緒的執行任務太多,執行時間太久的話,可能會延遲非同步函式的執行時間,進而導致像是setTimeout和setInterval所設定的時間不準。