先端性能最適化(四)okcoinオファー密度性能最適化及び作業機会推奨(純javascript高周波データ処理性能最適化)


前言
まず私の近況を説明します.もう入社しました.入社したばかりです.アリババ技術専門家の銘承(社長)に感謝します.歩くのは慌ただしくて、多くのアリさんのクラスメートは挨拶に間に合いませんでした.幸い、私は今でも釘付けを見ています.釘付けにしてもいいです.また昇進シーズンになりました.以下はこのテーマに入ります.この文章は「純javascript高周波データ処理性能最適化」といいます.
背景の紹介
オファー密度は各段のオファーの数量を展示するために使用されます.ブラウザ側でマージを行う必要があります.例えば、2.9511の数量は1.0200で、2.9520の価格は1.0333で、二桁の小数点以下の合併によって、売り相場なら、合わせて2.9600の価格をオファーします.どのような精度でユーザーを統合するかは自分で選択できます.特に取引が活発なため、プッシュが頻繁で、ブラウザ側で大量の計算をする必要があります.直接の結果はCPUが非常に高いです.
最適化
前に、最適化された記事を読み込み、リンクを書きました. 小姜哥:先端性能最適化(一)図でロード最適化を説明します. , 
@i 5 ting
 狼おじさんは見た後、業務整理がもっと重要だと言いました.確かにこのようにしています.今回は確かに多くの業務整理の最適化をしました.原則はもちろん計算しないで計算しないことができます.例えばサイクル外で確定できる値はサイクル内で計算しないでください.例えばオファーは20段を表示しています.計算したデータが十分に表示されている時は計算しないでください.
 
シーンが特殊なため、今回の純技術の角度の最適化による収益も非常に多く、業務整理を超える可能性もあります.
一般的にブラウザの端末プログラムの性能問題はDOM操作と関係があります.純粋なjavascriptに深刻な性能問題が発生するのはまれです.私は今までに二回も会ったことがあります.初めては大知で相場を示して、頻繁に送ります.回目は今回のオッケーの見積り密度で、頻繁にプッシュして送ります.本論文は主にいくつかの純技術面の最適化点を説明します.いくつかは今回作ったもので、まだやっていないものもあります.最適化は無限で、一歩ずつやってきます.
1.try catchの性能
例を先に見る
// === try catch
var start = window.performance.now()
for (var i = 0, b = ''; i < 500000; i++) {
    var a = b + i;
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, b = ''; i < 500000; i++) {
    try {
        var a = b + i;
    } catch (e) {

    }
}
var end = window.performance.now()
console.log(end - start)

//     
37.59999999991851
58.79999999998836
テストの結果から見ると、try catchは確かに遅いですが、ゆっくりとスペクトルを離れないと、倍も遅くなりません.
もう一つの例を見に来ます.
// === try catch
var start = window.performance.now()
for (var i = 0, b = ''; i < 500000; i++) {
    var a;
    a = (i.toString().split('.')[1] || '').length;
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, b = ''; i < 500000; i++) {
    var a;
    try {
        a = i.toString().split('.')[1].length;
    } catch (e) {
        a = 0;
    }
}
var end = window.performance.now()
console.log(end - start)

//     
148.00000000011642
3314.400000000256
驚いたでしょう.20倍も遅くなりました.だから結論を出します.try catchは慎重に使ってください.もしプログラムの丈夫さをtry catchで解決しないでください.
これも今回の最適化されたプリクラであり、以前のプログラムの加減乗除はそれぞれ2つのtryを使って計算された小数位の処理をしていました.多くはcatchの分岐に行きましたが、各データの処理は数回の加減乗除演算に関わり、時間がかかります.
2.withの性能
コードを先に見ます
// === with
var arr = [];
for (var i = 0; i < 50000; i++) {
    arr.push('' + Math.random() * 100000)
}
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = Math.max(i, arr[i]) 
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    with (Math) {
        value = max(i, arr[i]) 
    }   
}
var end = window.performance.now()
console.log(end - start)

