Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/459.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Arrow函数、.bind或argThis for Array.map()?垃圾收集&x2B;演出_Javascript_Node.js_Performance_Memory_Garbage Collection - Fatal编程技术网

Javascript Arrow函数、.bind或argThis for Array.map()?垃圾收集&x2B;演出

Javascript Arrow函数、.bind或argThis for Array.map()?垃圾收集&x2B;演出,javascript,node.js,performance,memory,garbage-collection,Javascript,Node.js,Performance,Memory,Garbage Collection,我正在做一个每天要处理数十亿个请求的项目,而性能和内存使用是一个很大的问题 昨天,我在一个每分钟执行很多次的代码中实现了一些更改,我使用箭头函数进行了一些映射,但是团队要求我在使用.map时始终使用argsThis,我不明白为什么,所以我做了很多基准测试,结果正好相反 (绑定vs箭头函数vs ArgsThis) 他们的论点是,当使用箭头函数时,垃圾收集是最糟糕的,这些情况并没有显示真实的场景,因为它有一个非常浅的上下文 基准测试结果表明,箭头函数快得多,有什么我需要考虑的吗? 谢谢 编辑: 问

我正在做一个每天要处理数十亿个请求的项目,而性能和内存使用是一个很大的问题

昨天,我在一个每分钟执行很多次的代码中实现了一些更改,我使用箭头函数进行了一些映射,但是团队要求我在使用.map时始终使用argsThis,我不明白为什么,所以我做了很多基准测试,结果正好相反

(绑定vs箭头函数vs ArgsThis)

他们的论点是,当使用箭头函数时,垃圾收集是最糟糕的,这些情况并没有显示真实的场景,因为它有一个非常浅的上下文

基准测试结果表明,箭头函数快得多,有什么我需要考虑的吗? 谢谢

编辑:

问题是对于我们需要来自上层上下文的变量的情况,例如:

function doSomething() {
    const someUpperContextValue = 5;
    [1, 2, 3].map((currentValue) => calculateValues(someOutterContextValue, currentValue));
}

免责声明:只需知道,你的低于真实世界的基准可能不会显示完整的画面,但我不会在这里讨论

我们可以非常简单地了解JavaScript引擎如何调用函数。请注意,我不是JS运行时工作原理方面的专家,所以请纠正我的错误或不完整之处

每当执行一个函数时,就会创建一个“调用范围”,并将其添加到堆栈中。对于普通/经典函数(非箭头函数),引擎创建一个新的上下文,该上下文有自己的“闭包”和变量范围。在这个上下文中,有一些隐式创建的变量,例如引擎放在那里的
this
arguments

function foo() {
  const self = this;
  function bar(...args) {
    console.log(this === self); //-> false
    console.log(arguments); //-> { length: 1, 0: 'barg' }
    console.log(args); //-> [ 'barg' ]
  }
  bar('barg');
  console.log(arguments); //-> { length: 1, 0: 'farg' }
} 
foo('farg');
Arrow函数的工作原理与常规函数非常相似,但没有额外的闭包和额外的变量。密切注意记录结果的差异:

function foo() {
  const self = this;
  const bar = (...args) => {
    console.log(this === self); //-> true
    console.log(arguments); //-> { length: 1, 0: 'farg' }
    console.log(args); //-> [ 'barg' ]
  }
  bar('barg');
  console.log(arguments); //-> { length: 1, 0: 'farg' }
} 
foo('farg');
带着这个非常热门的话题。。。几乎是肤浅的。。。您可以看到,在创建箭头函数时,引擎所做的工作“更少”。原因是,由于这个原因,箭头函数天生就更快此外,我认为箭头函数不会比常规函数()带来更多内存泄漏或垃圾收集的可能性。

编辑:

值得一提的是,每次声明函数时,都会定义一个占用内存空间的新变量。JavaScript引擎还必须为每个函数保留“上下文”,以便在“父”作用域中定义的变量在函数执行时仍然可用。例如,每当您在上面调用
foo
时,就会在内存中创建一个新的
bar
变量,可以访问其父“foo”调用范围的完整上下文。JS引擎能够很好地判断何时不再需要上下文,并在垃圾收集过程中对其进行清理,但要知道,如果垃圾太多,即使垃圾收集也会很慢

此外,引擎有一个优化层(请参阅),它非常智能并且不断发展。为了说明这一点,考虑你提供的例子:

function doSomething() {
    const someUpperContextValue = 5;
    [1, 2, 3].map((currentValue) => calculateValues(someOutterContextValue, currentValue));
}

在不太了解JS引擎内部的情况下,我可以看到引擎优化了
doSomething
函数,因为
someUpperContextValue
变量的静态值为
5
。如果将该值更改为类似于
Math.random()
,那么现在引擎不知道该值是什么,无法进行优化。出于这些原因,很多人会告诉你,你问“哪个更快”是在浪费时间,因为你永远不知道什么时候一个小的无害的改变会完全毁掉你的表现。

我要给你点颜色看看。你为什么需要这两个呢?绑定和内联箭头函数每次都将创建一个新函数。如果你如此关心内存使用,为什么不重用一个函数,而不是创建新的呢?好问题,塔普拉,检查一下基准测试,原因很明确。它适用于我们需要来自上层上下文的变量的情况,而不仅仅是数组元素上的变量。
函数.prototype.call
(或apply)vs bind可用于执行相同类型的操作来更改函数的上下文,而无需创建函数的全新实例。.call和.apply立即调用函数,它将如何与.map一起工作?有趣的思考过程。我倾向于接受你的回答。我相信你是对的,这很有道理,我会测试这个,强调这个解决方案,只是为了确保。非常感谢。基准测试的谬误在于JS引擎在执行之前不断提高优化代码的能力(请阅读v8)。所以今天慢的东西明天可能会非常快,而且经常有一些快的代码会变慢——你永远不知道。所以,花点时间,运行一些测试,看看什么更快,但不要太沉迷其中。@RyanWheale优化不仅是一个移动目标,基准测试的另一个问题是它们很少使用真实数据。OP的基准也落入了同样的陷阱。数据是
新数组(100)。填充(1)
新数组(1_000_000)。填充({id:“some_id”,值:0})
,这完全是人为的。这是单调的数据,搜索它可能会表现出与真实数据不同的行为@我在这里比较的是箭头函数和其他实现,并试图理解为什么它在性能上有不同的结果。我完全同意早期避免超级优化的理念,但这不是问题的主题。如果你想谈论这一点,问题是,一些开发人员正试图强制一个可读性不好的代码标准,以换取一个虚假的“超级优化”。(使用map的第二个参数argThis)这些答案将帮助我反驳这些“超级优化”,它们会增加额外的代码和复杂性。@PedroKehl我会让他们回答1。证明它2。嘘