摘要:從閉包引出來的一系列問題不起眼的開始很明顯,由于異步的作用。追問如果變成該怎樣處理首先可以使用閉包來解決這個問題利用立即執行函數,來解決閉包造成的問題。
從閉包引出來的一系列問題 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執行完畢,執行最后一個輸出i Promise.all(tasks).then( () => { setTimeout( () => { console.log(new Date, i) }, 1000) })追問3:使用 async / await 怎么實現
// 模擬sleep const 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); })();
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/97099.html
摘要:作用域分類作用域共有兩種主要的工作模型。換句話說,作用域鏈是基于調用棧的,而不是代碼中的作用域嵌套。詞法作用域詞法作用域中,又可分為全局作用域,函數作用域和塊級作用域。 一篇鞏固基礎的文章,也可能是一系列的文章,梳理知識的遺漏點,同時也探究很多理所當然的事情背后的原理。 為什么探究基礎?因為你不去面試你就不知道基礎有多重要,或者是說當你的工作經歷沒有亮點的時候,基礎就是檢驗你好壞的一項...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經典面試題從輸入到頁面加載發生了什么這是一篇開發的科普類文章,涉及到優化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網絡基礎知識之 HTTP 協議 詳細介紹 HTT...
摘要:所以覺得把這個執行的詳細過程整理一下,幫助更好的理解。類似的語法報錯的如下圖所示三預編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進入預編譯階段。另開出新文章詳細分析,主要介紹執行階段中的同步任務執行和異步任務執行機制事件循環。 一、概述 js是一種非常靈活的語言,理解js引擎的執行過程對于我們學習js是非常有必要的。看了很多這方便文章,大多數是講的是事件循環(event loo...
閱讀 781·2021-11-09 09:47
閱讀 1568·2019-08-30 15:44
閱讀 1143·2019-08-26 13:46
閱讀 2107·2019-08-26 13:41
閱讀 1266·2019-08-26 13:32
閱讀 3772·2019-08-26 10:35
閱讀 3519·2019-08-23 17:16
閱讀 448·2019-08-23 17:07