日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

惰性求值——lodash源码解读

發布時間:2025/3/17 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 惰性求值——lodash源码解读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

lodash受歡迎的一個原因,是其優異的計算性能。而其性能能有這么突出的表現,很大部分就來源于其使用的算法——惰性求值。
本文將講述lodash源碼中,惰性求值的原理和實現。

一、惰性求值的原理分析

惰性求值(Lazy Evaluation),又譯為惰性計算、懶惰求值,也稱為傳需求調用(call-by-need),是計算機編程中的一個概念,它的目的是要最小化計算機要做的工作
惰性求值中的參數直到需要時才會進行計算。這種程序實際上是從末尾開始反向執行的。它會判斷自己需要返回什么,并繼續向后執行來確定要這樣做需要哪些值。

以下是How to Speed Up Lo-Dash ×100? Introducing Lazy Evaluation.(如何提升Lo-Dash百倍算力?惰性計算的簡介)文中的示例,形象地展示惰性求值。

function priceLt(x) {return function(item) { return item.price < x; }; } var gems = [{ name: 'Sunstone', price: 4 },{ name: 'Amethyst', price: 15 },{ name: 'Prehnite', price: 20},{ name: 'Sugilite', price: 7 },{ name: 'Diopside', price: 3 },{ name: 'Feldspar', price: 13 },{ name: 'Dioptase', price: 2 },{ name: 'Sapphire', price: 20 } ];var chosen = _(gems).filter(priceLt(10)).take(3).value();

程序的目的,是對數據集gems進行篩選,選出3個price小于10的數據。

1.1 一般的做法

如果拋開lodash這個工具庫,讓你用普通的方式實現var chosen = _(gems).filter(priceLt(10)).take(3);那么,可以用以下方式:
_(gems)拿到數據集,緩存起來。
再執行filter方法,遍歷gems數組(長度為10),取出符合條件的數據:

[{ name: 'Sunstone', price: 4 },{ name: 'Sugilite', price: 7 },{ name: 'Diopside', price: 3 },{ name: 'Dioptase', price: 2 } ]

然后,執行take方法,提取前3個數據。

[{ name: 'Sunstone', price: 4 },{ name: 'Sugilite', price: 7 },{ name: 'Diopside', price: 3 } ]

總共遍歷的次數為:10+3。
執行的示例圖如下:

1.2 惰性求值做法

普通的做法存在一個問題:每個方法各做各的事,沒有協調起來浪費了很多資源。
如果能先把要做的事,用小本本記下來?,然后等到真正要出數據時,再用最少的次數達到目的,豈不是更好。
惰性計算就是這么做的。
以下是實現的思路:

  • _(gems)拿到數據集,緩存起來
  • 遇到filter方法,先記下來
  • 遇到take方法,先記下來
  • 遇到value方法,說明時機到了
  • 把小本本拿出來,看下要求:要取出3個數,price<10
  • 使用filter方法里的判斷方法priceLt對數據進行逐個裁決
[{ name: 'Sunstone', price: 4 }, => priceLt裁決 => 符合要求,通過 => 拿到1個{ name: 'Amethyst', price: 15 }, => priceLt裁決 => 不符合要求{ name: 'Prehnite', price: 20}, => priceLt裁決 => 不符合要求{ name: 'Sugilite', price: 7 }, => priceLt裁決 => 符合要求,通過 => 拿到2個{ name: 'Diopside', price: 3 }, => priceLt裁決 => 符合要求,通過 => 拿到3個 => 夠了,收工!{ name: 'Feldspar', price: 13 },{ name: 'Dioptase', price: 2 },{ name: 'Sapphire', price: 20 } ]

如上所示,一共只執行了5次,就把結果拿到。
執行的示例圖如下:

1.3 小結

從上面的例子可以得到惰性計算的特點:

  • 延遲計算,把要做的計算先緩存,不執行
  • 數據管道,逐個數據通過“裁決”方法,在這個類似安檢的過程中,進行過關的操作,最后只留下符合要求的數據
  • 觸發時機,方法緩存,那么就需要一個方法來觸發執行。lodash就是使用value方法,通知真正開始計算

二、惰性求值的實現

依據上述的特點,我將lodash的惰性求值實現進行抽離為以下幾個部分:

2.1 實現延遲計算的緩存

實現_(gems)。我這里為了語義明確,采用lazy(gems)代替。

var MAX_ARRAY_LENGTH = 4294967295; // 最大的數組長度// 緩存數據結構體 function LazyWrapper(value){this.__wrapped__ = value;this.__iteratees__ = [];this.__takeCount__ = MAX_ARRAY_LENGTH; }// 惰性求值的入口 function lazy(value){return new LazyWrapper(value); }
  • this.__wrapped__ 緩存數據
  • this.__iteratees__ 緩存數據管道中進行“裁決”的方法
  • this.__takeCount__ 記錄需要拿的符合要求的數據集個數

這樣,一個基本的結構就完成了。

2.2 實現filter方法

var LAZY_FILTER_FLAG = 1; // filter方法的標記// 根據 篩選方法iteratee 篩選數據 function filter(iteratee){this.__iteratees__.push({'iteratee': iteratee,'type': LAZY_FILTER_FLAG});return this; }// 綁定方法到原型鏈上 LazyWrapper.prototype.filter = filter;

filter方法,將裁決方法iteratee緩存起來。這里有一個重要的點,就是需要記錄iteratee的類型type。
因為在lodash中,還有map等篩選數據的方法,也是會傳入一個裁決方法iteratee。由于filter方法和map方法篩選方式不同,所以要用type進行標記。
這里還有一個技巧:

(function(){// 私有方法function filter(iteratee){/* code */}// 綁定方法到原型鏈上LazyWrapper.prototype.filter = filter; })();

原型上的方法,先用普通的函數聲明,然后再綁定到原型上。如果工具內部需要使用filter,則使用聲明好的私有方法。
這樣的好處是,外部如果改變LazyWrapper.prototype.filter,對工具內部,是沒有任何影響的。

2.3 實現take方法

// 截取n個數據 function take(n){this.__takeCount__ = n;return this; };LazyWrapper.prototype.take = take;

2.4 實現value方法

// 惰性求值 function lazyValue(){var array = this.__wrapped__;var length = array.length;var resIndex = 0;var takeCount = this.__takeCount__;var iteratees = this.__iteratees__;var iterLength = iteratees.length;var index = -1;var dir = 1;var result = [];// 標簽語句outer:while(length-- && resIndex < takeCount){// 外層循環待處理的數組index += dir;var iterIndex = -1;var value = array[index];while(++iterIndex < iterLength){// 內層循環處理鏈上的方法var data = iteratees[iterIndex];var iteratee = data.iteratee;var type = data.type;var computed = iteratee(value);// 處理數據不符合要求的情況if(!computed){if(type == LAZY_FILTER_FLAG){continue outer;}else{break outer;}}}// 經過內層循環,符合要求的數據result[resIndex++] = value;}return result; }LazyWrapper.prototype.value = lazyValue;

這里的一個重點就是:標簽語句

outer:while(length-- && resIndex < takeCount){// 外層循環待處理的數組index += dir;var iterIndex = -1;var value = array[index];while(++iterIndex < iterLength){// 內層循環處理鏈上的方法var data = iteratees[iterIndex];var iteratee = data.iteratee;var type = data.type;var computed = iteratee(value);// 處理數據不符合要求的情況if(!computed){if(type == LAZY_FILTER_FLAG){continue outer;}else{break outer;}}}// 經過內層循環,符合要求的數據result[resIndex++] = value;}

當前方法的數據管道實現,其實就是內層的while循環。通過取出緩存在iteratees中的裁決方法取出,對當前數據value進行裁決。
如果裁決結果是不符合,也即為false。那么這個時候,就沒必要用后續的裁決方法進行判斷了。而是應該跳出當前循環。
而如果用break跳出內層循環后,外層循環中的result[resIndex++] = value;還是會被執行,這是我們不希望看到的。
應該一次性跳出內外兩層循環,并且繼續外層循環,才是正確的。
標簽語句,剛好可以滿足這個要求。

2.5 小檢測

var testArr = [1, 19, 30, 2, 12, 5, 28, 4];lazy(testArr).filter(function(x){console.log('check x='+x);return x < 10}).take(2).value();// 輸出如下: check x=1 check x=19 check x=30 check x=2// 得到結果: [1, 2]

2.6 小結

整個惰性求值的實現,重點還是在數據管道這塊。以及,標簽語句在這里的妙用。其實實現的方式,不只當前這種。但是,要點還是前面講到的三個。掌握精髓,變通就很容易了。

結語

惰性求值,是我在閱讀lodash源碼中,發現的最大閃光點。
當初對惰性求值不甚理解,想看下javascript的實現,但網上也只找到上文提到的一篇文獻。
那剩下的選擇,就是對lodash進行剖離分析。也因為這,才有本文的誕生。
希望這篇文章能對你有所幫助。如果可以的話,給個star :)

最后,附上本文實現的簡易版lazy.js完整源碼:
https://github.com/wall-wxk/blogDemo/blob/master/lodash/lazy.js


喜歡我文章的朋友,可以通過以下方式關注我:

  • 「star」「watch」 我的GitHub blog
  • RSS訂閱我的個人博客:王先生的基地

總結

以上是生活随笔為你收集整理的惰性求值——lodash源码解读的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 视频精品一区二区 | 日本欧美色| 91尤物视频 | 对白刺激国产子与伦 | 日本韩国免费观看 | 美女隐私无遮挡网站 | 巨茎人妖videos另类 | 午夜久久一区 | 亚洲视频一二 | 97色干| 奇米影视9999 | 亚色在线| 中国肥胖女人真人毛片 | 久久久夜色精品亚洲 | 全肉的吸乳文 | 好吊色这里只有精品 | 亚洲欧美日韩成人在线 | 男生裸体视频 | 国产视频二区三区 | 中国精品视频 | 亚洲香蕉在线观看 | 深田咏美中文字幕 | av中字在线 | 伊人99在线 | 亚洲二区视频 | 欧美性啪啪 | 深夜在线网站 | 日本在线免费观看视频 | 激情二区 | 日韩激情在线播放 | 国产成人精品一区二区三区 | 国产午夜精品一区二区三区欧美 | 青青青免费视频观看在线 | 免费无码国产精品 | 精品国产欧美日韩 | 国产鲁鲁视频在线观看免费 | 久草视频中文在线 | 国产6区 | 成人黄色片在线观看 | 中文在线不卡视频 | 北条麻妃久久精品 | 9999av| 欧美午夜精品久久久久免费视 | 欧美成人一区二区三区片免费 | 激情视频亚洲 | 亚洲综合色成人 | 空姐毛片 | 91丝袜呻吟高潮美腿白嫩 | 成人一级片视频 | 日韩久久一区 | 自由成熟xxxx色视频 | 亚洲性视频网站 | 最新国产视频 | 人妻一区二区三 | 91精品免费看 | 好色先生tv官网 | 欧美黑人又粗又大的性格特点 | 一本无码aⅴ久久久国产 | 极品白嫩的小少妇 | 欧美在线精品一区二区三区 | 青娱乐导航| 国产精品av在线 | 啪啪网视频| 综合婷婷 | 国产美女无遮挡网站 | 黄色三级视频网站 | 久久国产露脸精品国产 | a∨鲁丝一区鲁丝二区鲁丝三区 | 神马午夜伦理 | 国内精品在线观看视频 | 免费日本黄色片 | 韩国一区二区三区四区 | 呦呦av| 国产欧美日韩三级 | 中文字幕资源网 | 天堂综合网 | 嫩草影院在线观看视频 | 国产观看| 色播网址| 色噜噜狠狠狠综合曰曰曰88av | 久久久久亚洲av无码专区桃色 | 欧美伊人| 亚洲综合在线成人 | 强乱中文字幕av一区乱码 | 在线播放无码后入内射少妇 | 欧美成人免费在线视频 | 亚洲欧美变态另类丝袜第一区 | 嫩草在线观看 | 国产电影免费观看高清完整版视频 | 色播视频在线观看 | 性少妇mdms丰满hdfilm | 99riav视频| 欧美高清精品一区二区 | 欧美乱论| 日本在线视频不卡 | av男人资源 | 国产精品一级二级三级 | 美女xx网站 | 亚洲欧美一区二区在线观看 |