Author Mark ' Tarquin ' wilton-jones • November 2, 2006
This article translates from efficient JavaScript
The address of the original translation http://kb.operachina.com/node/207
Traditionally, web pages don't have a large number of scripts, and at least scripts rarely affect the performance of a Web page. But as Web pages become more and more like web applications, the efficiency of scripts is increasingly affecting the performance of Web pages. And more and more applications are being developed using WEB technology, so it's important to improve the performance of scripts.
For desktop applications, you typically use the compiler to convert source code into a binary program. The compiler can spend a lot of time optimizing the efficiency of the final binary program. Web applications are different. Because Web applications need to run in different browsers, platforms, and architectures, it is not possible to compile them completely in advance. The browser performs the interpretation and compilation work after obtaining the script. User requirements not only require Web pages to be loaded quickly, but also require that final Web applications perform as smoothly as desktop applications. Web applications should be able to run on a variety of devices, from ordinary desktop computers to mobile phones.
Browsers are not very good at this job. Although Opera has the fastest scripting engine in the present, browsers have the inevitable limitations that require the help of WEB developers. Web developers have a lot of ways to improve the performance of Web applications, such as simply turning one loop into another, splitting the combined style into three or adding only the actual script needed.
This article introduces several simple ways to improve the performance of WEB applications from Ecmascript/javascript, DOM, and page loading.
Directory
ECMAScript
- Avoid using
eval
or Function
constructing functions
- Rewrite
eval
- If you need a function, then use the function
- Avoid using
with
- Do not use
try-catch-finally
in critical functions that affect performance
- Separation
eval
and with
- Avoid using global variables
- Note Implicit object conversions
- Avoid
for-in
in key functions
- Optimizing String Merging
- Basic operators are faster than function calls
- To
setTimeout()
and setInterval()
transfer function names instead of passing strings
Dom
- Redrawing and Reflow
- Reduce the number of reflow
- Minimizing the impact of reflow
- Modifying the DOM Tree
- Modifying an invisible Element
- Measurement size
- Modify multiple style values at once
- Exchange fluency for Speed
- Avoid searching a large number of nodes
- Using XPath to improve speed
- Avoid modifying the DOM while traversing the DOM
- Using variables to save DOM values
Page load
- Avoid saving references from other documents
- Fast history browsing
- Using XMLHttpRequest
- Dynamically creating a SCRIPT element
location.replace()
Controlling history items
ECMAScript
Avoid using eval
or Function
constructing functions
Each time eval
or Function
constructor acts on the source code represented by the string, the scripting engine needs to convert the source to executable code. This is a very resource-intensive operation-usually 100 times times slower than a simple function call.
eval
The function is particularly inefficient, because the contents of the string being passed are not known in advance, and the eval
eval
code to be processed is interpreted in its context, meaning that the compiler cannot optimize the context, so only browsers can interpret the code at run time. This has a significant impact on performance.
Function
The constructor eval
is slightly better because using this code does not affect the surrounding code, but it is still slow.
Rewriteeval
eval
Not only inefficient, but most of the cases are completely unused. In many cases, eval is used because the information is provided as a string, and developers mistakenly believe that only eval can use this information. The following example is a typical error:
Copy Code code as follows:
function GetProperty (ostring) {var oreference; eval (' oreference = Test.prop. ') +ostring); return oreference; }
The following code executes exactly the same function, but does not use eval
:
Copy Code code as follows:
function GetProperty (ostring) {return test.prop[ostring];}
In Opera 9, Firefox, and Internet Explorer the latter is 95% faster than the former and 85% in Safari. (Note that this comparison does not contain the call time for the function itself.) )
If you need a function, then use the function
The following are common Function
constructor uses:
Copy Code code as follows:
function Addmethod (oobject,oproperty,ofunctioncode) {Oobject[oproperty] = new Function (Ofunctioncode);} addmethod ( MyObject, ' rotateBy90 ', ' this.angle= (this.angle+90)%360 '); Addmethod (MyObject, ' rotateBy60 ', ' this.angle= (this.angle+60)%360 ');
The following code does not use Function
constructors, but provides the same functionality: By creating an anonymous function:
Copy Code code as follows:
function Addmethod (oobject,oproperty,ofunction) {Oobject[oproperty] = ofunction;} addmethod (MyObject, ' rotateBy90 ', function () {this.angle= (this.angle+90)%360;}); Addmethod (MyObject, ' rotateBy60 ', function () {this.angle= (this.angle+60)%360;});
Avoid using with
Although it looks convenient, it with
is inefficient. The with
structure also creates a scope so that the script engine searches when the variable is used. This in itself only slightly affects performance. But the serious thing is that the scope content is not known at compile time, so the compiler cannot be optimized as it does for other scopes, such as the scope that the function produces.
Another efficient and convenient approach is to use variables to refer to objects, and then use variables to access object properties. It is only applicable if the property is not literal type, such as a string or a Boolean value.
Consider the following code:
Copy Code code as follows:
With (test.information.settings.files) {primary = ' names '; secondary = ' roles '; tertiary = ' References ';}
The following code is more efficient:
var testobject = test.information.settings.files;
testobject.primary = ' names ';
testobject.secondary = ' roles ';
Testobject.tertiary = ' References ';
Do not use try-catch-finally
in critical functions that affect performance
try-catch-finally
The structure is quite special. Unlike other syntactic structures, it creates new variables in the current scope of runtime. Whenever catch
executed, the captured exception object is assigned to a variable. This variable does not belong to any script. It catch
is created at the beginning of the statement and is destroyed at the end.
Because this function is special, and dynamic destruction is created dynamically at run time, some browsers do not work efficiently with it. Placing catch statements in a critical loop will have a significant impact on performance.
If possible, do exception handling in a script where it is not frequently invoked, or avoid using it by checking if an action is supported. In the following example, if the required property does not exist, a number of exceptions are thrown in the loop statement:
Copy Code code as follows:
var oproperties = [' A ', ' second ', ' third ',..., ' nth '], I; for (i = 0; i < oproperties.length; i++) {try {test[oproperties[i]].someproperty = somevalue;} catch (E) {...}}}
In many cases, you can
try-catch-finally
move the structure outside of the loop. This slightly changes the semantics of the program, because if an exception is thrown, the entire loop is stopped:
var oproperties = [' A ', ' second ', ' third ',..., ' nth '], I;
try {for
(i = 0; i < oproperties.length i++) {
test[oproperties[i]].someproperty = somevalue;
}
} CA TCH (e) {
...
}
Sometimes you can replace the structure with property detection or other instrumentation try-catch-finally
:
[Code]var oproperties = [' A ', ' second ', ' third ',..., ' nth '], I; for (i = 0; i < oproperties.length i++) {if (test[oproperties[i)]) {test[oproperties[i]].someproperty = somevalue; } }
Separation eval
andwith
Because the eval and with structures seriously affect performance, you should avoid using these structures as much as possible. However, if you have to use them, avoid using them in frequently called functions or loops. It's a good idea to put these structures in code that runs only once, or a few times, and don't put them in code that is more performance-demanding.
If possible, separate these structures from other code so that they do not affect script performance. If you place it in the top-level function, or only once and then save the run result, avoid using it again.
try-catch-finally
Structures can also affect performance in some browsers, including Opera, so it is best to separate them.
Avoid using global variables
Global variables are simple to use, so it's tempting to resist the temptation to use global variables in scripts. However, sometimes global variables can also affect script performance.
First, if a global variable is referenced within a function or other scope, the scripting engine has to view the scope at one level until it is searched to the global scope. Querying local scope variables is faster.
Second, global variables will always exist in the script lifecycle. The local variable is destroyed at the end of the local scope and the memory used is reclaimed by the garbage collector.
At lastwindow 对象也共享全局作用域,也就是说本质上是两个作用域而不是一个。使用全局变量不能像使用本地变量那样使用前缀,因此脚本引擎要花更多时间查找全局变量。
You can also create global functions in global scopes. function, the script engine takes more time to find global variables to find global variables as the function call progression increases.
Consider the following simple example,i 和 s 是全局作用域且函数使用这两个全局变量:
Copy Code code as follows:
var i, s = '; function TestFunction () {for (i = 0; i < i++) {s + = i}} testfunction ();
The following function is more efficient. In most browsers, including Opera 9, the latest edition of Internet Explorer, Firefox, Konqueror, and Safari, the latter executes faster than 30% of the code above.
function TestFunction () {
var i, s = ';
for (i = 0; i < i++) {
S + = i
}
}
TestFunction ();
Note Implicit object conversions
Literal, such as strings, numbers, and Boolean values, have two representations in ECMAScript. Each type can create variable values or objects. For example, the string var oString = 'some content';
value is created, and var oString = new String('some content');
a string object is created.
All properties and methods are defined in a string object, not a string value. Each time a method or property that uses a string value, the ECMAScript engine implicitly creates a new string object with the same string value. This object is used only for this request and will be recreated each time the view calls the string value method.
The following code will require the scripting engine to create 21 new string objects, each time using thelength 属性时都会产生一个,每一个 charAt 方法也会产生一个:
var s = ' 0123456789 ';
for (var i = 0; i < s.length; i++) {
S.charat (i);
}
The following code is the same as above, but only one object is created, so it is more efficient:
Copy Code code as follows:
var s = new String (' 0123456789 '); for (var i = 0; i < s.length; i++) {S.charat (i);}
If the method of literal value is often called in your code, you should consider creating the object as in the example above.
Note that most of the techniques in this article are valid for all browsers, but this technique is particularly specific to Opera. The improvement in Internet Explorer and Firefox is not as noticeable in Opera as this optimization technique.
Avoid for-in
in key functions
for-in
Often misused, especially for
when simple loops are more appropriate. for-in
looping requires the script engine to create a list of all enumerable properties, and then check for duplicates.
Sometimes the script has known enumerable properties. This is a simple for
loop that iterates through all the properties, especially when using sequential numeric enumeration.
The following is an incorrect for-in
circular usage:
Copy Code code as follows:
var osum = 0; for (var i in Oarray) {osum + = Oarray[i];}
for
Loops are no doubt more efficient:
Copy Code code as follows:
var osum = 0; var olength = oarray.length; for (var i = 0; i < olength i++) {osum + = Oarray[i];}
Optimizing String Merging
String merging is relatively slow. +
operator Regardless of whether the result is saved in a variable. It creates a new string object and assigns the result to this object, and perhaps the new object is assigned to a variable. The following is a common string merge statement:
Copy Code code as follows:
This code first creates a temporary string object to hold the merged ' XY ' value, and thena变量合并,最后将结果赋给a。下面的代码使用两条分开的命令,但每次都直接赋值给a ,因此不需要创建临时string对象。结果在大部分浏览器中,后者比前者快20%,而且消耗更少的内存:
Copy Code code as follows:
A = = ' x '; A + = ' y ';
Basic operators are faster than function calls
While the effect of individual use is not obvious, it can improve scripting performance if you use basic operators in place of function calls in critical loops and functions that require high performance. Examples include arrays of push 方法,其效率低于直接在数组末位赋值。另一个例子是 Math 对象方法,大部分情况下,简单的数学运算符效率更高更合适。
Copy Code code as follows:
var min = math.min (a,b); A.push (v);
The following code implements the same functionality but is more efficient:
Copy Code code as follows:
var min = a < b? A:B; A[a.length] = v;
To setTimeout()
and setInterval()
transfer function names instead of passing strings
setTimeout()
And setInterval()
methods approximate to eval
. If the pass parameter is a string, then after a period of time, the eval
string value is executed as the same, and of course its inefficiency is the eval
same.
However, these methods can also accept functions as the first argument. This function is called after a period of time, but this function can be interpreted and optimized at compile time, which means better performance. A typical example of using string as a parameter is as follows:
Copy Code code as follows:
SetInterval (' Updateresults () ', 1000); SetTimeout (' X+=3;prepareresult (); if (!hascancelled) {Runmore ();} ', 500);
The first statement can pass a function name directly. In the second statement, you can use anonymous functions to encapsulate code:
SetInterval (updateresults,1000);
settimeout (function () {
x + 3;
Prepareresult ();
if (!hascancelled) {
runmore ();
}
},500);
It should be noted that timeout or time delay may not be accurate. Browsers usually spend more time than they ask for. Some browsers will complete the next delay slightly earlier to compensate. Some browsers may be waiting for the exact time each time. Many factors, such as CPU speed, thread state, and JavaScript load all affect the precision of time delay. Most browsers cannot provide a delay of less than 1ms, which may set a minimum possible delay, usually between 10 and Ms.
Dom
Typically, there are three main situations that cause the DOM to run slower. The first is a script that performs a large number of DOM operations, such as building a new DOM tree from the obtained data. The second scenario is that the script causes too much reflow or redrawing. The third scenario is the use of slower DOM node positioning methods.
The second and third scenarios are more common and have a more severe performance impact, so the first two cases are introduced.
Redrawing (Repaint) and reflow
Redrawing is also referred to as redrawing, which requires redrawing the operation whenever previously invisible elements become visible (or vice versa), and redrawing does not change the layout of the page. If you add contours to an element, change the background color, and change the style. Redrawing has a significant impact on performance because the scripting engine needs to search all elements to determine which ones are visible and which should be displayed.
Reflow is a much larger change. When the DOM number is changed, the style that affects the layout is modified, when the element'sclassName属性被修改时或当浏览器窗口大小变化时都会引起 reflow。脚本引擎必须 reflow 相关元素以确定哪些部分不应被现实。其子节点也会被reflow 以考虑其父节点的新布局。DOM 中此元素之后出现的元素也被 reflow以计算新布局,因为它们的位置可能已被移动了。祖先节点也需要 reflow 以适应子节点大小的改变。总之,所有元素都需被重绘。
Reflow is a very time-consuming operation from a performance perspective, and is one of the main causes of slow DOM scripting, especially on devices with weaker processing power such as mobile phones. In many cases, the reflow and redistribution of the entire page is time-consuming.
Reduce the number of reflow
In many cases, scripts require operations that cause reflow or redrawing, such as animations that require reflow operations, so reflow is an essential feature of WEB development. To allow the script to run quickly, you should minimize the number of reflow without affecting the overall visual effect.
The browser can choose to cache reflow operations, such as to wait until the script thread finishes before reflow to render the change. Opera can wait for a sufficient number of changes before reflow, or wait long enough to reflow, or wait for the script thread to end before reflow. That is, if a lot of small changes occur in a script thread, it may cause only one reflow. However, developers cannot rely on this feature, especially given the varying speed of the different devices running opera.
Note that the reflow consumption time of different elements is different. Reflow table elements consume up to 3 times times the time of the reflow block element.
Minimizing the impact of reflow
A normal reflow may affect the entire page. The more Reflow page content, the longer the reflow operation. The more Reflow page content, the longer it takes. Elements with fixed positions do not affect the layout of the page, so if they are reflow, they simply reflow themselves. The pages behind it need to be redrawn, but this is much faster than reflow the entire page.
So the animation should not be used for the entire page, preferably for fixed position elements. Most animations meet this requirement.
Modifying the DOM Tree
Modifying the DOM tree can cause reflow. Adding new elements to the DOM, modifying text node values, or modifying properties can cause reflow. Multiple modifications in order can cause more than one reflow, so it is a good idea to place multiple modifications in an invisible DOM tree fragment. This requires only one DOM modification operation:
Copy Code code as follows:
var docfragm = document.createdocumentfragment (); var elem, contents; for (var i = 0; i < textlist.length i++) {elem = document.createelement (' P '); contents = document.createTextNode (Tex Tlist[i]); Elem.appendchild (contents); Docfragm.appendchild (Elem); } document.body.appendChild (DOCFRAGM);
You can also make multiple DOM tree modifications in the clone version of an element, replacing the original version with a cloned version after the modification is complete, which requires only one reflow operation. Note If the element contains form controls, you cannot use this technique because the user's modifications will not be reflected in the DOM tree. This technique should also not be used to bind the elements of an event handler, since these elements should not theoretically be cloned.
Copy Code code as follows:
var original = document.getElementById (' container '); var cloned = Original.clonenode (true); Cloned.setattribute (' width ', ' 50% '); var elem, contents; for (var i = 0; i < textlist.length i++) {elem = document.createelement (' P '); contents = document.createTextNode (Tex Tlist[i]); Elem.appendchild (contents); Cloned.appendchild (Elem); } original.parentNode.replaceChild (cloned,original);
Modifying an invisible Element
If an element'sdisplay 样式被设置为 none,即使其内容变化也不再需要重绘此元素,因为根本就不会显示此元素。可以利用这一点。如果需要对一个元素或其内容做出多个修改,又无法将这些更改放在一个重绘中,则可以先将元素设置为 display
:none ,做出修改后,在把元素改回原来状态。
The above method will result in two additional reflow, one to hide the element when the other is to display the element again, but the overall efficiency of this method is still high. If the hidden element affects the scroll bar position, the above method may also cause the scroll bar to bounce. But this technique is also used to fix position elements without causing any unattractive effects.
Copy Code code as follows:
var Poselem = document.getElementById (' animation '); PosElem.style.display = ' None '; Poselem.appendchild (Newnodes); PosElem.style.width = ' 10em '; ... other changes ... posElem.style.display = ' block ';
Measurement size
As described above, browsers may cache multiple modifications to execute together and perform only one reflow. But note that to ensure the correct results, measuring the size of the elements will also cause reflow. Although this does not cause any redrawing, reflow operations are still performed in the background.
Use offsetWidth 这样的属性或 getComputedStyle 这样的方法都会引起 reflow 。即使不使用返回的结果,上述操作也会引起立即 reflow。如果重复需要测量结果,可以考虑只测量一次但用变量保存结果。
Copy Code code as follows:
var Poselem = document.getElementById (' animation '); var calcwidth = poselem.offsetwidth; PosElem.style.fontSize = (CALCWIDTH/10) + ' px '; PosElem.firstChild.style.marginLeft = (CALCWIDTH/20) + ' px '; PosElem.style.left = ((-1 * calcwidth)/2) + ' px '; ... other changes ...
Modify multiple style values at once
Similar to a DOM tree modification, multiple styles can be modified one at a time to minimize the number of redraw or reflow. Common settings style methods are set individually:
Copy Code code as follows:
var tochange = document.getElementById (' mainelement '); ToChange.style.background = ' #333 '; ToChange.style.color = ' #fff '; ToChange.style.border = ' 1px solid #00f ';
The above code may cause multiple reflow and redrawing. There are two methods of improvement. If the elements take multiple styles, and these style values are known beforehand, you can use the new style by modifying the element class:
div {
background: #ddd;
Color: #000;
border:1px solid #000;
}
div.highlight {
background: #333;
Color: #fff;
border:1px solid #00f;
}
...
document.getElementById (' mainelement '). ClassName = ' highlight ';
The second approach is to define new styles for the elements, rather than assigning them to each. This is primarily used for dynamic modifications, such as in animations where new style values cannot be known beforehand. By using style 对象的 cssText 属性,或者通过 setAttribute. 可以实现此技巧。Internet Explorer 不允许第二种形式,支持第一种形式。有些较老的浏览器,包括 Opera 8 需要使用第二种形式,不支持第一种形式。最简单的方式是测试看是否支持第一种形式,如果支持就使用,如果不支持则使用第二种形式。
Copy Code code as follows:
var Poselem = document.getElementById (' animation '); var NewStyle = ' background: ' + newback + '; ' + ' color: ' + Newcolor + '; ' + ' border: ' + Newborder + '; if (typeof (PosElem.style.cssText)!= ' undefined ') {posElem.style.cssText = NewStyle;} else {Poselem.setattribute (' st Yle ', NewStyle); }
Exchange fluency for Speed
As developers, of course you want the animation to run as smoothly as possible, usually with smaller time intervals or smaller changes. If you update the animation every 10ms, or move 1 pixels at a time. This animation may work perfectly on your desktop computer or in some browsers. However, the 10ms time interval may be the smallest value that the browser can achieve with 100%CPU. Some browsers may not even complete-requiring 100 reflow per second is not easy for most browsers. Low-performance computers or other devices may not be able to achieve this speed, and animations can be slow or even unresponsive on those devices.
So it's best to put the developer's pride aside for a while, sacrificing fluency in exchange for speed. Changing the time interval to 50ms or setting the animation step to 5 pixels consumes less computing resources and works well on low performance devices.
Avoid searching a large number of nodes
When you need to find a node, try to narrow your search using the DOM built-in methods and collections. If you want to locate an element that contains an attribute, you can use the following code:
Copy Code code as follows:
var allelements = document.getelementsbytagname (' * '); for (var i = 0; i < allelements.length i++) {if (Allelements[i].hasattribute (' someattr ')) {...}}}
Even if you haven't heard of advanced techniques such as XPath, you can see that the above code has two problems that cause slower speeds. First it searches for each element, rather than trying to narrow the search. Second, even if you have found the element you want to show off the code, continue searching. If you know the element you are looking for is in the IDinhere的 div 中,最好使用下面的代码:
Copy Code code as follows:
var allelements = document.getElementById (' Inhere '). getElementsByTagName (' * '); for (var i = 0; i < allelements.length i++) {if (Allelements[i].hasattribute (' someattr ')) {... break;}}
If you know that you are looking for an element to be a direct child of a Div, the following code is faster:
Copy Code code as follows:
var allchildren = document.getElementById (' Inhere '). ChildNodes; for (var i = 0; i < allchildren.length i++) {if (Allchildren[i].nodetype = 1 && allchildren[i].hasattribute (' SomeAttr ')) {... break;} }
The basic idea is to try to avoid looking at the DOM nodes individually. Dom has a number of better and faster methods, such as Dom 2 traversal treewalker, which is more efficient than recursive lookupschildNodes 集合。
Using XPath to improve speed
If you need to create a table of contents in an HTML Web page based on the H2-H4 element. Header elements can be present in many places in HTML, so you cannot use recursive functions to get these elements. Traditional DOM may use the following methods:
Copy Code code as follows:
var allelements = document.getelementsbytagname (' * '); for (var i = 0; i < allelements.length i++) {if (Allelements[i].tagname.match (/^h[2-4]$/i)) {...}}}
This method can be slow if the page has more than 2000 elements. If XPath is supported, a much faster approach can be used, because the XPath query engine is better tuned than JavaScript that needs to be interpreted. In some cases, the XPath speed can be as fast as 2 orders of magnitude above. The following code completes the same function as above, but uses XPath to make it faster:
Copy Code code as follows:
var headings = document.evaluate ('//h2|//h3|//h4 ', document, NULL, xpathresult.ordered_node_iterator_type, NULL); var oneheading; while (oneheading = Headings.iteratenext ()) {...}
The following version of the code blends the above two methods, uses the Quick Method where XPath is supported, and uses the traditional DOM method when not supported:
if (document.evaluate) {
var headings = document.evaluate ('//h2|//h3|//h4 ', document, NULL, Xpathresult.ordered_ Node_iterator_type, null);
var oneheading;
while (oneheading = Headings.iteratenext ()) {
...
}
}} else {
var allelements = document.getElementsByTagName (' * ');
for (var i = 0; i < allelements.length i++) {
if (Allelements[i].tagname.match (/^h[2-4]$/i)) {
...
}
}
}
Avoid modifying the DOM while traversing the DOM
Some DOM collections are real-time, and if the related elements change when your script traverses the list, the collection changes immediately without waiting for the script to end.childNodes 集合和 getElementsByTagName 返回的节点列表都是这样的实时集合。
If you add elements to it while traversing such a collection, you may experience an infinite loop because you are constantly adding elements to the list and never touching the end of the list. This is not the only problem. To improve performance, these collections may be optimized, such as remembering their length and remembering the last access element ordinal in the script, so that you can quickly locate the next element when you access it.
If you modify the DOM tree at this time, even if the modified element is not in this collection, the collection will search again to see if there are any new elements. This makes it impossible to remember the last access element ordinal or to remember the collection length, because the collection itself may have changed so that the optimizations cannot be used:
var Allpara = document.getelementsbytagname (' P ');
for (var i = 0; i < allpara.length i++) {
allpara[i].appendchild (document.createTextNode (i));
}
The following code is 10 times times faster than the above code in mainstream browsers such as Opera and Internet Explorer. Create a static list of elements that you want to modify, and then iterate through the static list and make the appropriate changes instead of traversing thegetElementsByTagName 返回的节点列表:
var Allpara = document.getelementsbytagname (' P ');
var collecttemp = [];
for (var i = 0; i < allpara.length i++) {
collecttemp[collecttemp.length] = Allpara[i];
}
for (i = 0; i < collecttemp.length i++) {
collecttemp[i].appendchild (document.createTextNode (i));
}
Collecttemp = null;
Using variables to save DOM values
Some DOM return values cannot be cached, and the function is called again each time it is invoked. Such as getElementById 方法。下面是一个低效率代码的例子:
Copy Code code as follows:
document.getElementById (' Test '). Property1 = ' value1 '; document.getElementById (' Test '). Property2 = ' value2 '; document.getElementById (' Test '). Property3 = ' value3 '; document.getElementById (' Test '). Property4 = ' value4 ';
This code calls four times for the same object to be positionedgetElementById 方法。下面的代码只调用了一次并将结果保存在变量中,单看这一个操作可能比上面单个操作要略慢,因为需要执行赋值语句。但后面不再需要调用 getElementById 方法!下面的代码比上面的代码要快5-10倍:
Copy Code code as follows:
var sample = document.getElementById (' test '); sample.property1 = ' value1 '; Sample.property2 = ' value2 '; Sample.property3 = ' value3 '; Sample.property4 = ' value4 ';
Page load
Avoid saving references from other documents
If the document has access to nodes or objects in other documents, avoid retaining the references at the end of the script. If you have saved these references in global variables or object properties, either clear them by setting them to null or delete them directly.
The reason is that after another document is destroyed, such as a pop-up window is turned off, and even though that document is no longer available, all references to objects in that document will save the entire DOM tree and script environment in memory. This also applies to pages that are contained in frame, inline frame, or OBJECT element.
Copy Code code as follows:
var remotedoc = parent.frames[' Sideframe '].document; var remotecontainer = Remotedoc.getelementbyid (' content '); var Newpara = remotedoc.createelement (' P '); Newpara.appendchild (Remotedoc.createtextnode (' new content ')); Remotecontainer.appendchild (Newpara); Remove references remotedoc = null; Remotecontainer = null; Newpara = null;
Fast history browsing (history navigation)
Opera (and many other browsers) uses fast history browsing by default. When the user clicks back or forward, the status of the current page and the script in the page are recorded. When the user returns to the previous page, the page is immediately displayed as if it had never left the page. You do not need to reload the page and you do not need to reinitialize it. The script continues to run and the DOM is exactly the same as before leaving the page. This is a very quick response to users, and better performance for loading slower web applications.
Although Opera offers developers the means to control this behavior, it is best to keep the fast history browsing function as long as possible. That is, it is best to avoid actions that affect this feature, including the fading effects that disable form controls or make the content of the page transparent or invisible when submitting the form.
A simple workaround is to use the OnUnload listener reset to fade out or to enable the form control again. Note For some browsers, such as Firefox and Safari, forunload 事件添加监听器会禁用历史浏览。而在 Opera 中禁用提交按钮会导致禁用历史浏览。
Copy Code code as follows:
Window.onunload = function () {document.body.style.opacity = ' 1 ';};
Using XMLHttpRequest
This technique does not necessarily apply to every project, but it can significantly reduce the amount of data downloaded from the server, as well as the overhead of destroying and creating a scripting environment when overloading pages. Load the page normally at first, and then use XMLHttpRequest to download the smallest amount of new content. This JavaScript environment will always exist.
Note that this method may also cause problems. First, this method completely destroys history browsing. Although the information can be stored through an inline frame to solve the problem, it is clearly not in line with the intent to use XMLHttpRequest. Therefore, use sparingly, only if you do not need to fall back to the previous content. This method also affects the use of assistive devices (Assistivedevice), because the DOM has been changed, so it is best to use xmlhttprequest where it does not cause problems.
This technique also fails if JavaScript is unavailable or does not support XMLHttpRequest. The easiest way to avoid this problem is to use a normal link to point to a new page. Add an event handler that detects if the link is activated. The processor can detect whether XMLHttpRequest is supported and, if supported, load new data and block the link default action. When new data is loaded, it replaces part of the page, and the request object can be destroyed and the garbage collector is allowed to reclaim the memory resources.
Copy Code code as follows:
document.getElementById (' Nextlink '). onclick = function () {if (!window). XMLHttpRequest) {return true;} var request = new XMLHttpRequest (); Request.onreadystatechange = function () {if (request.readystate!= 4) {return;} var useresponse = Request.responsetex T.replace (/^[\w\w]*<div id= "container" >|<\/div>\s*<\/body>[\w\w]*$/g, ""); document.getElementById (' container '). InnerHTML = Useresponse; Request.onreadystatechange = null; request = NULL; }; Request.open (' Get ', this.href, true); Request.send (NULL); return false; }
Dynamically creating a SCRIPT element
Loading and processing scripts takes time, but some scripts are never used when they are loaded. Loading such scripts wastes time and resources and affects current script execution, so it is best not to reference this unused script. You can use simple load scripts to determine which scripts are needed and create script elements for only the scripts that you need later.
Theoretically, this load script can be added to the DOM by creating a SCRIPT element at the end of the page load. This works in all major browsers, but it may be more demanding for browsers, or even more than the script itself to load. And you might need a script before the page loads, so it's a good idea to create a script tag during page loading document.write
. Remember that you must escape the '/' character to prevent the current script from running:
Copy Code code as follows:
if (document.createelement && document.childnodes) {document.write (' <script type= ' text\/javascript ' src= ') Dom.js "><\/script>"); } if (window. XMLHttpRequest) {document.write (' <script type= ' text\/javascript ' src= ' xhr.js ' ><\/script> ');
location.replace()
Controlling history items
Sometimes you need to modify the page address by scripting. A common method is to location.href
assign a new address. This will add new history items and load new pages just as you would open a new link.
Sometimes you don't want to add new history items because users don't need to go back to the previous page. This is useful in devices with limited memory resources. Restores the memory used by the current page by replacing the history item. Can be location.replace()
implemented by means of a method.
Copy Code code as follows:
Location.replace (' newpage.html ');
Note that the page is still stored in the cache, still consuming memory, but much less than it was saved in history.