//     
13.10000000000582
60.20000000001164
性能差四五倍、withというものは本当に使えません.ベストプラクティスはとっくにwithを否定しています.
3.小数の精度を計算する
コードを先に見ます
// ===       
var arr = [];
for (var i = 0; i < 50000; i++) {
    arr.push('' + Math.random() * 100000)
}
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = arr[i]                    
    var index = value.indexOf('.');
    var len = 0;
    if (index > -1) {
        len = value.length - 1 - index;
    }    
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = arr[i]                    
    var index = value.indexOf('.');
    var len = 0;
    if (index > -1) {
        len = value.split('.')[1].length;
    }    
}
var end = window.performance.now()
console.log(end - start)

//     
3.5000000009313226
20.00000000046566
テストの結果から見て、スプリットの実現方法は5、6倍遅くて、よく分かります.この例に対して、スプリットは2つの文字列と1つの配列を多く作成します.これも今回の最適化のポイントの一つであり、前述のように小数の精度を計算する際にはtry catchを使用しているので、今回の最適化は小数の計算精度においては従来の数十倍から百倍以上に向上しました.
4.小数点のある文字列を整数と小数に分割する
コードを先に見ます
// === slice vs split
var arr = [];
for (var i = 0; i < 500000; i++) {
    arr.push('' + Math.random() * 100000)
}
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = arr[i]                    
    var index = value.indexOf('.');
    var a = value.slice(0, index)
    var b = value.slice(index + 1)   
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = arr[i]                
    var array = value.split('.')
    var a = array[0]
    var a = array[1]   
}
var end = window.performance.now()
console.log(end - start)

//     
47.8000000002794
146.8000000002794
結果から見て、sliceはsplitより優勢があります.道理は操作のメモリ空間が違います.今回は最適化していません.今回の最適化は主に何倍の性能向上がある点に対して行われます.
5.Cookieの操作
// === Cookie
var start = window.performance.now()
var cookie = document.cookie
for (var i = 0, value; i < 5000; i++) {
    value = cookie;
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, value; i < 5000; i++) {
    value = document.cookie;
}
var end = window.performance.now()
console.log(end - start)

//     
0.7999999997991836
623.7999999993917
また驚いたでしょう.cookieを読むのはこんなに遅くて、七、百倍で、これは5000回の結果です.cookieを読む時はハードディスクと関係があります.私はssdです.機械のハードディスクはもっと遅いかもしれません.この例は、Dcument.co okieをテストしただけで、実際の操作は;に従ってsplitをすることにも関連しています.その後、=に従ってスプリットを繰り返します.前にも述べたように、split性能は優れていません.
したがって、cookieを読み取る正確な姿勢は、変更しにくいクッキーを一回だけ読み込むと、変数でキャッシュし、容易に変更できる更新機構を作ることです.これも今回の最適化のポイントです.以前は毎回のデータ更新でクッキーを読んでいましたが、前に述べたように、データのプッシュがとても頻繁でした.
6.数字を文字列に変換する
結論から言えば、これは差がないと言えます.回転しないなら回転しないで、少なく回れば少なくなります.
// === toString vs plus
var arr = [];
for (var i = 0; i < 500000; i++) {
    arr.push(Math.random() * 100000)
}
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = arr[i].toString()                  
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = '' + arr[i]
}
var end = window.performance.now()
console.log(end - start)

//     
144.80000000004657 
148.19999999948777
7.文字列を数字に変換し、new Num br vs Number
// === new Number vs Number
var arr = [];
for (var i = 0; i < 500000; i++) {
    arr.push('' + Math.random() * 100000)
}
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = new Number(arr[i]) - new Number('1')                 
}
var end = window.performance.now()
console.log(end - start)
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = Number(arr[i]) - Number('1');
}
var end = window.performance.now()
console.log(end - start)

