Javascript 下划线中的优化CB是如何工作的?
我一直在思考这个问题,从: 因此,显然,这种优化只适用于设置Javascript 下划线中的优化CB是如何工作的?,javascript,performance,underscore.js,Javascript,Performance,Underscore.js,我一直在思考这个问题,从: 因此,显然,这种优化只适用于设置这个值的回调(这里称为上下文)。这与直接调用回调有什么不同?这是如何提高性能的 如果优化只对遗留的JS引擎有效,那也没关系。我很想知道 编辑 这个问题我可能不清楚。这就是我的意思。让我们举一个使用optimizeCb的例子: _.each = _.forEach = function(obj, iteratee, context) { iteratee = optimizeCb(iteratee, context); //R
这个
值的回调(这里称为上下文
)。这与直接调用回调有什么不同?这是如何提高性能的
如果优化只对遗留的JS引擎有效,那也没关系。我很想知道
编辑
这个问题我可能不清楚。这就是我的意思。让我们举一个使用optimizeCb的例子:
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context); //REMOVE this
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
//REPLACE with iteratee.call(context, obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};
\uEach=\uForEach=函数(对象、迭代对象、上下文){
iteratee=optimizeCb(iteratee,context);//删除此
变量i,长度;
if(类isArrayLike(obj)){
对于(i=0,长度=obj.length;i
请参阅2条注释:iteratee=optimizeCb(iteratee,context)//删除此
和迭代对象(obj[i],i,obj)//替换为iteratee.call(上下文,obj[i],i,obj)代码>。我知道争论很慢,应用也很慢。但我看不出参数和调用vs应用在这里起到什么作用?我认为这两种方法没有区别
我认为关键问题是,如果回调被传递给某个下划线方法,那么签名就已经被知道了。例如,传入的回调。每个必须具有函数(值、索引、集合)
。这个观察结果通过调用optimizeCb的方式得到证实:如果optimizeCb的调用者能够提供argCount参数(留空意味着它是3),那么它知道它是哪个签名
有人能再详细说明一下吗?非常感谢 他们这样做的三个原因:
在旧的JavaScript引擎上访问参数
伪数组的成本很高。真的很贵。比如,几个数量级的成本。:-)
我不认为现代引擎会有太大的成本,特别是在严格模式下,这会消除参数
和形式函数参数之间的实时联系
正如a中所指出的,apply
比call
慢。基于这一点,看起来大约是成本的一半到两倍。因此,与参数的数量级或两个数量级不同(回到今天),但速度更快
如果context
是undefined
,则它们返回函数时保持不变(这是初始的If(context==void 0)return func;
),因此调用时根本不涉及。call
或。apply
因此,这有两方面的作用:
A) 如果回调不需要特定的this
,它将通过简单的函数调用直接使用回调。如果回调确实需要一个特定的this
,它们会创建一个函数,它们可以使用正确的this
来调用该函数,这样可以避免传递上下文
参数,并简化调用代码
B) 通过定制包装函数,他们避免访问参数
,并使用apply
处理常见数量的参数:使用1-4个参数的回调可以避免成本,使用0个或4个以上参数的回调会产生成本。调用
的速度要快得多。我在想,因为它不必访问参数array@Moogs:您链接到的测试不是对苹果进行比较;我认为这一点是正确的:call
比apply
还有一个明显的优势。@CharlesW.:上面加了第3条。
_.each = _.forEach = function(obj, iteratee, context) {
iteratee = optimizeCb(iteratee, context); //REMOVE this
var i, length;
if (isArrayLike(obj)) {
for (i = 0, length = obj.length; i < length; i++) {
iteratee(obj[i], i, obj);
//REPLACE with iteratee.call(context, obj[i], i, obj);
}
} else {
var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
iteratee(obj[keys[i]], keys[i], obj);
}
}
return obj;
};