const、let 和 var 对 v8 JavaScript 性能的影响?

2023-11-26

无论功能差异如何,使用新关键字“let”和“const”相对于“var”是否会对性能产生任何普遍或特定的影响?

运行程序后:

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)));

..我的结果如下:

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}

然而,此处提到的讨论似乎表明在某些情况下确实存在性能差异的潜力:https://esdiscuss.org/topic/performance-concern-with-let-const


TL;DR

理论上,该循环的未优化版本:

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

可能比相同循环的未优化版本慢var:

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

因为一个不同的 i为每个循环迭代创建变量let,而只有一个i with var.

反对这一点事实是var被提升,因此它在循环之外声明,而let仅在循环内声明,这可能提供优化优势。

在实践中,在 2018 年,现代 JavaScript 引擎对循环进行了足够的内省,以了解何时可以优化该差异。 (甚至在那之前,你的循环很可能已经做了足够的工作,以至于额外的let无论如何,相关的开销都被消除了。但现在你甚至不必担心它。)

谨防综合基准因为它们非常容易出错,并以真实代码不会的方式触发 JavaScript 引擎优化器(无论好坏方式)。但是,如果您想要一个综合基准,这里有一个:

const now = typeof performance === "object" && performance.now
    ? performance.now.bind(performance)
    : Date.now.bind(Date);

const btn = document.getElementById("btn");
btn.addEventListener("click", function() {
    btn.disabled = true;
    runTest();
});

const maxTests = 100;
const loopLimit = 50000000;
const expectedX = 1249999975000000;

function runTest(index = 1, results = {usingVar: 0, usingLet: 0}) {
    console.log(`Running Test #${index} of ${maxTests}`);
    setTimeout(() => {
        const varTime = usingVar();
        const letTime = usingLet();
        results.usingVar += varTime;
        results.usingLet += letTime;
        console.log(`Test ${index}: var = ${varTime}ms, let = ${letTime}ms`);
        ++index;
        if (index <= maxTests) {
            setTimeout(() => runTest(index, results), 0);
        } else {
            console.log(`Average time with var: ${(results.usingVar / maxTests).toFixed(2)}ms`);
            console.log(`Average time with let: ${(results.usingLet / maxTests).toFixed(2)}ms`);
            btn.disabled = false;
        }
    }, 0);
}

function usingVar() {
    const start = now();
    let x = 0;
    for (var i = 0; i < loopLimit; i++) {
        x += i;
    }
    if (x !== expectedX) {
        throw new Error("Error in test");
    }
    return now() - start;
}

function usingLet() {
    const start = now();
    let x = 0;
    for (let i = 0; i < loopLimit; i++) {
        x += i;
    }
    if (x !== expectedX) {
        throw new Error("Error in test");
    }
    return now() - start;
}
<input id="btn" type="button" value="Start">

它表示,V8/Chrome 或 SpiderMonkey/Firefox 上的综合测试没有显着差异。 (在两种浏览器中进行重复测试,其中一个获胜,或者另一个获胜,并且在两种情况下都在误差范围内。)但同样,这是一个综合基准,而不是您的代码。当您的代码存在性能问题时,请担心代码的性能。

就风格而言,我更喜欢let如果我在闭包中使用循环变量,则可以获得范围优势和循环闭包优势。

Details

之间的重要区别var and let in a for循环是一个不同的i为每次迭代创建;它解决了经典的“循环闭包”问题:

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);

为每个循环体创建新的环境记录(规格链接)是工作,而工作需要时间,这就是为什么理论上let版本比之前慢var版本。

但只有当您在循环中创建一个使用以下函数(闭包)时,差异才重要i,就像我在上面的可运行代码片段示例中所做的那样。否则,无法观察到这种区别,并且可以通过优化消除这种区别。

在 2018 年,V8(以及 Firefox 中的 SpiderMonkey)似乎正在进行充分的自省,在不使用let的每次迭代变量语义。看这次测试.


在某些情况下,const很可能提供一个优化的机会var不会,特别是对于全局变量。

全局变量的问题在于它是全局的;any code anywhere可以访问它。所以如果你声明一个变量var如果您从不打算更改(并且从不在代码中进行更改),则引擎不能假设它永远不会因为稍后加载的代码或类似的结果而发生更改。

With const不过,您明确告诉引擎该值不能更改。因此,它可以自由地进行任何它想要的优化,包括发出文字而不是对使用它的代码的变量引用,因为知道这些值无法更改。

¹ 请记住,对于对象,其值是参考指向对象,而不是对象本身。所以与const o = {},您可以更改对象的状态(o.answer = 42),但你不能o指向一个新对象(因为这需要更改它包含的对象引用)。


使用时let or const其他var-类似的情况,他们不太可能有不同的表现。无论您使用该函数,该函数都应该具有完全相同的性能var or let, 例如:

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

当然,这一切都不太重要,只有当确实有问题需要解决时才需要担心。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

