Re: [問題] 延後執行的問題

看板Ajax作者 (function(){})()時間10年前 (2015/08/22 11:27), 10年前編輯推噓1(100)
留言1則, 1人參與, 最新討論串4/4 (看更多)
前陣子因為試用 Visual Studio Code 與 Electron 寫了一個小專案 剛好寫到跟你問題一模一樣的東西,code 在此 https://github.com/s25g5d4/SlideShow/blob/master/scripts/main.js#L76 我使用 mrbigmouth 板友提到的 async.js 套件,你可以參考一下 configs.images 是一個包含數個字串的陣列 (就是圖檔檔名) loadImg 函數會試著把這些圖檔載入,具體行為是 1. 建立 Image() 並檢查是否有 cache (透過檢查 complete 屬性) 2. 掛上 onload 事件 3. 掛上 onerror 事件 imgDone 函數是當 configs.images 裡所有圖檔都載入後 過濾錯誤的圖片,將頁面初始化並開始繪製畫面 -- 若不引入 async.js 套件,可以參考 dianwu 板友的解法 只是不需要多 imgReady 變數 直接檢查 array.length 跟 m.length 就好 另外一個做法是把 dosomething() 改寫成 function dosomething(val, array) { array.push(val); // 如果圖檔還沒全部載入,就先退出 function if (array.length < m.length) return; // 若執行到這邊代表圖檔已全部載入 // 接著做原本該做的事 // ... } 原本 onload 事件改成 img.onload = function () { //圖片讀取好後進行一些處理再return回來 var t = doImg(this); i.forEach(function(p){ //將圖片及資訊push進array dosomething({ img : t, p1 : p, p2 : [p[0] + t.width, p[1] + t.height], p3 : t.pos[1] + p[1] }, array); }); }; -- 另外 dianwu 板友提到「不建議在迴圈中直接宣告 function」 我的看法是「不建議使用匿名函數」 這並不是代表不要使用 callback 或 Immediately-invoked function expression 註:即 (function () { /* some code */ }()) 而是使用 function expression (以下簡稱 func expr) 時一定要指定函數名稱 在偵錯的時候瀏覽器開發工具或 Node.js 大多會提供 function call stack 如果用一堆匿名函數,錯誤訊息會看得很痛苦 http://craigshoemaker.net/images/command-prompt-node-error.png
有看到 at <anonymous>:1:55 嗎? 如果 func expr 在內部須呼叫 func expr 本身 使用具名函數便可以以該名稱存取自己 範例: setTimeout(function doAnimation() { // do something setTimeout(doAnimation, 100); }, 100); 而且不會造成任何變數汙染問題 doAnimation 名稱只在 doAnimation 函數內可見 即使在與 setTimeout 同 scope 的地方也不可見 doAnimation 所以不用擔心會蓋掉同樣名稱的變數 -- 其實我不知道為什麼 scope 會有問題 除非把 function 提到迴圈所在 scope 外面才會造成 scope 不同 以下兩個例子的 scope 是一樣的 ======== array.forEach(function forEach(e, i) { // do something }); ======== var doSomething = function doSomething(e, i) { // do something }; array.forEach(doSomething); ======= 在大多數情況下, callback function 應該不需要離 iteration 太遠 頂多拉出來變成另一個變數,這樣還是會在同一個 scope 下啊 XD 如果有必要讓 callback 與 iteration 所在 scope 不同 那應該是這個 callback 可以在多個地方重複使用 這種情況下就需要注意 scope 的問題 javascript 是 static(lexical) scope 的語言 scope 只與 function 定義的地方有關,與執行期 call stack 無關 --

07/27 22:36,
昨天看到就秒下載了
07/27 22:36

07/27 22:40,
好色龍也喜歡人味重的了? 我還以為擬人度高的都不行呢
07/27 22:40

07/27 22:42,
你誤會了 好色龍看上的是那狼人
07/27 22:42

07/27 22:43,
你看三樓就很懂
07/27 22:43
-- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 1.174.152.40 ※ 文章網址: https://www.ptt.cc/bbs/Ajax/M.1440214075.A.C46.html

08/22 12:31, , 1F
詳細的解說,我印象中如果在迴圈內的function 直接使用上
08/22 12:31, 1F

08/22 12:31, , 2F
層的變數很可能在執行時與一開始的想法有出入,特別又是im
08/22 12:31, 2F

08/22 12:31, , 3F
g onload,但早上回文時沒有再實做確認一次,也許錯了:)
08/22 12:31, 3F
你說的其實不是 scope 問題 是因為 async call 的關係,抓到的是被覆蓋掉的值 解決方法是建立一個新的 scope, 也就是 closure var i; for (i = 0; i < 5; ++i) { setTimeout(function () { alert(i); }, 1); } 這個範例會彈出五個 5, 而不是預期的 0, 1, 2, 3, 4 var i; for (i = 0; i < 5; ++i) { (function (t) { setTimeout(function () { alert(t); }, 1); }(i)); } 這樣才是預期的 0, 1, 2, 3, 4 -- 酷一點的解法 var i; for (i = 0; i < 5; ++i) { setTimeout(alert.bind(this, i), 1); } -- 這應該是講到爛掉的問題了 :P ※ 編輯: s25g5d4 (1.174.152.40), 08/22/2015 13:13:05

08/22 23:18, , 4F
謝謝大大詳細講解!檢查快取那一步讓我學到了新東西!
08/22 23:18, 4F
文章代碼(AID): #1Lr-mxn6 (Ajax)
文章代碼(AID): #1Lr-mxn6 (Ajax)