Code optimization and organization in Javascript / jQuery
2015-10-07 20:38
756 查看
This article is a combined effort of Innofied Javascript developers Puja Deora and Subhajit Ghosh)
We have been working on a project for past 8 months (ongoing). Over the course of this project, we have learnt that small tweaks to general coding practices goes a long way in improving the overall performance of the code.
In this article, we will discuss some of these common JavaScript practices and tricks to code optimization that improve the overall efficiency and performance of our code. Most of the techniques described below are fairly intuitive once we grasp the underlying problem or overhead.
Code 1
JavaScript
Code 2
JavaScript
The problem with code 1 is that for every statement, jQuery has to search the entire DOM and find the element and after that execute the attached function on it. But when chaining is used, jQuery has to find the element only once and it will execute all the attached functions one by one. So, Code 2 is optimized.
Code 1
JavaScript
Code 2
JavaScript
The second method is better as it allows us to bind events to dynamic HTML elements.
That’s why global scopes are slow. They are worst-case scenarios for object lookups.
Example Code
JavaScript
Here when the function is invoked referencing outer is slower than referencing inner, which is slower than referencing efficient.
Math.floor() and Math.round() for arithmetic operations
(new Date()).getTime() for timestamps
String.prototype.match() and String.prototype.replace() for regexes
parseInt(n, radix) for changing numeral systems
=== instead of == for faster type-based comparison
instanceof for checking type up the hierarchy
& and | for bitwise comparisons.
&& and || operators instead of simple if-else statements.
JavaScript
As discussed in point number 3 above, this takes longer time as the closure variables (in this example, me) are held at a higher level of the scope chain. We can improve this by binding the correct scope to our asynchronous function when we call them. For example,
JavaScript
Method 1
JavaScript
Method 2
JavaScript
When we define a class method using prototype (Method 2), only one copy of the function is created which is shared by all object instances of the class. The context within the function will refer to the instance which calls it. Hence, it is a more efficient way of defining methods than using ‘this’.
Method 1
JavaScript
Method 2(Optimized)
Method 1
JavaScript
Method 2
JavaScript
When working with similar cases as described in the above example, there is another way that’s far more efficient than using jQuery’s CSS method. We could add a new class to the DOM element and write the style changes against that class in our CSS file.
Efficient Method
JavaScript
Method 1
JavaScript
Method 2(Optimized)
Method 1
JavaScript
Method 2
JavaScript
When we concatenate some substrings to create a larger string, all intermediate results are stored in temporary variables. Therefore the second method is optimized as it requires lesser memory for execution.
Method 1
Method 2(Optimized)
Let’s consider the example of data structure Stack. We define the push method for Stack as follows:
JavaScript
Since we are dealing with Stack, ‘push’ will be an integral method for any implementation. We would be referring it repeatedly and wouldn’t want anything to modify, overwrite or delete our definition. This can be controlled by defining it as follows:
JavaScript
Another advantage of working with defineProperty is that we can use the getter/setter methods to get or set the value for an object property.
JavaScript
Here the get method is called implicitly when we refer to square.area. Read here for more information on defineProperty.
These are some of the many best practices that we have found effective. We hope you find these helpful. Do comment and share optimization techniques from your experience. Happy coding.
We have been working on a project for past 8 months (ongoing). Over the course of this project, we have learnt that small tweaks to general coding practices goes a long way in improving the overall performance of the code.
In this article, we will discuss some of these common JavaScript practices and tricks to code optimization that improve the overall efficiency and performance of our code. Most of the techniques described below are fairly intuitive once we grasp the underlying problem or overhead.
1. Chain of Command
JQuery Chaining is a very powerful feature of jQuery that connects multiple functions and events on a particular selector. The following example shows how chaining makes our code shorter and faster.Code 1
JavaScript
1 2 3 | $('.element').removeClass('old'); $('.element').addClass('new'); $('.element').show(); |
JavaScript
1 2 | $('.element').removeClass('old') .addClass('new').show(); |
2. Event Management
Using jQuery, we can attach events to an element in the following two ways:Code 1
JavaScript
1 | $(‘selector’).click(function() {}); |
JavaScript
1 | $('parent-selector').on('click', 'selector', function callback(){}); |
3. Out of Scope
Every time we define a new function and create a new closure, javascript adds a level to its scope chain. When the browser resolves properties, each level of the scope chain must be checked. In other words, JavaScript looks at the first item in the scope chain, and if it doesn’t find the variable, it bubbles up the chain until it hits the global object.That’s why global scopes are slow. They are worst-case scenarios for object lookups.
Example Code
JavaScript
1 2 3 4 5 6 7 8 9 10 | var outer = 'outer'; var sampleFunction = function() { var inner = 'inner'; return function() { var efficient = 'efficient'; outer; inner; efficient; }; }; |
4. Power of Native functions and constructs
Its good to be aware of native constructs provided by ECMAScript as it saves us from having to write our own algorithms. Some commonly used constructs are-Math.floor() and Math.round() for arithmetic operations
(new Date()).getTime() for timestamps
String.prototype.match() and String.prototype.replace() for regexes
parseInt(n, radix) for changing numeral systems
=== instead of == for faster type-based comparison
instanceof for checking type up the hierarchy
& and | for bitwise comparisons.
&& and || operators instead of simple if-else statements.
5. Use ‘this’ the right way
In case of using asynchronous code blocks, a common practice is to use global or closure variables to refer to object properties outside the scope of the asynchronous block. For example:JavaScript
1 2 3 4 5 6 7 | var Test = function() { var me = this; this.x = 5; return function() { console.log(me.x); }; }; |
JavaScript
1 2 3 4 5 6 7 | var Test = function(callback) { this.x=5 callback.call(this); }; Test(function(){ console.log(this.x) }); //output is 5 |
6. Define class methods with prototype
We can define a method of a class in the following two ways:Method 1
JavaScript
1 2 3 4 | MyClass = function() { var privateVariable; this.privilegedMethod = function() {}; }; |
JavaScript
1 | MyClass.prototype.publicMethod = function() {}; |
7. Avoid referencing Object properties
Reading an object property takes longer than reading a variable. It would do us good to remember this when we are referring to some object property frequently. We could improve our code’s performance by storing this property in a temporary variable.Method 1
JavaScript
1 2 3 4 5 6 7 | var stringFill1 = function(string, count) { var result = ''; while (result.length < count) { result += string; } return result; }; // Execution time for this function is 47.297 microseconds |
1 2 3 4 5 6 7 | var stringFill1 = function(string, count) { var result = ''; while (count-- > 0) { result += string; } return result; };// Execution time for this function is 27.68 microseconds |
8. Batch style updates
In case we need to make several style updates for a particular DOM element, it is better to apply those changes at once instead of applying them one by one. This prevents the UI from being rendered repeatedly. In the following example, Method 2 is better than Method 1.Method 1
JavaScript
1 2 3 4 5 6 7 | // This will incur 5 screen refreshes jQuery('.element') .width(600) .height(400) .css('position': 'absolute') .css('top', '200px') .css('left', '200px'); |
JavaScript
1 2 3 4 5 6 7 8 | // Let jQuery handle the batching jQuery('.element').css({ width: '600px', height: '400px', position: 'absolute', top: '200px', left: '200px' ); |
Efficient Method
JavaScript
1 | jQuery('.element').addClass('prefferedClass'); |
9. Build DOM ‘off-line’
Every time we add a DOM element to the UI, it refreshes the entire screen. We can improve that by building DOM ‘off-line’ and adding it to the UI at once.Method 1
JavaScript
1 2 3 4 | var list = $('<ul></ul>'); $(list).append('<li>Sample1</li>'); $(list).append('<li>Sample2</li>'); $(list).append('<li>Sample3</li>'); |
1 2 3 4 5 6 | var list = $('<ul></ul>'), htmlBuffer=[" <li>Sample1</li>", "<li>Sample2</li>", "<li>Sample3</li>"].join(""); $(list).append(htmlBuffer); |
10. Many-to-one
After we have completed developing our .js files, we can pass them through a javascript minimizer tool (such as JsMin) which removes the unnecessary code blocks (read comments and white spaces). This way, we just have to add one minified script file to our HTML. Its better because a request to fetch one comparatively larger file executes faster than the request to fetch multiple smaller files.11. Dependency Manager
The idea is to load modules to the browser as and when they are required. When a user requests for a page, the first thing they notice is the HTML content. The functionality is required only after they get familiarised with the layout. We can achieve this by working with dependency managers likeRequireJS or Browserify.12. Better String concatenation
String concatenation causes major problems with Internet Explorer 6 and 7 garbage collection performance.Method 1
JavaScript
1 | var longString = "This is a long String" + "So the question is how to concatenate a string" + "in a better way"; |
JavaScript
1 | var longString = ["This is a long String" , "So the question is how to concatenate a string" , "in a better way"].join(" "); |
13. Indexing power of Javascript Objects
Lengthy if-else blocks can be reduced to a single line of code. All we need to do is create a Javascript object to map each condition to a function name. It works in a manner similar to HashMap data structures. The following example illustrates this technique.Method 1
1 2 3 4 5 6 7 | if(action === 'add'){ onAdd(); }else if(action === 'edit'){ onEdit(); } else if(action === 'delete') { delete(); } |
1 2 3 4 5 6 | var actions = { 'edit' : 'doEdit', 'delete': 'delete', 'add': 'onAdd' }; actions[action](); |
14. Primitive vs Reference variable types
Primitive variables and reference variables behave differently when we pass them as parameters for a function call. A copy of primitive variables is created in the function whereas only a light-weight reference is passed to the new function, in case of reference type variables. So whenever we need to pass a few parameters to a function, it is better to create a config object and pass a reference to that instead.15. Use defineProperty/defineProperties
defineProperty gives us more control over the behaviour of object properties that we define. We get options to- prevent further modification or deletion after an object property has been defined, control whether the property shows up during enumeration or not and so forth.Let’s consider the example of data structure Stack. We define the push method for Stack as follows:
JavaScript
1 2 | function Stack(){}; Stack.prototype.push = function(x){/* */} |
JavaScript
1 2 3 4 5 6 7 8 9 | function Stack() { }; Object.defineProperties(Stack.prototype, { push: { writable: false, configurable: true, value: function (x) { /* ... */ } } }); |
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 | var square ={ width: 20, height: 30 }; Object.defineProperty(square, 'area', { get: function(){ return this.width*this.height; } }); console.log(square.area); |
These are some of the many best practices that we have found effective. We hope you find these helpful. Do comment and share optimization techniques from your experience. Happy coding.
相关文章推荐
- js的链式调用-如何实现类似jquery的链式调用
- jQuery源码分析之closest,has,addBack,addSelf,add方法
- jQuery Mobile基础03----jQuery Mobile Widgets-button
- jQuery Mobile基础02----jQuery Mobile Widgets-page(跳转效果
- 简单的百度预测搜索功能(php+jQuery+js+ajax)
- 报表增删改开发过程中知识整合
- jquery 获取下拉框值与select text
- 7款jQuery图片轮播滑动插件
- 分享15款为jQuery Mobile定制的插件
- JQuery中使用a-jax局部书刷新验证表单
- domino显示二维条形码
- domino 显示海康威视摄像头内容
- Javascript、Jquery获取浏览器和屏幕各种高度宽度
- 很容易学习的JQuery库 : (四) 效果
- jQuery源码分析之parents,parentsUntil,next,prev,nextAll,prevAll,nextUntil,prevUntil,siblings,children
- springMVC框架下JQuery传递并解析Json数据
- jQuery Mobile基础01----jQuery Mobile-使用jQueryMobile
- jQuery 下拉框常用用法
- jQuery基础
- jQuery动态添加删除select项