//     
129
74.40000000060536
発見するかどうかは違っていますが、一番いい実践は正しいです.
8.new Arayと配列の字面量
// === new Array vs []
var arr = [];
for (var i = 0; i < 500000; i++) {
    arr.push('' + Math.random() * 100000)
}
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = [];               
}
var end = window.performance.now()
console.log(end - start)
var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = new Array()
}
var end = window.performance.now()
console.log(end - start)

//      
16.199999999953434
20.199999999953434
ベストプラクティスは文字の量を使うのは道理があると教えてくれますよね.
9.0ビットでどうやって0を生成しますか?
// ===     0 VS slice
var arr = [];
for (var i = 0; i < 50000; i++) {
    arr.push('' + Math.random() * 100000)
}

var start = window.performance.now()
var zero20 = '000000000000000';
for (var i = 0, value; i < arr.length; i++) {
    value = zero20.slice(0, 4)    
}
var end = window.performance.now()
console.log(end - start)

var start = window.performance.now()
for (var i = 0, value; i < arr.length; i++) {
    value = '';
    for (var j = 0 ; j < 4; j++) {
        value += '0';
    }
}
var end = window.performance.now()
console.log(end - start)

//     
3.3000000003085006
9.599999999409192
その結果、sliceには大きなメリットがあるということが分かりました.これも今回のことです.私たちは表示する時に0の位置を補う操作をしなければならないことを知っています.
10.上へ下への切り込み
この対比は貼り出さないで、前のコードは長すぎて、下の方は新しく実現したバージョンの下に切断して、テストしてもとのバージョンの性能より7倍ぐらい良いです.上へのカットが似ています.
var zero20 = '00000000000000000000';
//     (        )
function floorTruncation(number, len) {
    number = '' + number;
    var index = number.indexOf('.');
    var precision = index > -1 ? number.length - 1 - index : 0;
    if (precision == len) {
        //            
        return number;
    } else if (precision == 0 || len == 0) { 
        //      ,        。         0  toFixed    。
        return (+number).toFixed(len)
    }
    //      
    return (number + zero20).slice(0, index + 1 + len);
}
その他
他にもいくつかの点があります.この文章は一つ一つ列挙しないで、後でまた書く機会があります.
結論
実は上で言ったこれらの点はそれぞれ取り出して単独で実行するのがとても速いです.異なる実装間の違いはもちろんマイクロ秒レベルである.しかし、実行回数が大きい場合には差が出てきます.
重点を置く
前の時間は相対的に不安定で、多くの人が私を助けてくれました.こちらの文章を借りて彼らに感謝しています.
社長の銘承に感謝します.
クッキーの美女HRさん達に感謝します.
元社長の倪欧さんに感謝します.
狼おじさんに新しい観点をたくさんくれてありがとうございます.
前の会社の元社長たちと仲間たちに感謝します.
新浪微博の氷兄さんと呉先生に感謝します.
私はアメリカ団に入る機会を与えてくれました.美団の美女HRさんにも感謝しています.美団は本当に素晴らしいです.
彭さん、ありがとうございます
唐兄さんに感謝します
良い兄弟と友達に感謝します.
仕事の機会を紹介してくれてありがとうございます.ほとんど見に行きませんでしたが.
第二波重点
仕事を探しているなら、直接採用部門のリーダーに紹介します.紹介できる会社はok coin、新浪微博、美団、アリ大娯楽、チーター、速手、滴滴、初条などがあります.履歴書を私のメールに送ってください.  [email protected] ,自分の基本情報と行きたい会社を明記してください.また、私はWeChat lw 2017313を追加してもいいです.仕事が忙しくて、必ず返信するとは保証できません.履歴書をWeChatに送ってはいけません.ご了承ください.
終了
最後に、皆さんの仕事が順調でありますように、高性能コードを書いてください.
この文章には何か手落ちがあります.ご指摘を歓迎します.
どのような最適化点がありますか?教えてください.もしカラオケに来たら一緒に仕事をするのは素晴らしいです.履歴書を送ってください.