在对这个主题做了一些研究之后,我尝试了很多模式来组织我的 jQuery 代码(Rebecca Murphy 做了一个 )。
昨天我检查了(揭示的)模块模式。结果看起来有点让人想起我认为的 YUI 语法:
//global namespace MyNameSpace
if(typeof MNS=="undefined"||!MNS){var MNS={};}
//obfuscate module, just serving as a very simple example
MNS.obfuscate = function(){
//function to create an email address from obfuscated '@'
var email = function(){
$('span.email').each(function(){
var emailAddress = $(this).html().replace(' [ @ ] ','@');
$(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');
});
};
return {
email: email
};
}();
//using the module when the dom's ready
jQuery(document).ready(function($){
MNS.obfuscate.email();
});
最后我有几个模块。有些自然地包含“私有成员”,在这种情况下意味着仅对该模块内的其他函数重要的变量和/或函数,因此不会出现在 return 语句中。
我认为将我的代码的连接部分(例如与搜索有关的所有内容)组合在一个模块中是有意义的,给出了整个事物的结构。
但写完这篇文章后,我读了 John (Resig) 的文章,其中他还写了关于模块模式的性能:
“用一堆原型属性实例化一个函数非常非常快。它完全击败了模块模式,类似的,出水了。因此,如果你经常-你希望人们与之交互的访问函数(返回一个对象),那么将对象属性放在原型链中并实例化它对你有利:(
// Very fast
function User(){}
User.prototype = { /* Lots of properties ... */ };
// Very slow
function User(){
return { /* Lots of properties */ };
}
约翰提到他并不反对该模块。模式“本身”,只是为了让你知道:)然后
我不确定我的代码是否朝着正确的方向发展:我真的不需要需要。任何私人成员,我也认为暂时不需要继承。
我现在想要的只是一个可读/可维护的模式。我想这在一定程度上归结为个人偏好,但我不想最终得到具有(相当严重的)性能问题的可读代码。
我不是 JavaScript 专家,因此在性能测试方面更不是专家。所以首先,我真的不知道约翰提到的事情(“你希望人们与之交互的经常访问的函数(返回一个对象)”,很多属性等)在多大程度上适用于我的代码。我的代码与之交互的文档并不大,只有数百或数千个元素。所以也许这根本不是问题。
但我想到的一件事是,
$('span.email').each(function(){
var emailAddress = $(this).html().replace(' [ @ ] ','@');
$(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');
});
由于使用了模块模式,我不只是拥有(在 domready 函数内),而是创建了两个“额外”函数:混淆和电子邮件。创建附加功能需要花费一些时间。问题是:在我的情况下它是可以衡量的吗?
我不确定上面的示例中是否创建了一个闭包(在 jQuery 论坛上的一篇有趣的帖子中,我读到了以下内容:“对于内部函数是否不引用任何内容,是否会创建一个闭包,存在一个哲学争论。外部函数的变量对象...”),但我的真实代码中确实有闭包。即使我不认为其中有任何循环引用,我也不知道这会在多大程度上导致高(呃)内存消耗/垃圾收集问题。
我真的很想听听您对此的意见,也许还可以看看您的代码的一些示例。另外,您更喜欢使用哪些工具来获取有关执行时间、内存和 CPU 使用情况的信息?
After doing some research on the subject, I've been experimenting a lot with patterns to organize my jQuery code (Rebecca Murphy did a presentation on this at the jQuery Conference for example).
Yesterday I checked the (revealing) module pattern. The outcome looks a bit reminiscent of the YUI syntax I think:
//global namespace MyNameSpace
if(typeof MNS=="undefined"||!MNS){var MNS={};}
//obfuscate module, just serving as a very simple example
MNS.obfuscate = function(){
//function to create an email address from obfuscated '@'
var email = function(){
$('span.email').each(function(){
var emailAddress = $(this).html().replace(' [ @ ] ','@');
$(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');
});
};
return {
email: email
};
}();
//using the module when the dom's ready
jQuery(document).ready(function($){
MNS.obfuscate.email();
});
In the end I had several modules. Some naturally included "private members", which in this case means variables and/or functions which were only of importance for other functions within this module, and thus didn't end up in the return statement.
I thought having connected parts of my code (everything which has to do with the search for example) combined in a module makes sense, gives the whole thing structure.
But after writing this, I read an article by John (Resig), where he also writes about the performance of the module pattern:
"Instantiating a function with a bunch of prototype properties is very, very, fast. It completely blows the Module pattern, and similar, out of the water. Thus, if you have a frequently-accessed function (returning an object) that you want people to interact with, then it's to your advantage to have the object properties be in the prototype chain and instantiate it. Here it is, in code:
// Very fast
function User(){}
User.prototype = { /* Lots of properties ... */ };
// Very slow
function User(){
return { /* Lots of properties */ };
}
(John mentions he is not against the module pattern "per se" though - just to let you know :)
Then I wasn't sure anymore if I was going into the right direction with my code. The thing is: I don't really need any private members, and I also don't think I need inheritance for the time being.
All I want for now is a readable/maintainable pattern. I guess this boils down to personal preference to a certain extend, but I don't wanna end up with readable code which has (rather serious) performance issues.
I'm no JavaScript expert and thus even less of an expert when it comes to performance testing. So first, I don't really know in how far the things John mentioned ("frequently-accessed function (returning an object) that you want people to interact with", lots of properties, etc.) apply to my code. The documents my code interacts with are not huge, with 100s or 1000s of elements. So maybe it's not an issue at all.
But one thing which came to my mind is that instead of just having
$('span.email').each(function(){
var emailAddress = $(this).html().replace(' [ @ ] ','@');
$(this).html('<a href="mailto:' + emailAddress + '">' + emailAddress + '</a>');
});
(inside the domready function), I create two "extra" functions, obfuscate and email, due to the use of the module pattern. The creation of additional functions costs some time. The question is: will it be measurable in my case?
I'm not sure if a closure is created in my example above (in an interesting post on the jQuery forum I read the following: "There is a philosophical debate on whether an inner function creates a closure if it doesn't reference anything on an outer function's variable object..."), but I did have closures in my real code. And even though I don't think I had any circular references in there, I don't know in how far this could lead to high(er) memory consumption/problems with garbage collection.
I'd really like to hear your input on this, and maybe see some examples of your code. Also, which tools do you prefer to get information on execution time, memory and CPU usage?
发布评论
评论(2)
确实。这并不真正适用于使用模块作为命名空间。这是关于类实例的类似物。
通过从全新的
{name: member}
对象创建每个实例来创建的对象,其效率低于使用new Class
和Class.prototype.name 创建的对象= 成员
。在原型情况下,member
值是共享的,从而产生更轻量级的实例。在您的示例中,
MNS
是一个单例,因此通过原型共享成员没有任何好处。是的,是的。即使外部函数中没有定义变量,仍然会为外部函数创建一个 LexicalEnvironment 和作用域对象,并在其中绑定
this
和arguments
。一个聪明的 JS 引擎也许能够优化它,因为每个内部函数都必须用自己的副本隐藏this
和arguments
,但我不确定其中的任何一个当前的 JS 实现实际上就是这样做的。无论如何,性能差异应该是无法检测到的,因为您没有在参数中添加任何重要的内容。对于简单的模块模式,我认为没有任何坏处。
开始的地方只是在 for 循环中执行代码 10000 次,看看 new Date().getTime() 已经有多大,在尽可能多的不同浏览器上执行多次可以抓住。
(这是做什么的?此时它会将跨度的 HTML 读取到新的
String
中,仅将[ @ ]
的第一个实例替换为@
,并返回一个新的String
值,它不会更改 DOM 中的现有内容。)Indeed. This doesn't really apply to using modules as a namespace. It's about class instance analogues.
Objects you create by making every instance from a completely new
{name: member}
object are less efficient than objects you create usingnew Class
withClass.prototype.name= member
. In the prototype case themember
value is shared, resulting in lighter-weight instances.In your example
MNS
is a singleton, so there is no benefit to be had by sharing members through a prototype.Yes, it is. Even when no variables are defined in the outer function, there is still a LexicalEnvironment and scope object created for the outer function, with
this
andarguments
bound in it. A clever JS engine might be able to optimise it away, since every inner function must hidethis
andarguments
with their own copies, but I'm not sure that any of the current JS implementations actually do that.The performance difference, in any case, should be undetectable, since you aren't putting anything significant in the arguments. For a simple module pattern I don't think there's any harm.
The place to start is simply to execute the code 10000 times in a for-loop and see how much bigger
new Date().getTime()
has got, executed several times on as many different browsers as you can get hold of.(What is this supposed to do? At the moment it will read the HTML of the span into a new
String
, replace only the first instance of[ @ ]
with@
, and return a newString
value. It won't change the existing content in the DOM.)你有多少 JavaScript?根据我的经验,在页面上有大量 Javascript 代码的网站上,性能问题通常来自于实际做事情的代码。一般来说,问题源于试图做太多事情,或者试图把某件事做得非常糟糕。一个例子是尝试将处理程序绑定到表行(大表)中的元素,而不是使用“live”之类的东西。
我的观点是,诸如模块或功能或其他内容的组织方式之类的事情几乎肯定不会在您的页面上造成任何真正的性能问题。是什么促使你经历这些麻烦?
How much Javascript do you have? In my experience, on sites with lots of Javascript code on the pages, performance problems generally come from code that actually does things. Generally, problems stem from trying to do too many things, or trying to do some particular thing really badly. An example would be trying to do stuff like bind handlers to elements in table rows (big tables) instead of using something like "live".
My point is that things like how your modules or functions or whatever get organized is almost certainly not going to pose any sort of real performance issue on your pages. What is motivating you to go to all this trouble?