JavaScript全局优化带来的负面效果……
来源:互联网 发布:虚拟交易平台网站源码 编辑:程序博客网 时间:2024/06/14 21:35
读者在China-pub中指出《JavaScript语言精髓与编程实践》的一个示例在FF上不正常。具体来说,就是第“4.6.6 语句或语句块中的闭包问题”中的第二、三、四三个示例。这个问题我反复测试过,只出现FireFox(SpiderMonkey JavaScript)中。我当时意识到是SpiderMonkey特殊的全局变量引用机制导致的,但因为没有切实地、在源代码级别观察过,因此我没有立即回答这个问题。
这些天有点时间了,把这个话题拿出来重新讨论。代码是这样子的:
--------var obj = new Object();var events = {m1: "clicked", m2: "changed"};for (e in events) { obj[e] = function(){ alert(events[e]); };}// 显示false, 表明是不同的函数实例alert( obj.m1 === obj.m2 );--------
这个示例在其它的js引擎中,总是显示false。这与我们在“4.6.6”章中的分析是一致的。但是在Firefox中,就会显示true。按照我们的分析,这里的匿名函数直接量应该根据循环次数创建多个实例。然而在Firefox中,它只创建了一次。
出了什么问题了?
回到SpiderMonkey JavaScript引擎的源代码中,我们得知道,执行引擎并不直接执行代码,而是先将代码文本分析(parser)成代码树,再按规则执行代码树中的指令结点(op)。指令在JS中总是确定的,例如源代码中是FOR,那么总是JSOP_FOR*这个操作码。但是,指令所使用的参数却不是确定的,而是通过参数名绑定到一个具体的操作数。参数名是字符串,也就是标识符;操作数则位于该代码上下文所使用的栈中。这个栈中的操作数使用slot位置来表示。因此,这个关键的函数就是BindNameToSlot()。
这个函数具体分析执行过程中使用的一个标识符应该绑定到那个闭包(上下文)中的哪个slot位置。这受非常多的因素影响,例如我们下面这段代码(出自“5.2.3 奇特的、甚至是负面的影响”):
--------var i = 100;function myFunc(ctx) { alert("value is: " + i); eval(ctx); alert("value is: " + i);}--------
在myFunc()中,由于有一行动态执行eval()的代码,因此第一行和第二行中的变量“i”,就可能被绑定在不同闭包的solt上。例如我们执行:
--------myFunc("var i = 10;");--------
那么代码的执行效果将是显示:
--------value is: 100value is: 10--------
这也就意味着变量名必须在每行代码执行时都重新绑定——而这,也正是JavaScript效率偏低的原因。
这些过程,对所有的JS引擎来说是统一的,这是语言规范所决定的。然而,SpiderMonkey大概是觉得这想在全局范围上的效率太差……准确地说,如果一个变量标识符总是要绑定到全局变量,而每次绑定都要回溯很多层次的闭包链,所以从效率上来讲,每次都这样做就会很不经济。
于是SpiderMonkey做了一个优化。这个优化在SpiderMonkey中叫“optimizeGlobal”。其规则是:
1、在语法分析期(jsparse.c)对标识符进行计数
/* Measure optimizable global variable uses. */ ATOM_LIST_SEARCH(ale, &tc->decls, pn->pn_atom); if (…… js_IsGlobalReference(tc, pn->pn_atom, &loopy)) { tc->globalUses++; if (loopy) tc->loopyGlobalUses++; }
也就是说,当一个标识符是引用全局的,则globalUses加1,而当它处于循环体内(loopy)时,loopyGlobalUses也同时加1。
2、在标识符绑定时(BindNameToSlot)确定是否优化,即启用optimizeGlobal
function BindNameToSlot(...) {... optimizeGlobals = (tc->globalUses >= 100 || (tc->loopyGlobalUses && tc->loopyGlobalUses >= tc->globalUses / 2));...}
也就是说,在一个代码块中有超过100个全局变量名的引用;或在循环中引用全局变量的数量,超过了该上下文中所引用全局变量数量的1/2。则开启optimizeGlobal……
3、当启用optimizeGlobal时的一些优化效果
--------
这个就不讲了……极复杂的一套规则,其中就包括本文前面我们提到的这个问题。
OK。到这里我们告一段落。基本上来说,从这个例子的实际效果来讲,这是一个失败的优化。或者说SpiderMonkey中存在这样的BUG。在书中“4.6.6 语句或语句块中的闭包问题”中的第二、三、四三个示例,仅在SpiderMonkey中存在异常,就证明了这一点。另一方面,我们可以将示例代码稍作一下修改,改变它的上下文环境,效果就大为不同了。例如:
var obj = new Object();var events = {m1: "clicked", m2: "changed"};with ({}) { // <-- 打开一个对象闭包 for (e in events) { obj[e] = function(){ alert(events[e]); } }}// 显示false, 表明是不同的函数实例alert( obj.m1 === obj.m2 );
- JavaScript全局优化带来的负面效果……
- 大数据用于教育带来的负面冲击
- @import 对于网站的性能有某些负面…
- 负面搜索引擎优化策略
- 浅析:网站优化之负面排名的因素有哪些
- 民营医院负面信息处理【优化】
- 谷歌也能搜到李开复的负面报道
- Android 的负面信息
- javascript的全局函数
- javascript的全局函数
- JavaScript 的全局对象
- JavaScript的全局函数
- 在公司传播流言以及负面能量给你带来厄运
- 【妈妈负面身材形象会影响女儿】炎…
- 【7个步骤,将负面批评转为进步动…
- 【习惯接受自身负面情绪有利心理健…
- 【育儿方式遭批评,对母子都有负面…
- Javascript实现的一个简单的弹幕效果-优化版
- c#存储图片到数据库.
- 关于servlet的理解(1)
- 一句话的多种写法
- XNA Unleashed 部分翻译(1)
- C#学习4——字符串与正则表达式
- JavaScript全局优化带来的负面效果……
- 编译错误:undefined reference to `__umoddi3'的处理
- [转帖]可支持1亿pv/天的数据库缓存系统
- 免疫共沉淀
- 主板检测卡(POST卡)故障代码及排除方法速查表
- 看“单一职责原则”的感悟
- asp.net连接Access数据库
- 为谁刻下伤痕
- JavaScript通用校验汇总