Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/39.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 蓝知更鸟';s util.toFastProperties函数生成一个对象';"香港地产";快;?_Javascript_Node.js_Performance_V8_Bluebird - Fatal编程技术网

Javascript 蓝知更鸟';s util.toFastProperties函数生成一个对象';"香港地产";快;?

Javascript 蓝知更鸟';s util.toFastProperties函数生成一个对象';"香港地产";快;?,javascript,node.js,performance,v8,bluebird,Javascript,Node.js,Performance,V8,Bluebird,在蓝鸟中,它具有以下功能: function toFastProperties(obj) { /*jshint -W027*/ function f() {} f.prototype = obj; ASSERT("%HasFastProperties", true, obj); return f; eval(obj); } 出于某种原因,在返回函数后面有一个语句,我不知道它为什么在那里 同样,这似乎是有意为之,因为作者已经压制了关于这一点的JSH

在蓝鸟中,它具有以下功能:

function toFastProperties(obj) {
    /*jshint -W027*/
    function f() {}
    f.prototype = obj;
    ASSERT("%HasFastProperties", true, obj);
    return f;
    eval(obj);
}
出于某种原因,在返回函数后面有一个语句,我不知道它为什么在那里

同样,这似乎是有意为之,因为作者已经压制了关于这一点的JSHint警告:

“return”后无法访问的“eval”。(W027)

这个函数到底做什么?
util.toFastProperties
真的会使对象的属性“更快”吗


我已经在Bluebird的GitHub存储库中搜索了源代码中的任何注释或问题列表中的解释,但我找不到任何注释。

2017更新:首先,对于今天的读者,这里有一个适用于Node 7(4+)的版本:

Sans一个或两个小优化-下面的所有内容仍然有效。 让我们先讨论一下它的作用,为什么更快,然后讨论它为什么有效

它做什么 V8发动机使用两种对象表示:

  • 字典模式-在该模式中,对象作为键值映射存储为
  • 快速模式-在该模式中,对象以类似的方式存储,在该模式中,属性访问不涉及任何计算
下面是演示速度差异的示例。这里我们使用
delete
语句强制对象进入慢速字典模式

引擎在任何可能的情况下,通常在执行大量属性访问时,都会尝试使用快速模式,但有时会被抛出到字典模式。处于dictionary模式会带来很大的性能损失,因此通常需要将对象置于fast模式

这种黑客行为旨在迫使对象从字典模式进入快速模式

  • 蓝鸟自己就是佩卡
  • Vyacheslav Egorov也提到了这一点
  • 这些都是相关的
  • 这仍然是一本相当不错的书,可以让您对v8中对象的存储方式有一个很好的了解
为什么更快 在JavaScript中,原型通常存储多个实例之间共享的函数,很少动态更改很多。出于这个原因,最好让它们处于快速模式,以避免每次调用函数时都会受到额外的惩罚

为此,-v8将很乐意将函数的
.prototype
属性的对象置于快速模式,因为它们将被通过调用该函数作为构造函数创建的每个对象共享。这通常是一个聪明和可取的优化

工作原理 让我们首先浏览一下代码,了解每一行的作用:

function toFastProperties(obj) {
    /*jshint -W027*/ // suppress the "unreachable code" error
    function f() {} // declare a new function
    f.prototype = obj; // assign obj as its prototype to trigger the optimization
    // assert the optimization passes to prevent the code from breaking in the
    // future in case this optimization breaks:
    ASSERT("%HasFastProperties", true, obj); // requires the "native syntax" flag
    return f; // return it
    eval(obj); // prevent the function from being optimized through dead code 
               // elimination or further optimizations. This code is never  
               // reached but even using eval in unreachable code causes v8
               // to not optimize functions.
}
我们不必自己找到代码来断言v8进行了此优化,我们可以:

阅读并运行此测试向我们表明,此优化在v8中确实有效。不过,如果能看到这一点,那就太好了

