Question: Background
----------

I have been asked to write a script that will create a vertical scrolling parallax background effect for a project. My initial attempt looks a little something like this:

```
(function($){
    $.fn.parallax = function(options){
        var $$ = $(this);
        offset = $$.offset();
        var defaults = {
            "start": 0,
            "stop": offset.top + $$.height(),
            "coeff": 0.95
        };
        var opts = $.extend(defaults, options);
        return this.each(function(){
            $(window).bind('scroll', function() {
                windowTop = $(window).scrollTop();
                if((windowTop >= opts.start) && (windowTop <= opts.stop)) {
                    newCoord = windowTop * opts.coeff;
                    $$.css({
                        "background-position": "0 "+ newCoord + "px"
                    });
                }
            });
        });
    };
})(jQuery);

// call the plugin
$('.lines1').parallax({ "coeff":0.65 });
$('.lines1 .lines2').parallax({ "coeff":1.15 });

```

This code does give the required effect, but the bind on the scroll event is a real performance drain.

Question
--------

Part 1. How could I change my plugin to be more efficient?
Part 2. Are there any resources (books, links, tutorials) I can read to find out more?

Answer: 
You may try something like:

```
(function($){
    $.fn.parallax = function(options){
        var $$ = $(this);
        offset = $$.offset();
        var defaults = {
            "start": 0,
            "stop": offset.top + $$.height(),
            "coeff": 0.95
        };
        var timer = 0;
        var opts = $.extend(defaults, options);
        var func = function(){
            timer = 0;
            var windowTop = $(window).scrollTop();
            if((windowTop >= opts.start) && (windowTop <= opts.stop)) {
                newCoord = windowTop * opts.coeff;
                $$.css({
                    "background-position": "0 "+ newCoord + "px"
                });
            }
        };
        return this.each(function(){
            $(window).bind('scroll', function() {
                window.clearTimeout(timer);
                timer = window.setTimeout(func, 1);
            });
        });
    };
})(jQuery);

```

So the browser will not scroll the background if there are multiple scroll events is sequence. I wrote `func` outside the event handler to avoid the creation of a new closure in every event.
You should make the actual "scroll" event handler start a timer:

```
    var opts = $.extend(defaults, options);
    var newCoord = null, prevCoord = null;

    setInterval(function() {
      if (newCoord !== null && newCoord !== prevCoord) {
                $$.css({
                    "background-position": "0 "+ newCoord + "px"
                });
                prevCoord = newCoord;
       }
    }, 100);

    return this.each(function(){
        $(window).bind('scroll', function() {
            windowTop = $(window).scrollTop();
            if((windowTop >= opts.start) && (windowTop <= opts.stop)) {
                newCoord = windowTop * opts.coeff;
            }
            else
                prevCoord = newCoord = null;
        });
    });

```

Or something like that. This way, you're only doing the DOM manipulation at most 10 times a second.