我的程式碼大概長這樣, 請問應該怎樣才能使console.log(rawData)可以等待上面的setTimeout呢? 謝謝
axios
.get(BASE_URL)
.then((response) => {
setTimeout(() => {
rawData = response.data
}, 3000)
})
.then((response) => {
console.log(rawData)
})
.catch((err) => console.log(err));
axios 使用 Javascript 的 Promise
給一個範例:
const promise = new Promise((resolve) => {
return resolve('abc') // 將abc字串丟到下一個 then
}).then((data) => {
console.log(data) // data 收到 'abc'
})
// abc
使用以上的概念,在你的 setTimeout 裡面使用 Promise.resolve(data)
axios
.get(BASE_URL)
.then((response) => {
return new Promise( (resolve) => {
setTimeout(() => {
resolve(response.data)
// 3秒後透過Promise.resolve(response.data) 丟到下一個 then
}, 3000)
} )
})
.then((rawData) => { // 接收上一個resolve丟過來的資料
console.log(rawData)
})
.catch((err) => console.log(err));
我剛在家測試完,成功了~
謝謝你~
不過我一直以為axios的.then是會等待上一步完成後才會執行....不用再另外new一個promise
認真來說,你的理解是正確的。
它的確是等待上一步完成才執行。
但你誤解的是它完成的定義。
在它執行了setTimeout。對它來說就是已經完成了。
至於setTimeout等3秒後執行的程式。與它無關。
因為那又是另一個閉包的事了。
對它來講,它已經完成了「呼叫setTimeout」
你要理解JS的同步及非同步是什麼才行。
聽了你這樣說, 我想我下面的理解應該是錯的了
非同步是把要執行的指令放在stack中, 然後不管了, 直接執行下一行指令.
同步是要完成每一個指令才執下一個指令.
所以第二個.then是怎樣拿到rawData的呢?
不好意思我真的很不熟處理非同步
當你執行setTimeout
時,就會開始在瀏覽器web apis開始讀秒,直到時間到了才會將setTimeout
的callback放進event loop中的 callback queue
然後直到call stack清空才會將 queue裡的callback function放進去並開始執行。
所以「大概」的流程會是
axios.get
放入到callback queue.then()
setTimeout
註冊timer.then()
console.log(rawData)
setTimeout
的callback放進queuerawData = response.data
問題就是會在第三步只是單純的執行setTimeout
,所以基本上會像是.then(response=>void).then()
那第二個.then
沒有什麼東西可以等待的
所以如果不是用setTimeout
而是資料太多要.get
很久的話。
結果也是 .then(response=>void).then()
嗎?
題外問一下,你們覺得當後端工程師也有需要熟悉處理非同步嗎?
因為其實我是在讀後端....
hypons
不會,並不是setTimeout等太久所以最後是void
而是setTimoue本身就沒有retune value,然後剛好是非同步行為
所以他會等到同步的行為(確切來說是 call stack清空)
才會執行到setTimeout的callback
所以.then(response=>void).then()
中第二個.then
才不會等待setTimeout執行完才執行裡面的console.log,而是馬上執行
axios.get()
本身就是會回傳一個promise
所以你才有辦法.then
取出她的值,所以如果你又要進行一個有順序/需要等待的非同步操作,你就得用另外一個promise包起來
也就是上面例子在setTimeout裡時間到後將值resolve,而且也要回傳整個promise,否則下一個.then
會不知道到底是在等誰
而.get
太久可能會發生其他事情,像是timeout之類的錯誤,在promise中會用.catch
去做錯誤處理
至於後端需不需要懂非同步的問題,看語言
因為不是每個語言都有非同步的設計
可以單純看一個正常 function 的表現
function demo () {
setTimeout(() => {
console.log('timed out')
}, 2000)
return 'done'
}
console.log(demo())
當 return
的時候表示 function 結束
可以清楚觀察到 console.log 先印出 done
, 約2秒後才印出 timed out
在執行的時候 setTimeout 會先被放在背景的 task queue 中, 直接執行下一行 return 'done'
這就是為什麼你認為
function 會等待裡面的程式全部做完才會結束
但 function 其實早在 setTimedout 的 callback 執行前就已經結束了
, 放到背景queue的 task 已經與function脫離獨立
至於背景task怎麼運作的有興趣可以看一下
https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
Todd
所以你意思是如果情況單純是想等.get
把全部資料都取得後才.then
動態的加到畫面中,是不需要再加promise
也可以做到。但因為我發問時的例子用了setTimeout
,所以才需要另外再加一個promise。是這樣嗎?
cloudeasy
哦, 那我懂了, 所以對.then來說是已經完成執行. 但setTimeout其實是卡在task queue...