近期在搞Mix2ool,是mix framework的進化版,這次view engine由B/S 轉為C/S架構,大量使用了javascript。
其中寫了這麼的一段
1 2 3 4 5 6 7 8 9 10 11 | mix.Bindable.bindingFunc = function (n, old, vari){ var b = $(this).attr("binding"); if (b == null) b = ""; var context = this; b.replace(" ", "").split(";").removeNothing().each(function (v){ var t = v.split(":"); if (t[1] == vari){ $(this).attr(t[0], n); } }, this); }; |
就是做binding的工作,然而卻產生了too much recursion的問題,因為當我setAttribute的時候,下一個element也會notify一個attrChange event,那個event同時又做了binding的工作,結果bind得沒完沒了。
解決方法是把$(this).attr(t[0], n)放在一個新的closure中進行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | mix.Bindable.bindingFunc = function (n, old, vari){ var b = $(this).attr("binding"); if (b == null) b = ""; var context = this; b.replace(" ", "").split(";").removeNothing().each(function (v){ var t = v.split(":"); if (t[1] == vari){ if (mix.Bindable.stacked > mix.Bindable.maxStack){ //if there are too many stacked event handlers, browsers will stop running due to "too much recursion" mix.Bindable.stacked = 0; (function(){ //this method is generally slower in performance, so use different methods alternatively $(context).attr(t[0], n); }).once(0); }else{ mix.Bindable.stacked++; $(this).attr(t[0], n); } } }, this); }; |
把.attr()放在一個function之中並在0微秒之後執行(setTimeout),可以在這個closure的執行者設為window,而不是mix.Bindable.bindFunc,那就可以解決問題了。然而,如果把所有工作都放到新的function內執行,setTimeout產生出來的delay會很明顯,因此我用了mix.Bindable.stacked來記錄recur了的次數,當recur到一定大的地步才會在新的function執行,這可以加快一點速度。
P.S.其實這個方法不太好,現在我在想其他方法。
Categories : Uncategorized