const、let 和 var 对 v8 JavaScript 性能的影响? 的相关文章

  • 类型错误:类扩展值未定义不是函数或 null

    尝试创建这些实体时出现以下错误 TypeError Class extends value undefined is not a function or null 我假设这与循环依赖有关 但是在使用表继承和一对多关系时应该如何避免这种情况
  • 如何让Gmail像加载进度条一样

    我想在页面的中心和顶部创建一个像 Gmail 一样的加载进度条 并适用于所有浏览器 这是基本代码
  • 在 R 传单中添加不透明度滑块

    如何在 R leaflet 应用程序中添加滑块来控制特定图层的不透明度 对于这个应用程序 我不想使用闪亮 这里建议 在 R 传单应用程序中添加滑块 https stackoverflow com questions 37682619 add
  • 如何立即启动setInterval循环? [复制]

    这个问题在这里已经有答案了 在一个简单的setInterval setInterval function Do something every 9 seconds 9000 第一个动作将在 9 秒后发生 t 9s 如何强制循环立即执行第一个
  • 设置双指缩放时精确的滚动位置

    我正在创建一个地图应用程序 它将标记图像放置在画布上并滚动到它 我正在使用浏览器的捏缩放和滚动来放大 缩小地图 然而 我注意到有一些奇怪的行为 我想知道如何解决它 这有点难以解释 但我们开始吧 假设您处于网页的标准缩放级别 无法进一步缩小
  • 此页面上的脚本导致 ie 运行缓慢

    问题就在标题中 IE 行为异常 并说有一个脚本运行缓慢 FF 和 Chrome 没有这个问题 我怎样才能找到问题所在 那个页面有很多JS 手动检查不是一个好主意 EDIT 这是我正在处理的一个项目的页面 但我需要一个工具来查找问题 End
  • API 使用令牌向 odoo 进行身份验证

    我想使用令牌从 Express 应用程序向 Odoo 进行身份验证 我在用odoo xmlrpc https www npmjs com package odoo xmlrpc连接 Odoo 的节点模块 我的快递应用程序 Odoo 要求 A
  • 访问 nuxt 配置文件中的存储

    我想添加通过 Nuxt 静态生成的动态路由 我定义了一个客户端 服务器端存储asyncData方法 我想将这个存储值 一个数组 映射到我的nuxt config js文件使其成为 动态 静态 路线图nuxt generate命令 但如何访问
  • mysql表中的数据非常大。即使 select 语句也需要很多时间

    我正在开发一个数据库 它是一个相当大的数据库 有 13 亿行和大约 35 列 这是我检查表状态后得到的结果 Name Table Name Engine InnoDB Version 10 Row format Compact Rows 1
  • 全局传递 xhr onload 函数的值

    在我正在创建的应用程序中 我有以下 XMLHttpRequest 并且我正在尝试传递结果data在 的里面xhr onload 到在同一父函数中创建的数组中 var url http api soundcloud com resolve j
  • 为什么在 JavaScript 中 if([]) 被验证而 [] == false ?

    if false alert empty array is false alert alert 0 if alert empty array is true 他们都会运行警报 Demo http jsfiddle net roine ZFD
  • 使用 JQuery 禁用和启用所有超链接

    我有以下禁用所有超链接的内容 但在事件发生后我想再次启用它们 我该如何执行此操作 a click function return false 我认为这不仅仅是将其设置为 true 那么简单 谢谢大家 不要以这种方式绑定 点击 处理程序 而是
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • 为什么我收到“在嵌套函数中通过 this 对类字段进行潜在无效的引用访问”错误

    在普通 JS 中 我的代码可以正常工作 对于这种情况 我想组件化我的Wall类应该在浏览器中显示用户上传的图像 同样 这在 vanilla JS 中正常工作 但在 JSX 中不起作用 我得到了一个potentially invalid re
  • 呃!尝试将包发布到 npm 时出现 403

    我正在尝试将包发布到 npm 您可以在此处查看存储库 https github com biowaffeln mdx state https github com biowaffeln mdx state 我登录到 npmnpm login
  • Javascript 浮点乘以 100 仍然有错误

    我有一个货币字段的文本输入 我在字段中输入 33 91 并在尝试使用 乘以 100 技术时得到以下结果 var curWth parseInt trans withdraw index val 100 3390 var curWth par
  • 如何重复 ajax 请求,直到满足 RxJS Observable 的条件?

    我正在尝试重复请求 直到响应包含使用 RxJS 的数据 此时我想调用成功 或失败 处理程序 但我在使用 RxJS 时遇到了麻烦 这是我目前的方法 redux observable action observable mergeMap gt
  • ChartJs:如何按时间值(而不是像素)以编程方式平移

    我使用的是chartJs 3 6 1 和 Chartjs plugin zoom 1 2 1 但我认为这并不重要 我有 2 个时间序列折线图 当我通过拖放平移一个图表时 我也想移动 平移另一个图表 为此 我为 graphA 启用了缩放 平移
  • 尝试使用 Javascript 解决对称差异

    我正在尝试找出对称的解决方案 使用 javascript 完成以下任务的差异 目标 接受未指定数量的数组作为参数 保留数组中数字的原始顺序 不删除单个数组中数字的重复项 删除数组中出现的重复项 因此 例如 如果输入是 1 1 2 6 2 3
  • PDF 在 Safari 中隐藏 Jquery Modal

    这是与我有关的事情this https stackoverflow com questions 24052681 pdf hide jquery modal in ie问题 在 IE 中 我在对话框中使用 iframe 解决了问题 所以它工

随机推荐