亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

提升JS性能:將遞歸轉換為迭代

2024-09-06 12:40:55
字體:
來源:轉載
供稿:網友

影響javascript性能的另外一個殺手就是遞歸,在上一節中提到采用memoization技術可以優化計算數值的遞歸函數,但memoization不是萬能的,不是所有的遞歸函數都可以用memoization技術優化,本文介紹了這些情況,并介紹了解決辦法,就是將遞歸轉換為迭代,同時需要注意,本文末尾介紹的方案不是最終的方案,還需要和上一節優化循環的方案綜合起來才能達到最佳效果。

【原文】speed up your javascript, part 3
【作者】nicholas c. zakas
【譯文】http://cuimingda.com/2009/02/speed-up-your-javascript-part-3.html
【譯者】明達

以下是對原文的翻譯

遞歸是拖慢腳本運行速度的大敵之一。太多的遞歸會讓瀏覽器變得越來越慢直到死掉或者莫名其妙的突然自動退出,所以我們一定要解決在javascript中出現的這一系列性能問題。在這個系列文章的第二篇中,我曾經簡短的介紹了如何通過memoization技術來替代函數中太多的遞歸調用。memoization是一種可以緩存之前運算結果的技術,這樣我們就不需要重新計算那些已經計算過的結果。對于通過遞歸來進行計算的函數,memoization簡直是太有用了。我現在使用的memoizer是由 crockford寫的,主要應用在那些返回整數的遞歸運算中。當然并不是所有的遞歸函數都返回整數,所以我們需要一個更加通用的memoizer()函數來處理更多類型的遞歸函數。

function memoizer(fundamental, cache) {
  cache = cache || {};
  var shell = function(arg) {
      if (! (arg in cache)) {
          cache[arg] = fundamental(shell, arg);
      }
      return cache[arg];
  };
  return shell;}

這個版本的函數和crockford寫的版本有一點點不同。首先,參數的順序被顛倒了,原有函數被設置為第一個參數,第二個參數是緩存對象,為可選參數,因為并不是所有的遞歸函數都包含初始信息。在函數內部,我將緩存對象的類型從數組轉換為對象,這樣這個版本就可以適應那些不是返回整數的遞歸函數。在shell函數里,我使用了in操作符來判斷參數是否已經包含在緩存里。這種寫法比測試類型不是undefined更加安全,因為undefined是一個有效的返回值。我們還是用之前提到的斐波納契數列來做說明:

var fibonacci = memoizer(function(recur, n) {
  return recur(n - 1) + recur(n - 2);
}, { "0": 0, "1": 1} );

同樣的,執行fibonacci(40)這個函數,只會對原有的函數調用40次,而不是夸張的331,160,280次。memoization對于那些有著嚴格定義的結果集的遞歸算法來說,簡直是棒極了。然而,確實還有很多遞歸算法不適合使用memoization方法來進行優化。

我在學校時的一位教授一直堅持認為,任何使用遞歸的情況,如果有需要,都可以使用迭代來代替。實際上,遞歸和迭代經常會被作為互相彌補的方法,尤其是在另外一種出問題的情況下。將遞歸算法轉換為迭代算法的技術,也是和開發語言無關的。這對javascript來說是很重要的,因為很多東西在執行環境中是受到限制的(the importance in javascript is greater, though, because the resources of the execution environment are so restrictive.)。讓我們回顧一個典型的遞歸算法,比如說歸并排序,在javascript中實現這個算法需要下面的代碼:

function merge(left, right) {
  var result = [];
  while (left.length > 0 && right.length > 0) {
      if (left[0] < right[0]) {
          result.push(left.shift());
      } else {
          result.push(right.shift());
      }
  }
  return result.concat(left).concat(right);
}

//采用遞歸實現的歸并排序算法
function mergesort(items) {
  if (items.length == 1) {
      return items;
  }
  var middle = math.floor(items.length / 2),
  left = items.slice(0, middle),
  right = items.slice(middle);
  return merge(mergesort(left), mergesort(right));
}

