Pertanyaan v8 implikasi kinerja JavaScript dari const, let, dan var?


Terlepas dari perbedaan fungsional, apakah menggunakan kata kunci 'let' dan 'const' baru memiliki dampak umum atau spesifik pada kinerja relatif terhadap 'var'?

Setelah menjalankan program:

function timeit(f, N, S) {
    var start, timeTaken;
    var stats = {min: 1e50, max: 0, N: 0, sum: 0, sqsum: 0};
    var i;
    for (i = 0; i < S; ++i) {
        start = Date.now();
        f(N);
        timeTaken = Date.now() - start;

        stats.min = Math.min(timeTaken, stats.min);
        stats.max = Math.max(timeTaken, stats.max);
        stats.sum += timeTaken;
        stats.sqsum += timeTaken * timeTaken;
        stats.N++
    }

    var mean = stats.sum / stats.N;
    var sqmean = stats.sqsum / stats.N;

    return {min: stats.min, max: stats.max, mean: mean, spread: Math.sqrt(sqmean - mean * mean)};
}

var variable1 = 10;
var variable2 = 10;
var variable3 = 10;
var variable4 = 10;
var variable5 = 10;
var variable6 = 10;
var variable7 = 10;
var variable8 = 10;
var variable9 = 10;
var variable10 = 10;

function varAccess(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += variable1;
        sum += variable2;
        sum += variable3;
        sum += variable4;
        sum += variable5;
        sum += variable6;
        sum += variable7;
        sum += variable8;
        sum += variable9;
        sum += variable10;
    }
    return sum;
}

const constant1 = 10;
const constant2 = 10;
const constant3 = 10;
const constant4 = 10;
const constant5 = 10;
const constant6 = 10;
const constant7 = 10;
const constant8 = 10;
const constant9 = 10;
const constant10 = 10;

function constAccess(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += constant1;
        sum += constant2;
        sum += constant3;
        sum += constant4;
        sum += constant5;
        sum += constant6;
        sum += constant7;
        sum += constant8;
        sum += constant9;
        sum += constant10;
    }
    return sum;
}


function control(N) {
    var i, sum;
    for (i = 0; i < N; ++i) {
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
        sum += 10;
    }
    return sum;
}

console.log("ctl = " + JSON.stringify(timeit(control, 10000000, 50)));
console.log("con = " + JSON.stringify(timeit(constAccess, 10000000, 50)));
console.log("var = " + JSON.stringify(timeit(varAccess, 10000000, 50)));

.. Hasil saya adalah sebagai berikut:

ctl = {"min":101,"max":117,"mean":108.34,"spread":4.145407097016924}
con = {"min":107,"max":572,"mean":435.7,"spread":169.4998820058587}
var = {"min":103,"max":608,"mean":439.82,"spread":176.44417700791374}

Namun diskusi sebagaimana dicatat di sini tampaknya menunjukkan potensi nyata untuk perbedaan kinerja di bawah skenario tertentu: https://esdiscuss.org/topic/performance-concern-with-let-const


32
2017-10-16 13:12


asal


Jawaban:


TL; DR

Dalam teori, versi yang tidak dioptimalkan dari loop ini:

for (let i = 0; i < 500; ++i) {
    doSomethingWith(i);
}

akan lebih lambat daripada versi yang tidak dioptimalkan dari loop yang sama dengan var:

for (var i = 0; i < 500; ++i) {
    doSomethingWith(i);
}

karena a berbeda  i variabel dibuat untuk setiap iterasi pengulangan dengan let, sedangkan hanya ada satu i dengan var.

Dalam praktek, di sini di 2018, V8 cukup introspeksi loop untuk mengetahui kapan dapat mengoptimalkan perbedaan itu. (Bahkan sebelum itu, kemungkinan besar loop Anda sudah cukup melakukan pekerjaan tambahan itu letNamun, overhead yang terkait pun tersapu bersih. Tapi sekarang kamu bahkan tidak perlu khawatir tentang itu.)

Detail

Perbedaan penting antara var dan let di sebuah for loop adalah hal yang berbeda i dibuat untuk setiap iterasi; ini membahas masalah klasik "penutupan dalam lingkaran":

function usingVar() {
  for (var i = 0; i < 3; ++i) {
    setTimeout(function() {
      console.log("var's i: " + i);
    }, 0);
  }
}
function usingLet() {
  for (let i = 0; i < 3; ++i) {
    setTimeout(function() {
      console.log("let's i: " + i);
    }, 0);
  }
}
usingVar();
setTimeout(usingLet, 20);

Membuat EnvironmentRecord baru untuk setiap loop body (tautan spesifikasi) adalah pekerjaan, dan pekerjaan membutuhkan waktu, itulah sebabnya dalam teori let versi lebih lambat daripada versi var versi.

Tetapi perbedaan hanya masalah jika Anda membuat fungsi (penutupan) dalam loop yang menggunakan i, seperti yang saya lakukan dalam contoh cuplikan runnable di atas. Jika tidak, perbedaan tidak dapat diamati dan dapat dioptimalkan.

Di sini di 2018, sepertinya V8 (dan SpiderMonkey di Firefox) melakukan introspeksi yang cukup bahwa tidak ada biaya kinerja dalam satu lingkaran yang tidak memanfaatkan letsemantik variabel per iterasi. Lihat tes jsPerf ini.


Dalam beberapa kasus, const mungkin memberikan peluang untuk pengoptimalan itu var tidak akan, terutama untuk variabel global.

Masalah dengan variabel global adalah bahwa, baik, global; apa saja kode di mana saja bisa mengaksesnya. Jadi jika Anda mendeklarasikan variabel dengan var bahwa Anda tidak pernah berniat untuk mengubah (dan tidak pernah melakukan perubahan dalam kode Anda), mesin tidak dapat menganggap itu tidak akan pernah berubah karena hasil dari kode dimuat nanti atau serupa.

Dengan constNamun, Anda secara eksplisit mengatakan kepada mesin bahwa nilai tidak dapat berubah¹. Jadi, gratis untuk melakukan pengoptimalan apa pun yang diinginkan, termasuk memancarkan literal, bukan referensi variabel untuk kode yang menggunakannya, karena mengetahui bahwa nilai tidak dapat diubah.

¹ Ingat bahwa dengan objek, nilainya adalah a referensi ke objek, bukan objek itu sendiri. Jadi dengan const o = {}, Anda bisa mengubah keadaan objek (o.answer = 42), tetapi Anda tidak bisa membuatnya o arahkan ke objek baru (karena itu akan membutuhkan mengubah referensi objek yang dikandungnya).


Ketika menggunakan let atau const di lain var-seperti situasi, mereka tidak memiliki kinerja yang berbeda. Fungsi ini harus memiliki kinerja yang sama persis baik yang Anda gunakan var atau let, contohnya:

function foo() {
    var i = 0;
    while (Math.random() < 0.5) {
        ++i;
    }
    return i;
}

Ini semua, tentu saja, tidak mungkin penting dan sesuatu yang perlu dikhawatirkan hanya jika dan ketika ada masalah nyata untuk dipecahkan.


38
2017-10-16 13:16