如果我们检查objects.cc,我们可以找到以下函数(L9925):

这又被
FunctionSetPrototype
调用,这就是我们通过
得到的原型

执行
\uuuu proto\uuu=
.setPrototypeOf
也会起作用,但这些是ES6函数,自Netscape 7以来,Bluebird在所有浏览器上运行,因此这里不可能简化代码。例如,如果我们选中
.setPrototypeOf
,我们可以看到:

// ES6 section 19.1.2.19.
function ObjectSetPrototypeOf(obj, proto) {
  CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");

  if (proto !== null && !IS_SPEC_OBJECT(proto)) {
    throw MakeTypeError("proto_object_or_null", [proto]);
  }

  if (IS_SPEC_OBJECT(obj)) {
    %SetPrototype(obj, proto); // MAKE IT FAST
  }

  return obj;
}
直接位于
对象上的:

InstallFunctions($Object, DONT_ENUM, $Array(
...
"setPrototypeOf", ObjectSetPrototypeOf,
...
));
因此,我们已经走上了从佩特卡编写的代码到裸机的道路。这很好

免责声明: 请记住,这些都是实现细节。像佩特卡这样的人都是优化怪胎。永远记住,过早优化在97%的情况下是万恶之源。Bluebird经常做一些非常基本的事情,因此它从这些性能测试中获益匪浅——要像回调一样快并不容易。您很少需要在不支持库的代码中执行类似的操作。

2021年的现实(NodeJS版本12+)。 看起来一个巨大的优化完成了,具有删除字段和稀疏数组的对象不会变慢。还是我错过了smth

//在具有启用标志的节点中运行
//节点--允许本机语法script.js
功能点(x,y){
这个.x=x;
这个。y=y;
}
var obj1=新点(1,2);
var obj2=新点(3,4);
删除obj2.y;
var arr=[1,2,3]
arr[100]=100
log('obj1具有快速属性:',%HasFastProperties(obj1));
log('obj2具有快速属性:',%HasFastProperties(obj2));

log('arr具有快速属性:',%HasFastProperties(arr))eval
(在解释发布的代码OP时的代码注释中):“防止通过消除死代码或进一步优化来优化函数。此代码永远不会达到,但即使是无法达到的代码也会导致v8无法优化函数。”。你想让我进一步阐述这个问题吗?@dherman a
1不会导致“去优化”,即
调试器
也可能同样有效。很好的一点是,当
eval
被传递一个不是字符串的东西时,它不会对它做任何事情,所以它是无害的-有点像
if(false){debugger;}
Btw由于最近的v8中的一个更改,这个代码已经被更新了,现在您也需要实例化构造函数。所以它变得更懒了;d@BenjaminGruenbaum你能详细解释一下为什么不应该优化这个函数吗?在缩小的代码中,eval无论如何都不存在。为什么eval在非精简代码中有用?
void JSObject::OptimizeAsPrototype(Handle<JSObject> object) {
  if (object->IsGlobalObject()) return;

  // Make sure prototypes are fast objects and their maps have the bit set
  // so they remain fast.
  if (!object->HasFastProperties()) {
    MigrateSlowToFast(object, 0);
  }
}
if (value->IsJSObject()) {
    JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
}
// ES6 section 19.1.2.19.
function ObjectSetPrototypeOf(obj, proto) {
  CHECK_OBJECT_COERCIBLE(obj, "Object.setPrototypeOf");

  if (proto !== null && !IS_SPEC_OBJECT(proto)) {
    throw MakeTypeError("proto_object_or_null", [proto]);
  }

  if (IS_SPEC_OBJECT(obj)) {
    %SetPrototype(obj, proto); // MAKE IT FAST
  }

  return obj;
}
InstallFunctions($Object, DONT_ENUM, $Array(
...
"setPrototypeOf", ObjectSetPrototypeOf,
...
));