JavaScript函数offsetLeft-返回值慢(主要是IE9)
我很难调试一个新闻代码器——我是用JavaScript从头开始编写的 除了IE9(以及一些移动浏览器——Opera mobile)之外,它在大多数浏览器上都工作得很好,而IE9的运行速度非常缓慢 使用Developer Tools>Profiler使我能够找到问题的根本原因 这是对JavaScript函数offsetLeft-返回值慢(主要是IE9),javascript,internet-explorer,internet-explorer-9,unobtrusive-javascript,Javascript,Internet Explorer,Internet Explorer 9,Unobtrusive Javascript,我很难调试一个新闻代码器——我是用JavaScript从头开始编写的 除了IE9(以及一些移动浏览器——Opera mobile)之外,它在大多数浏览器上都工作得很好,而IE9的运行速度非常缓慢 使用Developer Tools>Profiler使我能够找到问题的根本原因 这是对offsetLeft的调用,以确定是否旋转股票代码,即第一个元素成为最后一个元素 function NeedsRotating() { var ul = GetList(); if (!ul) {
offsetLeft
的调用,以确定是否旋转股票代码,即第一个元素成为最后一个元素
function NeedsRotating() {
var ul = GetList();
if (!ul) {
return false;
}
var li = GetListItem(ul, 1);
if (!li) {
return false;
}
if (li.offsetLeft > ul.offsetLeft) {
return false;
}
return true;
}
function MoveLeft(px) {
var ul = GetList();
if (!ul) {
return false;
}
var li = GetListItem(ul, 0);
if (!li) {
return false;
}
var m = li.style.marginLeft;
var n = 0;
if (m.length != 0) {
n = parseInt(m);
}
n -= px;
li.style.marginLeft = n + "px";
li.style.zoom = "1";
return true;
}
返回值似乎需要300毫秒,而股票代码每10毫秒向左移动1个像素
有没有已知的修复方法
如果您不将选择器缓存在
var li=GetListItem(ul,1)中,请感谢代码>
那么演出就会受到很大的影响。。这就是你所看到的,因为你每10毫秒就会启动一个新的选择器
您应该将选择器缓存在散列中,如
elms["foo"] = elms["foo"] || selectElm(foo);
elms["foo"].actionHere(...)
DOM操作
我同意@samccone的观点,即如果GetList()
和GetListItem()
每次都在执行DOM操作,那么应该尽量保存对这些调用检索到的元素的引用,并减少DOM操作
然后我就可以操作这个变量,希望它不会因为调用offsetLeft而与“real”值不同步
您只需在变量中存储对DOM元素的引用。因为它是一个参考,所以它才是真正的价值。它是同一个物体。例如:
var li = ul.getElementsByTagName( "li" )[ index ];
它存储对DOM对象的引用。您可以随时从该对象读取offsetLeft
,而无需执行另一个DOM操作(如getElementsByTagName
)来检索该对象
另一方面,以下内容仅存储该值,不会保持同步:
var offsetLeft = ul.getElementsByTagName( "li" )[ index ].offsetLeft;
偏左
如果offsetLeft
确实是一个瓶颈,那么您是否可以重新编写它以减少阅读量?在这种情况下,每次旋转出第一项时,是否可以为新的第一项读取一次offsetLeft
,然后在每次调用MoveLeft()
时减小该值,直到它达到0
(或其他)?例如
如果您想更积极地避免offsetLeft
,您可以做一些事情,读取每个列表项的宽度一次,读取第一个项的offsetLeft
,然后使用这些值确定何时旋转,而不必再次调用offsetLeft
全局变量
我想我明白了。。。那么elms[“foo”]必须是一个全局变量
我想我真的需要使用全局变量,而不是每隔10毫秒调用offsetLeft
你不需要使用全局变量,事实上你应该避免它——这是一个糟糕的设计。在不使用全局变量的情况下,您至少可以采取以下几种好方法:
您可以将整个程序包装在一个闭包中:
( function () {
var elements = {};
function NeedsRotating() {
...
}
function example() {
// The follow var declaration will block access
// to the outer `elements`
var elements;
}
// Rest of your code here
} )();
有元素
的作用域是包含它的匿名函数。它不是全局变量,在匿名函数外不可见。它对匿名函数中的任何代码都是可见的,包括函数(如本例中的NeedsRotating()
),只要在内部函数中不声明同名变量
您可以将所有内容封装在一个对象中:
( function () {
var ticker = {};
ticker.elements = {};
// Assign a method to a property of `ticker`
ticker.NeedsRotating = function () {
// All methods called on `ticker` can access its
// props (e.g. `elements`) via `this`
var ul = this.elements.list;
var li = this.elements.list_item;
// Example of calling another method on `ticker`
this.do_something();
} ;
// Rest of your code here
// Something like this maybe
ticker.start();
} )();
在这里,我再次将所有内容包装在一个匿名函数中,这样即使ticker
也不是一个全局变量
对评论的答复
首先,关于setTimeout
,您最好这样做:
t = setTimeout( TickerLoop, i );
而不是:
t = setTimeout("TickerLoop();", i);
在JS中,函数是一级对象,因此您可以将实际函数对象作为参数传递给setTimeout
,而不是传递字符串,就像使用eval
您可能想考虑<代码> SETIFATION>代码>,而不是<代码> SETTIMEOUT < < /P>
因为在setTimeout中执行的任何代码都肯定会超出闭包的范围吗
事实并非如此。在定义函数时形成闭包。因此,通过setTimeout
调用函数不会干扰函数对闭合变量的访问。下面是一个简单的演示片段:
( function () {
var offset = 100;
var whatever = function () {
console.log( offset );
};
setTimeout( whatever, 10 );
} )();
但是,setTimeout
将干扰方法中的此
绑定,如果将所有内容封装在对象中,这将是一个问题。以下操作将不起作用:
( function () {
var ticker = {};
ticker.offset = 100;
ticker.whatever = function () {
console.log( this.offset );
};
setTimeout( ticker.whatever, 10 );
} )();
在ticker内部。无论什么
,这个
都不会指向ticker
。但是,在这里,您可以使用匿名函数形成闭包来解决问题:
setTimeout( function () { ticker.whatever(); }, 10 );
如果我将其存储在一个类变量中,即var ticker.SecondLiOffsetLeft=GetListItem(ul,1).offsetLeft
,那么当我旋转列表时,我只需再次调用offsetLeft
我认为这是全局变量的最佳替代方案
关键是:
每次旋转列表时,访问一次offsetLeft
offsetLeft
属性,而无需重复执行诸如getElementsByTagName()
之类的DOM操作来获取列表对象offsetLeft
,因为这样只会存储值,而不会保持同步
无论您决定如何存储它们(例如对象属性或变量),您可能都应该检索所有li
obj
setTimeout( function () { ticker.whatever(); }, 10 );
this.li = ul.getElementsByTagName( "li" );
this.current_item = ###;
// or
this.li.current = this.li[ ### ];
// Then
this.li[ this.current_item ].offsetLeft
// or
this.li.current.offsetLeft
this.li.push( this.li.shift() );
// then
this.li[0].offsetLeft