摘要:從閉包引出來的一系列問題不起眼的開始很明顯,由于異步的作用。追問如果變成該怎樣處理首先可以使用閉包來解決這個問題利用立即執(zhí)行函數(shù),來解決閉包造成的問題。
從閉包引出來的一系列問題 1. 不起眼的開始
for(var i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i) }, 1000) } console.log(new Date, i)
很明顯,由于異步的作用。到最后輸出的結(jié)果為6個5
如果用箭頭表示前后兩次輸出有1s的間隔,用,代表前后一起輸出,那么輸出結(jié)果是5->5,5,5,5,5
這個也很容易的就可以進(jìn)行解釋,先執(zhí)行console.log(),再進(jìn)行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
利用立即執(zhí)行函數(shù),來解決閉包造成的問題。
此外還可以使用setTimeout的第三個參數(shù) 文檔:
for(var i = 0; i < 5; i++) { setTimeout(function(j) { console.log(new Date, j) }, 1000, i) } console.log(new Date, i) // 5
可能會有很多同學(xué)采用ES6的方式來避免:
for(let i = 0; i < 5; i++) { setTimeout(function() { console.log(new Date, i) }, 1000) } console.log(new Date, i)
但是此時并不能正確輸出我們想要的結(jié)果,因?yàn)閘et聲明的 i 產(chǎn)生了塊級作用域,導(dǎo)致 for 循環(huán)外面的輸出不能獲取的 i ,所以此時會報錯 i is not defined
追問2:如果把輸出變?yōu)?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中定時器的觸發(fā)時機(jī)是不確定的,每次循環(huán)都會產(chǎn)生一個異步操作之后,會有一個輸出,那么完全可以使用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執(zhí)行完畢,執(zhí)行最后一個輸出i Promise.all(tasks).then( () => { setTimeout( () => { console.log(new Date, i) }, 1000) })追問3:使用 async / await 怎么實(shí)現(xiàn)
// 模擬sleep const sleep = (time) => new Promise((resolve) => { setTimeout(resolve, time); }); (async () => { // 聲明即執(zhí)行的 async 函數(shù)表達(dá)式 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); })();
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/97099.html
摘要:作用域分類作用域共有兩種主要的工作模型。換句話說,作用域鏈?zhǔn)腔谡{(diào)用棧的,而不是代碼中的作用域嵌套。詞法作用域詞法作用域中,又可分為全局作用域,函數(shù)作用域和塊級作用域。 一篇鞏固基礎(chǔ)的文章,也可能是一系列的文章,梳理知識的遺漏點(diǎn),同時也探究很多理所當(dāng)然的事情背后的原理。 為什么探究基礎(chǔ)?因?yàn)槟悴蝗ッ嬖嚹憔筒恢阑A(chǔ)有多重要,或者是說當(dāng)你的工作經(jīng)歷沒有亮點(diǎn)的時候,基礎(chǔ)就是檢驗(yàn)?zāi)愫脡牡囊豁?xiàng)...
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識之 HTTP 協(xié)議 詳細(xì)介紹 HTT...
摘要:所以覺得把這個執(zhí)行的詳細(xì)過程整理一下,幫助更好的理解。類似的語法報錯的如下圖所示三預(yù)編譯階段代碼塊通過語法分析階段之后,語法都正確的下回進(jìn)入預(yù)編譯階段。另開出新文章詳細(xì)分析,主要介紹執(zhí)行階段中的同步任務(wù)執(zhí)行和異步任務(wù)執(zhí)行機(jī)制事件循環(huán)。 一、概述 js是一種非常靈活的語言,理解js引擎的執(zhí)行過程對于我們學(xué)習(xí)js是非常有必要的??戳撕芏噙@方便文章,大多數(shù)是講的是事件循環(huán)(event loo...
摘要:如果本次定時器沒有被清除,時間到后就會自然執(zhí)行事件處理函數(shù)。綁定去抖后的事件回調(diào)函數(shù)綁定回調(diào)函數(shù)的屬性方法,點(diǎn)擊頁面,重置去抖效果異步請求清空上一次事件觸發(fā)的定時器重置為從而下一次事件觸發(fā)就能立即執(zhí)行。 一、前言 為什么會有去抖和節(jié)流這類工具函數(shù)? 在用戶和前端頁面的交互過程中,很多操作的觸發(fā)頻率非常高,比如鼠標(biāo)移動 mousemove 事件, 滾動條滑動 scroll 事件, 輸...
閱讀 847·2021-11-09 09:47
閱讀 1654·2019-08-30 15:44
閱讀 1195·2019-08-26 13:46
閱讀 2178·2019-08-26 13:41
閱讀 1366·2019-08-26 13:32
閱讀 3847·2019-08-26 10:35
閱讀 3597·2019-08-23 17:16
閱讀 517·2019-08-23 17:07