調用mergesort()函數處理一個數組,就可以返回經過排序的數組。注意每次調用mergesort()函數,都會有兩次遞歸調用。這個算法不可以使用memoization來進行優化,因為每個結果都只計算并使用一次,就算緩沖了結果也沒有什么用。如果你使用mergesort()函數來處理一個包含100個元素的數組,總共會有199次調用。1000個元素的數組將會執行1999次調用。在這種情況下,我們的解決方案是將遞歸算法轉換為迭代算法,也就是說要引入一些循環(關于算法,可以參考這篇《list processing: sort again, naturally》):

// 采用迭代實現的歸并排序算法
function mergesort(items) {
  if (items.length == 1) {
      return items;
  }
  var work = [];
  for (var i = 0,
  len = items.length; i < len; i++) {
      work.push([items[i]]);
  }
  work.push([]); //in case of odd number of items
  for (var lim = len; lim > 1; lim = (lim + 1) / 2) {
      for (var j = 0,
      k = 0; k < lim; j++, k += 2) {
          work[j] = merge(work[k], work[k + 1]);
      }
      work[j] = []; //in case of odd number of items
  }
  return work[0];
}

這個歸并排序算法實現使用了一系列循環來代替遞歸進行排序。由于歸并排序首先要將數組拆分成若干只有一個元素的數組,這個方法更加明確的執行了這個操作,而不是通過遞歸函數隱晦的完成。work數組被初始化為包含一堆只有一個元素數組的數組。在循環中每次會合并兩個數組,并將合并后的結果放回 work數組中。當函數執行完成后,排序的結果會通過work數組中的第一個元素返回。在這個歸并排序的實現中,沒有使用任何遞歸,同樣也實現了這個算法。然而,這樣做卻引入了大量的循環,循環的次數基于要排序的數組中元素的個數,所以我們可能需要使用在 上篇討論過的技術 來進行修訂,處理這些額外開銷。

