循環異步操作的影響以及其解決方案


  上一次,我已經講過閉包是如何形成的,以及它的用途。但是對於循環閉包產生的陷阱,和解決方案一筆帶過啊(根本就沒有)!本着不坑爹的思想,絕逼是要重新再梳理一遍。但無論如何還是要強調一下的,在閉包中會一直引用變量(是引用而不是副本),直到其斷開連接不再引用,在內存中的閉包就可以得到釋放。所以當我們知道這個道理之后,我們就可以開始我們今天的旅程了。

  上次的例子舉的不夠好,竟然要操作DOM的,這次我們換個更直觀的寫法,用setTimeout函數。

  show code!

  這一次使用的是定時器setTimeout,大家都知道定時器函數執行的都是回調函數,即使那里的延時是0秒,也是等循環做完以后再輸出引用的 i 值,所以自然是一直輸出的是3。當然今天的重點是在如何避免出現這種情況,以及它的原理。其實我們只要對我們的代碼做個非常小的變動就可以了。它的原理就是,我們手動再建立閉包,讓正確的迭代值作為參數傳入其中。

  好,直接看看代碼吧。

  這里就是用了剛才說的,手動建立閉包。在回調函數外部再包裹多一層匿名函數,並用循環的i值作為參數傳入,setTimeout函數引用了匿名函數的參數Index,形成閉包。但是關鍵是這里的閉包有三個,所以最后並不會影響正確答案。

  不過,這樣的寫法難道不覺得有點惡心嗎?!我們可以不怕麻煩的,用我上一篇閉包說過的,用個輔助函數稍微簡化下,但原理是一樣的。

  我們從這兩個例子里,可以很明確的看到,回調函數不再是直接引用循環的變量,而是引用了新的父函數(包裹函數)的參數。這樣我們就可以避開循環造成的閉包陷阱了。當然我最后還是留了一個大招,ECMAScript5 的方法,forEach!

  我們簡單了解一下forEach(《JavaScript高級程序設計》96頁,有詳細解釋)。forEach可以接收兩個參數,一個是要循環執行的函數,另一個是指定執行該函數的對象改變this的值(可選參數)。當然重點在第一個參數,也就是要執行循環的函數,它會被傳入三個參數,當前的值item,在數組的位置index 和數組對象本身array。

  forEach其中有一個參數是當前的位置index,我告訴你,大膽放心的用!看代碼!

  干凈利索!連for循環都木有了。這個方法可以讓我們不用再考慮手動建立閉包的事,非常的酷炫!

  但是要強調兩點:

  1、這個方法是不能用在古董瀏覽器的(IE6-8),但是我們可以自行在數組的prototype里拓展呀!

  2、這個方法僅僅是數組對象的方法,對於類數組對象(如nodeList之流的)是無法直接使用的,但是我們可以Array.prototype.forEach.call呀!!

  對於call的作用不是很理解的同學,可以看看我的另一篇博客http://www.cnblogs.com/YikaJ/p/4113831.html,只要用心思考過,想必是可以幫助你更好的掌握call和apply的!

 

  原諒我,現在七點,我還沒吃飯,我得趕緊發完這篇blog吃飯去啦~!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM