前端與算法

做者:Jogis
原文連接:https://github.com/yesvods/Bl...
轉載請註明原文連接以及做者信息javascript

前言

最近舉行了一場盛大的前端算法大比拼,題目從真實業務場景中抽取出來,童鞋們紛紛摩拳擦掌展現本身算法基本功。題目以下:前端

真實場景裏面,有7M左右的JSON數據須要統一更新費率,聽說一開始處理這堆數據一次就得耗費20+秒。在瀏覽器場景下,這意味着這段時間UI渲染被阻塞,用戶交互徹底無響應。最後通過調整的算法,也須要1秒左右的執行時間,很是影響用戶體驗。java

略懂瀏覽器動畫的童鞋都知道,在瀏覽器一幀裏面layout、合成、渲染佔據了很多CPU時間,真實交給js進行運行的時間只有不到10ms。在如此大數據量處理的場景下要保持絲般順滑的用戶體驗,算法必不可少,可見算法對於前端依舊很是重要。node

鄙人也參加了大比拼,分享一下本身的小當心得,總結一下如何將7M數據處理從1000ms降到10ms如下。git

基本思路

從題目的數據結構能夠看到,這是一個多叉樹,第一時間聯想到的是樹的遍歷。
借鑑函數式編程思想,樹的處理只須要三個步驟:github

  1. 函數遞歸遍歷算法

  2. 使用processor處理每個樹節點編程

  3. 葛優躺...數組

    Talk is cheap, show me the code.

    樹的遍歷:瀏覽器

function trav(tree, processor){
  if(!tree.children) return;
  for(var i in tree.children){
    let node = tree.children[i];
    processor(node);
    if(item.children){
      trav(item, process)
    }
  }
}

處理器:

function processor(node){
    //...預處理
    let values = node.rate.split('_');
    values[0] = '3';
    values[1] = '5';
    node.rate = values.join('_');
}

好,大功告成,跑一下。。。43ms??!

不科學!這在瀏覽器特喵的已經卡了一會了。

優化思路

確定哪裏有問題,先看一下樹遍歷。

result: 3ms

唔..只用了3ms,對於大量數據遍歷這個時間也說得過去,不是性能瓶頸。

那就只有處理器出問題了,細看一下:

// node.rate.split('_')
result 10ms+

// values[0] = '3';
// values[1] = '5';
result 10ms+

// values.join('_');
result 10ms+

出乎意料,在大量重複調用狀況下,就算是一個普通的方法也會產生大量性能損耗。你們應該也據說過字符串處理是特別費性能的,處理不當就會產生很多問題。

從上面的運行能夠看出,不管是字符串的分離或者合併,仍是數組的賦值都會致使性能損耗。平時這麼說早被人打死了,什麼性能損耗,能跑就行。在真正性能瓶頸上,這些細節尤其關鍵。

字符串處理

實際上,咱們只是須要根據現有費率+要修改費率組成出一個新費率。咱們能夠把這些操做作成

  • 對原字符串的讀取

  • 對修改費率的讀取

  • 字符串合併

把屢次寫、賦值操做,改爲一次低性能損耗的字符串合併。

好好好,大家要的code
//讀取
function getValue(pos, raw, position, resMap){
  if(position.indexOf(pos) === -1) return raw.charAt(pos * 2);
  return resMap[pos];
}
//合併
function concat(raw, position, resMap){
  let str = '';
  str = str+getValue(0, raw, position, resMap)+'-'+getValue(1, raw, position, resMap)+'-'+getValue(2, raw, position, resMap);
  return str;
}

因而..最終的處理器代碼應該是醬紫的:

trav(this.data, item => {
    if(!item.rate) item.rate = '0_0_0';
    item.rate = concat(item.rate, position, resMap);
});

最終的最佳跑分結果是:

result: 6.666..ms

題內話

在處理字符串合併時候依然須要注意的是,不一樣的合併方式,系統調度是不同的。

//產生3次變量調度, tmpVal = 'hehe', tmpVal2 = val1 + 'hehe', tmpVal3 = tmpVal2 + val2;
let str = val1 + ' hehe ' + val2 ;

//產生1次變量調度, tmpVal = 'hehe', tmpVal +=val1, tmpVal +=val2
let str = ' hehe ' + val1 + val2
相關文章
相關標籤/搜索