轉(zhuǎn)載請(qǐng)注明出處:探索Flash播放器“運(yùn)行緩慢”的原因及解決方案 - http:///resources/upload-causing-flashplayer-slowly/
最近在實(shí)現(xiàn)基于JavaScript和ActionScript的“批量文件上傳系統(tǒng)”。感謝SWFUpload這樣一個(gè)有趣的項(xiàng)目,從前到后ActionScript(AS2)、JavaScript和PHP都已經(jīng)基本搞定。然而,當(dāng)我把本地的PHP腳本移到服務(wù)器上之后,在上傳大文件時(shí),瀏覽器端的FlashPlayer總是彈出如下警告:
A script in this movie is causing Adobe Flash Player to run slowly. If it continues to run, your computer may become unresponsive. Do you want to abort the script?
大致意思是:“該Flash中有一段單幀腳本導(dǎo)致Flash播放器運(yùn)行緩慢,如果繼續(xù),很可能會(huì)引發(fā)‘死機(jī)’現(xiàn)象”。其中,單幀腳本是指在Flash的一個(gè)關(guān)鍵幀中所處理的腳本。
Flash程序,也就是ActionScript,和C++、Java不同,ActionScript在2.0之前的入門門檻非常低,幾乎小學(xué)生學(xué)幾天都可以寫一個(gè)上來溜溜(這并不是一件壞事)。這樣一來,產(chǎn)生了不少效率低下的作品,甚至不少Flash動(dòng)畫含有潛在的死循環(huán)體(例如點(diǎn)擊某個(gè)按鈕后執(zhí)行死循環(huán))。雖然我們應(yīng)該給初學(xué)者鼓勵(lì),但對(duì)于while(true)類似的死循環(huán),則無疑嚴(yán)重破壞了用戶體驗(yàn),甚至?xí)o用戶造成不必要的損失。因此,對(duì)于編寫不規(guī)范的ActionScript代碼,采取這種措施是非常有必要的。
Adobe官方的解釋是“幾乎沒有一個(gè)用戶愿意為一個(gè)操作等待15秒以上的時(shí)間,他們(用戶)會(huì)認(rèn)為應(yīng)用程序出了問題”。因此,Adobe非常“人性化地”在這個(gè)“由眾多專家調(diào)查而得出的15秒”的時(shí)間段后給用戶一個(gè)提示。同時(shí),也給出了一些方法,例如,可以將循環(huán)“分?jǐn)?#8221;到不同的關(guān)鍵幀上。對(duì)于載入服務(wù)器端數(shù)據(jù),如XML文件的案例,當(dāng)被載入數(shù)據(jù)超過64k的時(shí)候,應(yīng)將數(shù)據(jù)分開載入,并以不同的關(guān)鍵幀建立HTTP請(qǐng)求。這么做,比較類似我們?cè)贘avaScript中通過setInterval、setTimeout來解決。例如曾經(jīng)寫過一段JavaScript代碼來改變整個(gè)頁面鏈接的href屬性,提供增加alexa排名的可能性。
很遺憾,Adobe忽略了一件事:文件上傳。
FileReference和FileReferenceList兩個(gè)類在Flash8的引入,無疑是Flash在Browser端應(yīng)用極大的突破之一,曾經(jīng)困擾Web開發(fā)者的Ajax文件上傳和批量上傳,尤其是對(duì)文件類型、大小的客戶端檢測(cè),如今都能依靠FlashPlayer實(shí)現(xiàn)。而且,借助Flash8的External API,可以使ActionScript與JavaScript方便地通信,這樣就可以讓FlashPlayer在“幕后”完成一切的文件操作,而讓DOM(HTML)來展現(xiàn)內(nèi)容。
然而,恰恰是如此好的功能,卻幾乎每次都會(huì)受到上面提到的“腳本超時(shí)保護(hù)”的困擾。顯然,Adobe官方的解決方案在這里就行不通了。
利用Google搜索,發(fā)現(xiàn)無數(shù)的人也在詢問同樣的問題。后來在這篇介紹用Flex實(shí)現(xiàn)的批量上傳的文章后的評(píng)論里面,找到了一個(gè)叫做“Timothee Groleau”的哥們的“自問自答”,終于解開了迷團(tuán):FlashPlayer在觸發(fā)并執(zhí)行用戶定義的腳本(就是你編寫的ActionScript)時(shí),會(huì)重置“腳本超時(shí)值”(上文提到的15秒)。這樣,我們可在某一個(gè)“馬甲MovieClip”上綁定一個(gè)onEnterFrame事件,讓它不斷地(逐幀)執(zhí)行。最簡(jiǎn)單的做法就是:
_root.onEnterFrame=function(){return false}