總結一下基本原則,不管是什么時候使用遞歸的時候都應該小心謹慎。memoization和迭代是代替遞歸的兩種解決方案,最直接的結果當然就是避免那個 提示腳本失控的對話框。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲专区在线视频| 国产精品高潮呻吟久久av野狼| 欧美电影在线免费观看网站| 久久综合国产精品台湾中文娱乐网| 最近2019中文字幕在线高清| 久久久久久国产精品| 久久99视频免费| 清纯唯美亚洲激情| 午夜精品一区二区三区在线视频| 国产啪精品视频网站| 538国产精品视频一区二区| 亚洲欧美综合精品久久成人| 国产在线视频91| 日本成人在线视频网址| 国产精品偷伦视频免费观看国产| 欧美在线视频免费| 久久久久99精品久久久久| 亚洲精品乱码久久久久久按摩观| 亚洲精品美女久久久| 91精品国产色综合久久不卡98口| 国产一区二区三区网站| 欧美日韩国产中文精品字幕自在自线| 亚洲天堂av图片| 精品久久久久久中文字幕| 欧美高跟鞋交xxxxhd| 国产精品久久久久久久久久尿| 欧美成人久久久| 国产成人精品久久久| 久久精品久久久久久| 久久久久久久久爱| 欧美猛少妇色xxxxx| 成人女保姆的销魂服务| 日韩精品在线私人| 精品视频9999| 日韩中文字幕在线精品| 亚洲午夜精品久久久久久性色| 日韩一二三在线视频播| 国外成人在线直播| 日韩欧美一区二区在线| 国产亚洲激情在线| 国产成人精品在线视频| 欧美成人合集magnet| 91视频免费在线| 亚洲午夜av久久乱码| 久久国产精品首页| 亚洲第一中文字幕| 久久久久久久久久婷婷| 国产精品丝袜久久久久久不卡| 色偷偷91综合久久噜噜| 欧美精品日韩www.p站| 免费99精品国产自在在线| 在线免费观看羞羞视频一区二区| 日韩av中文在线| 国产日韩一区在线| 国产精品一区二区女厕厕| 欧美疯狂性受xxxxx另类| 亚洲一二三在线| 欧美在线视频观看| 中文字幕在线国产精品| 欧美日韩国产综合新一区| 日韩精品欧美激情| 国产日韩欧美自拍| 亚洲国产精品资源| 欧美日韩亚洲91| 欧美精品久久久久久久久| 这里只有精品在线播放| 91免费视频网站| 欧美黑人xxxx| 岛国精品视频在线播放| 97在线日本国产| 欧洲亚洲女同hd| 久久九九热免费视频| 亚洲第一精品夜夜躁人人躁| 午夜精品视频网站| 久久人人爽人人爽爽久久| 亚洲国产免费av| 久久久精品免费视频| 日韩在线视频国产| 亚洲国产成人久久综合| 色与欲影视天天看综合网| 欧美成人午夜剧场免费观看| 亚洲欧洲第一视频| 国产美女扒开尿口久久久| 2019中文字幕在线观看| 精品视频在线播放色网色视频| 高清欧美性猛交xxxx| 日韩欧美高清在线视频| 成人动漫网站在线观看| 亚洲精品二三区| 成人中文字幕+乱码+中文字幕| 亚洲自拍高清视频网站| 一本久久综合亚洲鲁鲁| 国产精品高潮呻吟久久av无限| 欧美国产日韩xxxxx| 中文字幕日韩精品在线观看| 欧美日韩中文字幕| 国产精品自产拍在线观看中文| 91香蕉国产在线观看| 欧美激情xxxxx| 亚洲乱亚洲乱妇无码| 精品在线欧美视频| 91国在线精品国内播放| 色婷婷亚洲mv天堂mv在影片| 国外成人在线直播| 国产精品av网站| 欧美日韩午夜激情| 欧美激情亚洲激情| 亚洲国产另类 国产精品国产免费| 81精品国产乱码久久久久久| 日韩美女写真福利在线观看| 一级做a爰片久久毛片美女图片| 精品视频www| 国产香蕉精品视频一区二区三区| 久久人人爽国产| 98精品在线视频| 日日摸夜夜添一区| 国产精品夫妻激情| 亚洲第一网站免费视频| 亚洲**2019国产| 国产精品直播网红| 欧美中文字幕视频在线观看| 国产午夜精品全部视频播放| 成人精品久久久| 国产拍精品一二三| 色噜噜狠狠狠综合曰曰曰88av| 久久99热精品这里久久精品| 成人自拍性视频| 国产欧美日韩精品丝袜高跟鞋| 精品一区二区亚洲| 91香蕉亚洲精品| 国产精品视频成人| 亚洲福利在线播放| 久久国产精品99国产精| 国产精品va在线| 欧美野外猛男的大粗鳮| 国产精品高潮呻吟视频| 国产精品久久久久久久久久小说| 欧美日韩成人免费| 亚洲自拍在线观看| 国产免费一区二区三区在线能观看| 亚洲三级av在线| 97人人模人人爽人人喊中文字| 日韩经典第一页| 国产成人高潮免费观看精品| 91啪国产在线| 91精品视频大全| 久久久午夜视频| 日韩视频免费看| 欧美在线一区二区三区四| 国产精品久久久久久久美男| 日韩美女激情视频| 久久久精品电影| 亚洲爱爱爱爱爱| 亚洲石原莉奈一区二区在线观看| 久久精品国产v日韩v亚洲| 91wwwcom在线观看| 亚洲理论电影网| 亚洲香蕉伊综合在人在线视看| 成人a级免费视频| 久久视频精品在线| 亚洲国产精品成人av| 欧美激情视频在线免费观看 欧美视频免费一| 中文字幕综合在线| 欧美日韩国产在线播放|