從閉包引出來的一系列問題
從閉包引出來的一系列問題
1. 不起眼的開始
for(var i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i) }, 1000) }console.log(new Date, i)
很明顯,由於非同步的作用。到最後輸出的結果為6個5
如果用箭頭表示前後兩次輸出有1s的間隔,用,代表前後一起輸出,那麼輸出結果是5->5,5,5,5,5
這個也很容易的就可以進行解釋,先執行console.log()
,再進行setTimeout()
的非同步操作。
追問1:如果變成 5 -> 0,1,2,3,4 該怎樣處理?
首先可以使用閉包來解決這個問題:
for(var i = 0; i < 5; i++) { (function(j) { setTimeout(function() { console.log(new Date, j) }, 1000) })(i) }console.log(new Date, i) // 5
利用立即執行函式,來解決閉包造成的問題。
此外還可以使用setTimeout
的第三個引數 :
for(var i = 0; i < 5; i++) { setTimeout(function(j) { console.log(new Date, j) }, 1000, i) }console.log(new Date, i) // 5
可能會有很多同學採用ES6的方式來避免:
for(let i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i) }, 1000) }console.log(new Date, i)
但是此時並不能正確輸出我們想要的結果,因為let宣告的 i 產生了塊級作用域,導致 for 迴圈外面的輸出不能獲取的 i ,所以此時會報錯 i is not defined
追問2:如果把輸出變為 0->1->2->3->4->5 呢?
其中一種比較容易想到的方法:
for(var i = 0; i < 5; i++) { (function(j) { setTimeout(function() { console.log(new Date, j) }, 1000*j) })(i) } setTimeout(function() { console.log(new Date, i) }, 1000*i)
但是js中定時器的觸發時機是不確定的,每次迴圈都會產生一個非同步操作之後,會有一個輸出,那麼完全可以使用Promise
來解決這個問題。
const tasks = []for(var i = 0; i < 5; i++) { (function(j){ tasks.push(new Promise((resolve) => { setTimeout(() => { console.log(new Date, j) resolve() }, j*1000) })) })(i) }Promise.all(tasks).then( () => { setTimeout( () => { console.log(new Date, i) }, 1000) })
將上面程式碼處理一下:
const tasks = []const output = function(i) { new Promise( (resolve) => { setTimeout( () => { console.log(new Date, i) resolve() }, 1000*i) }) }for(var i = 0;i < 5; i++) { tasks.push(output(i)) }// 全部Promise執行完畢,執行最後一個輸出iPromise.all(tasks).then( () => { setTimeout( () => { console.log(new Date, i) }, 1000) })
追問3:使用 async / await
怎麼實現
// 模擬sleepconst sleep = (time) => new Promise((resolve) => { setTimeout(resolve, time); });(async () => { // 宣告即執行的 async 函式表示式 for (var i = 0; i < 5; i++) { if (i > 0) { await sleep(1000); } console.log(new Date, i); } await sleep(1000); console.log(new Date, i); })();
作者:宿雨jj
連結:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1868/viewspace-2815139/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 閉包問題
- 閉包 | 淺談JavaScript閉包問題JavaScript
- mysql 刪表引出的問題MySql
- go 閉包捕獲問題Go
- vue中methods中的方法閉包快取問題Vue快取
- Python閉包區域性變數問題Python變數
- [20231029]使用cygwin調式bash shell引出的問題.txt
- 荷蘭國旗問題引出的三色排序排序
- python安裝MySQL庫引出的一些問題PythonMySql
- react要避免閉包問題,具體指的是哪些?React
- 從這兩道題重新理解,JS的this、作用域、閉包、物件JS物件
- 從【零錢兌換】問題看01揹包和完全揹包問題
- Next.js-頁面重複渲染引出的水合問題JS
- go語言採坑:閉包共享變數問題Go變數
- Feign 400錯誤引發的一系列問題
- 前方一系列大事務問題來襲,請及時拉響警報
- Python:從閉包到裝飾器Python
- 收集的一些React hooks的效能優化以及閉包陷阱問題ReactHook優化
- 從執行上下文(ES3,ES5)的角度來理解"閉包"S3
- Python如何訪問閉包中的變數Python變數
- 面試題:如何理解閉包面試題
- 你真的懂01揹包問題嗎?01揹包的這幾問你能答出來嗎?
- 在 AI 的世界裡,年齡從來不是問題AI
- 什麼是閉包,閉包的優缺點?
- 閉包的起源
- JavaScript 的閉包JavaScript
- 我從來不理解JavaScript閉包,直到有人這樣向我解釋它JavaScript
- 我從來不理解JavaScript閉包,直到有人這樣向我解釋它...JavaScript
- 經典 JS 閉包面試題JS面試題
- 前端面試題15----閉包前端面試題
- 揹包問題
- 粘包問題
- 【Javascript】淺析JS中閉包的來龍去脈JavaScriptJS
- TCP粘包拆包問題TCP
- js閉包及閉包的經典使用場景JS
- [JavaScript閉包]Javascript閉包的判別,作用和示例JavaScript
- 什麼是閉包?閉包的作用是什麼?
- 【譯】JavaScript進階 從實現理解閉包JavaScript