Code Monkey home page Code Monkey logo

labjs's Introduction

IMPORTANT: This project is undergoing a complete 3.0 rewrite. Please follow the progress.

LABjs (Loading And Blocking JavaScript)

LABjs is a dynamic script loader intended to replace the use of the ugly, non-performant <script> tag with a flexible and performance-optimized alternative API.

The defining characteristic of LABjs is the ability to load all JavaScript files in parallel, as fast as the browser will allow, but giving you the option to ensure proper execution order if you have dependencies between files.

For instance, the following "<script> tag soup":

<script src="http://remote.tld/jquery.js"></script>
<script src="local/plugin1.jquery.js"></script>
<script src="local/plugin2.jquery.js"></script>
<script src="local/init.js"></script>
<script>
	initMyPage();
</script>

With LABjs becomes:

<script src="LAB.js"></script>
<script>
  $LAB
  .script("http://remote.tld/jquery.js").wait()
  .script("/local/plugin1.jquery.js")
  .script("/local/plugin2.jquery.js").wait()
  .script("/local/init.js").wait(function(){
      initMyPage();
  });
</script>

The differences between the two snippets is that with regular <script> tags, you cannot control their loading and executing behavior reliably cross-browser. Some new browsers will load them in parallel but execute them serially, delaying execution of a smaller (quicker loading) script in the pessimistic assumption of dependency on previous scripts. Older browsers will load and execute them one-at-a-time, completely losing any parallel loading speed optimizations and slowing the whole process drastically.

All browsers will, however, block other page resources (like stylesheets, images, etc) while these scripts are loading, which causes the rest of the page's content loading to appear much more sluggish to the user.

LABjs by contrast will load ALL the scripts in parallel, and will execute them as soon as possible, unless you express an execution order dependency in the chain by inserting .wait(). In addition, you can "couple" inline script logic to execute in the proper order in your chain as desired by passing a function to .wait(...).

It's important to realize that explicitly, separate $LAB chains operate completely independently, meaning there will be no explicit waiting for execution order between them.

NOTE: JavaScript execution is always still a single-threaded, first-come-first-served environment. Also, some browsers use internal loading queues which create implicit "blocking" on script execution between separate chains. Also, the 'AllowDuplicates:false' config option will de-duplicate across chains, meaning chain B can be made to implicitly "wait" on chain A if chain B references a same script URL as chain A, and that script is still downloading.

Build Process

There is no "official" build process or script. There is however "BUILD.md" which lists the steps that I take to prepare the LAB.min.js and LAB-debug.min.js files.

Configuration

There are a number of configuration options which can be specified either globally (for all $LAB chains on the page) or per chain.

For instance:

$LAB.setGlobalDefaults({AlwaysPreserveOrder:true});

would tell all $LAB chains to insert an implicit .wait() call in between each .script() call. The behavior is identical to if you just put the .wait() call in yourself.

$LAB.setOptions({AlwaysPreserveOrder:true}).script(...)...

would tell just this particular $LAB chain to do the same.

The configuration options available are:

  • UseLocalXHR: true/false (default true): use XHR to preload scripts from local (same-domain) locations
  • AlwaysPreserveOrder: true/false (default false): whether to insert an implicit .wait() call after each script load request... if turned on, prevents immediate execution of loaded files and instead executes all scripts in order
  • AllowDuplicates: true/false (default true): whether to inspect the current page and $LAB loading cache to see if the same script URL has already been requested and allow (true) or ignore (false) if so. NOTE: in v1.2.0 and before, this didn't work correctly across multiple $LAB chains, but as of v2.0, it works correctly.
  • CacheBust: true/false (default false): adds a cache-busting parameter (random number) to the end of a script URL
  • BasePath: {string} (default ""): a path string to prepend to every script request's URL

Protocol-relative URLs

Browsers have long supported "protocol-relative URLs", which basically means leaving off the "http:" or "https:" portion of a URL (leaving just the "//domain.tld/path/..." part), which causes that URL to be assumed to be the same protocol as the parent page. The benefit is that if you have a page that can be viewed in either HTTP or HTTPS, and your resources can (and need to be) served through either HTTP or HTTPS, respectively, you can simply list your URLs as protocol-relative and the browser will auto-select based on which protocol the page is viewed in.

LABjs now supports specifying such URLs to any script URL setting. NOTE: This is the recommended way to specify URLs for script resources if: a) the page you're serving can be viewed in both HTTP and HTTPS; and b) the script resource you're linking to can be accessed using the exact same domain/path with exception to the protocol.

A common example of such a resource is the CDN locations on the Google Ajax API, where popular frameworks like jQuery and Dojo are hosted. If you are linking to such CDN resources, you are strongly encouraged to change to using protocol-relative URLs, like "//ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" instead of "http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" or "https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js".

New in v2.0

  • AllowDuplicates now actually works across chains. This is very important for those who want to use multiple/nested $LAB chains as part of a shared-dependency loading mechanism.
  • Chains are now fully resumable, meaning you can save the return value from the last call to a chained function, and then use that saved value later as the starting point to resume the chain from where it left off.
  • Queueing is now built-in, with queueScript, queueWait and runQueue -- this important for those who want to build up the chain across multiple files or inline <script> elements (like in the CMS case), but want to defer starting the loading of the code starting until later (usually at the bottom of the page).
  • LABjs now supports noConflict (for rolling back to a previous version/copy of $LAB on the page) and sandbox (for creating a new pristine sandboxed copy of the current $LAB)
  • LABjs now relies on feature-testing for async=false and implicit/explicit "true preloading" (currently only IE, but in the spec process). Ugly/hacky "cache preloading" is now only used for "older webkit" (before March 2011 nightlies, etc), and even then, only for remote files.
  • For XHR preloading (only used in "older webkit" for local files, by default), to support better debugability, "// @sourceURL=..." is appended to the end of the code, to map the XHR/injected code to a real file name. Currently, browsers only support this for eval() (not script injection, like LABjs uses). It is hoped that browsers will soon support this annotation for their developer-tools.
  • Speaking of debugging, LABjs now supports a DEBUG mode (only if you use the source file, or if you use the LABjs-debug.min.js production file) and enable the "Debug" config option, which captures all the inner workings (and any errors in .wait() calls) to the browser's console.log, if present.
  • LABjs now supports a "CacheBust" config option, which will attempt to make sure all loaded scripts are forcibly loaded new on each page refresh, by auto-appending a random number parameter to each URL. This is really only practical/advised for DEV environments, where you want to ensure that the code reloads every time. Doing so in production would be really bad for user performance.*
  • As part of LABjs' rewrite, the code style is now significantly improved in readability (most "minification" hacks have been removed), and it's also using more memory-savvy code, such as far fewer closures. As a result, LABjs should run leaner and faster, if only by a little bit. The goal is to get LABjs out of the way so your scripts load and run as fast as possible.
  • "AppendTo", "UsePreloading", and "UseCachePreloading" options were removed as they are no longer useful. This is the only backwards-incompatible change (no actual API changes, just config), and the change should just cause older usage code to continue to operate as normal while ignoring the no longer supported options. Still, test your code carefully if you've been using either of those 3 config options before.

labjs's People

Contributors

getify avatar jdalton avatar prayagverma avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

labjs's Issues

Strange problem in Drupal

I'm integrating LABjs into Drupal 7. However I have a problem. Here are my code:
<script type="text/javascript" src="http://d7.ttcn/sites/all/libraries/labjs/LAB.min.js?lekatr"></script>
<script type="text/javascript">

</script>

<script type="text/javascript">
<!--//--><![CDATA[//><!--
$LAB.wait(function() {
jQuery.extend(Drupal.settings, {"basePath":"\/"},"overlay":{"... strip..."});
});
//--><!]]>
</script>

However, the code in jQuery.extend(...) has some problem. I don't know why. That line looks like never executed. I put an "alert(0)" before that line, it pops up, after that line, it does not.

Is that the correct way to do? I have a few more inline script block, I use $LAB.wait(...) for all of them.

Feature: load scripts as specified in a JSON manifest

What I envision for this feature is:

  1. Be able to specify a JSON manifest for all scripts that lists what scripts you want loaded, groupings, etc.
  2. Let this manifest either be in an external file, or in a dataURI.
  3. Also, let the manifest be able to be specified (and thus looked for) in the URL to load LAB.js, again as a dataURI format in the hash portion of the URL (to prevent unnecessary reloads of the LAB.js file itself when the script list changes).

Protocol independent scripts are not handled properly

In typical script tags, I can take the absolute path of

http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js

remove the protocol

//ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js

and use it in a script tag like so:

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>

This allows the browser to automatically assign the scripts protocol based on the protocol of the current page. This also works when creating script elements dynamically using JavaScript:

(function(d, t) {
    var g = d.createElement(t),
    s = d.getElementsByTagName(t)[0];
    g.async = true;
    g.src = '//ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js';
    s.parentNode.insertBefore(g, s);
})(document, 'script');

My issue is that, LABjs does not correctly handle these "protocol-less" URIs. If I try

$LAB.script("//ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js");

from example.com, it attempts to load

http://example.com///ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js

I'm sure this is an easy and simple fix. Thanks.

Ralph

Caching - how to turn off?

The JS files I load with LAB.js are cached and when I make changes they are not refreshed until the cache expires.
I tried turning off all caching with
$LAB.setGlobalDefaults({
UsePreloading: false,
UseLocalXHR: false,
UseCachePreload: false
});
but to no avail.

In Firebug the cached files appear grayed out: http://screencast.com/t/Z2YIr5M5o
and the cache tab tells me when the file expires and is reloaded from disk: http://screencast.com/t/IWVuGKeNnE
The times seem completely random, sometimes files are cached for a few seconds only, sometimes for five minutes.
What's going on here? How can I completely disable this caching?

2.0.2 broken in IE<=8

I'm not sure what the issue is but upgrading from 2.0.1 to 2.0.2 broke my scripts in IE 9.

Switching back to 2.0.1 makes everything work again.

Waits in medium-length chain don't always wait in Chrome 13.0.782.215 m

In Chrome 13.0.782.215 m, the waits in this chain don't always work properly:

$LAB
    .script("/Scripts/jquery-ui-1.8.16.custom.min.js")
    //.script("/Scripts/jquery.template.js")
    .script("/Scripts/jquery.query-2.0.1.js")
    // Knockout
    .script("/Scripts/knockout-1.2.1.js")
    // Common files
    .script("/Scripts/custom1.js").wait()
    .script("/Scripts/custom2.js").wait()
    .script("/Scripts/custom3.js").wait()
    .script("/Scripts/custom4.js").wait()
    // Page specific script
    .script("/Scripts/Pages/" + document.parsedPageName + ".js")
    // Google Analytics
    .script("/Scripts/google-analytics-loader.js")

I changed a few of the names and comments, but it's the same chain. Basically, custom1.js is not guaranteed to be done executing when the page-specific script starts. google-analytics-loader.js is a short script that loads Google Analytics.

Other browsers may also be affected.

Bug in path handling for IE6 and IE7

The canonical_uri() function improperly uses [0] style addressing of characters in a string, which doesn't work in IE6/IE7. The result is broken path handling if you use page-relative or domain-relative paths (absolute paths are fine AFAICT).

Should use charAt(0) instead of [0].

.wait() prevents further execution

I've been having a weird issue.
I have allow duplicates set to false.
I've defined a function that includes scripts on demand. The first time I call the function, it works perfect.
The second time, it should not load the files again since they've already been loaded, however, it doesn't execute the .wait(function(){}) after those .scripts.
If I delete the empty waits "wait()" after all those script loads it works fine, if I enable duplicates, it works as well.
Any thoughts would be appreciate.
Thanks!

load event not fired when script cached in IE 8

I have a script which I load in a LABjs load chain. This script contains a Prototype Event.observe:
Event.observe(window, 'load', function(){
//some code
});

This event is fired in Internet Explorer 8 when the script is fetch for the first time from the server. However subsequent calls have this script in the browser cache. The server is not hit and the event does not fire. Disabling caching on the browser side fixes the issue.

I'm using LABjs v1.0.2rc1, IE8.0.6001.18702 and Prototype 1.6.1.0.

After much searching I believe the problem described here in the comments is similar: http://api.jquery.com/load-event/

Consider preventing the LAB script from loading twice

I ran across a somewhat hard to debug problem caused by loading the LAB script twice. I had LAB included in the main page, which loaded some scripts.

Then, later on in the page lifecycle, I used jQuery.load to fetch another page, which also included LAB. When that version of LAB ran, it wiped out the previous $LAB global variable, which reset the registry of which scripts had been loaded. Then, the application reloaded other scripts, such as jQuery, which caused some other things to break...

Perhaps the LAB script could check if it has already been loaded before rebinding the $LAB variable. I'm thinking that it could set a special value $LAB.detect = 'j98hfahdsfasfkdvn' which it tests to see if the current $LAB variable is the lab loader, and if so, not overwrite it.

If you're ok with the change, but don't want to take the time to make it, I would be happy to fork and implement it.

Thanks!

Chris

Id

Hello,
Adding an option to add an id attribute to the script tag would be very helpful for loading templates, like jquery-tmpl, for example:


        .script({
            src: 'tmpl/row.tmpl',
            id: 'row-tmpl',
            type: 'text/x-jquery-tmpl'
        })

Object Returned by SetOptions is Missing queue methods

I don't know if this is by design or not, but it seems to me not. It appears as if you are starting a queued chain with setOptions(), the returned $LAB object contains only two methods: script() and wait(); it's missing the queueScript(), queueWait(), and runQueue() methods. E.g.:

$LAB
.setOptions({ AlwaysPreserveOrder: true, BasePath 'localhost/stuff/things' })
.queueScript('something.js');

It will run-time error on .queueScript (line 343 in LAB.src.js -- it eats the error in the try/catch, though, so things seem to be running fine, except no source files get loaded).

Strange delay between scripts in IE8

please see : http://www.webpagetest.org/result/110228_4D_3bb68ed39c46b859b9a84778f4c530a9/5/details/

I am loading LABjs using the async snippet and providing it a list of scripts to fetch. no ".wait()" .

But if you see the waterfall(Internet Explorer 8) linked to above, requests 8 to 13 - the ones injected by Labjs, have roughly 50ms gap between starting the requests. This is not a browser limitation since there is no other network activity going on to saturate the browsers limitations. Also, the cpu is also not busy during that time since no other script is being parsed/executed.

This gap between start of request is not seen on firefox and ie9 RC.

Couldnt find anything in the source which could be adding a settimeout for 50 or 60ms..

Support dependency loading from within loaded files

$LAB does a great job of loading dependencies specified in a script chain via the wait functionality, but this requires all of the dependencies to be known up front. The way we've built our application, the requested file is responsible for loading all of its own dependencies. That way, when the dependencies change for any of our classes, we don't need to change the loader request for that class throughout our application.

Is it possible to achieve this design pattern with LABjs?

Here's an example of the problem:

"Application":
$LAB.script("foo.js").wait().script("bar.js");

"foo.js":
$LAB.script("foo_fundamentals.js")

Here's what happens:

  1. $LAB loads "foo.js".
  2. During execution of "foo.js", $LAB is told to load "foo_fundamentals.js".
  3. "foo.js" finishes executing which triggers "bar.js" to begin execution.
  4. There is an error because "bar.js" depends on "foo_fundamentals.js", and "foo_fundamentals.js" hasn't finished loading.

Here's what I want (somehow):

  1. $LAB loads "foo.js".
  2. During execution of "foo.js", $LAB is told to load "foo_fundamentals.js".
  3. "foo.js" finishes executing, but does not trigger "bar.js" to begin loading because "foo.js" is still waiting for "foo_fundamentals.js".
  4. "foo_fundamentals.js" finishes loading and executing. Because all child dependencies of "foo.js" are now complete, "bar.js" begins executing.
  5. We all win.

I understand that moving dependency loading into the loaded files themselves kills the idea of asynchronous loading of those dependencies, but I find it makes the code far more maintainable. Also, in many cases I can still asynchronously load (and execute) some of the files, and I love LABjs's simplicity and performance for these cases.

As far as I can tell, JavaScriptMVC's Steal package allows me to do what I want, however, I prefer the LABjs API and I'd like to make it work if possible. See "Script Load Order" example on http://javascriptmvc.com/docs/steal.html#&who=steal

Error Callback in case of failed script loads

We are using labjs in conjunction with blockUI to block the page until all script ressources are loaded. This works fine, except that the page keeps being blocked if one of the script ressources couldn't be fetched. As some of the scripts are defined by third-party extensions of our framework, we prefer to unblock the page in this moment and display a useful error message.

Is there a possiblity to specify an error callback that gets executed if previous chain actions failed?

$LAB.wait dom.Ready for all ?

Hi,

I was wondering whether it's possible to implement a "global wait" function.

For example, in my masters pages - I load a bunch of scripts like

$LAB .script("jquery.min.js").wait() .script('myscript2').wait() .script('myscript3');

Then on another page I want to load a function like

$LAB.wait(function() { //my cool function });

However this doesn't work. What I am trying to do is basically make it act like a DOM.ready() type function ?

I noticed in HeadJS - which I previously used - it supported

head(function() { //blah }); [note: head(function... is a shortcut for head.ready(function..]

You can see the implementation for HeadJS here - https://github.com/headjs/headjs/blob/master/src/load.js#L102

Which basically calls the a function after all scripts have been loaded and the document is scriptable. Can LABJS support something like this as it would be immensely handy to have it ?

Perhaps

$LAB(function() { ...\\my favourite\\ });

or

$LAB.wait(function() { ... });

or

$LAB.ready(function() { ... });

AllowDuplicates not working?

Dear Kyle,

I suppose I found a bug when using AllowDuplicates parameters with false value.

I made a test suite: http://devidens.hu/dev/20110308/labjs-allowduplicates.html

I have a queue for chains in my php framework so I often define these chains redundant.

Like in the test suite I have two chains, with plugin1 and plugin2 with the same dependency
on the framework.

Chains in the test suite:

 $LAB.script(FRAMEWORK).wait().script('plugin1.js?r=' + r).wait(function() {
   rep('Inline function after plugin#1 has been executed!');
 });
 $LAB.script(FRAMEWORK).wait().script('plugin2.js?r=' + r).wait(function() {
   rep('Inline function after plugin#2 has been executed!');
 });

I know it's not the best behaviour, but it's simple and clean, and it works like a charm
with Firefox and Opera.

But not with IE and Chrome. It seems the wait() in the second chain simply skip the fact
that the framework hasn't loaded yet and immediately load and execute the plugin2.js.

I think the Firefox and Opera produce the expected result with AllowDuplicates = false, but
the IE and Chrome not.

I posted it to browsershots, so can check it there too... Maybe it helps. :)
http://browsershots.org/http://devidens.hu/dev/20110308/labjs-allowduplicates.html#

Would like be so kind to check my link?

Sincerely,

Wiktor

Google Maps Load Issue when using Mobile

I'm not sure if this is a bug or a mobile bug however this only occurs thus far using LAB js. I didn't find anything in relation to google maps in the git search.

My environment is XCode 4 + PhoneGap 1.0.

After the preload of the script below, I get a white screen of death for the mobile device. This happens on the script execution of Google maps. I don't have any other issue with Lab so far.

$LAB.script("http://maps.google.com/maps/api/js?sensor=false")

In this comment, James also mentions that it does not work, but I'm not sure what he means since I'm a bit new to script loaders.

http://www.bennadel.com/blog/1915-How-Javascript-Loading-And-Blocking-Works-By-Default.htm#comments_27022

enhancement: script callback

[editor: this comes from an email thread]

i see you can give json with src and such in the loading, but there is
one thing thats missing.

i have 3 scripts.

script 1 is a dependency of script 2 and script 3
script 2 and 3 are NOT depending on eachother.

i have some activation code for both script 2 and script 3

so what i propose to do is:

$LAB.script('1.js').wait()
.script( {src: '2.js', callback: function(){ 2_init(); } } )
.script( {src: '3.js', callback: function(){ 3_init(); } } )

1, 2 and 3.js would be loaded in parallel, when 1.js is executed, it
would execute 2 and 3 with equal priority, so, first to load, is
executed first. theres also a callback for when the script has been
executed.

my feature request, add callback for when a script is loaded.

--Kasper Sandberg

opts undefined

Firebug Exceptiontrace:
opts is undefined
processOpts(Object name=opts)LAB-1.0.2rc1.js (Zeile 313)
anonymous(Object name=opts)LAB-1.0.2rc1.js (Zeile 328)
anonymous()fLAB-0.2.js (Zeile 133)
anonymous()fLAB-0.2.js (Zeile 184)
game.html()game.html (Zeile 10) // loading first file here
[Break on this error] if (allOptssHASOWNPROPERTY && gl...) ? opts[k] : global_defs[allOpts[k]];\r\nLAB-1.0.2rc1.js (Zeile 313)

I'll try to fix it myself, if I succeed I post the fix.

wait() not working as expected

Hi,
I'm trying to use LABjs to load my scripts, but the .wait() is not working as I thought.
I'm using version 2.0.3 and testing with firefox 7.0.1

Here is my code:

$LAB.setGlobalDefaults({Debug: true})
.script("../js/mustache-min.js")
.script("http://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js").wait()
.script("../js/jquery.lightbox-0.5.min.js")
.script("../js/s3slider.js").wait()

Sometimes jQuery, which is loaded from an absolute url, is the last thing that gets executed.
Here is a page example that reproduces the problem:
http://rewind.sgconsulting.it/test-lab/

And here is a screenshot of my firebug console for the pageshowing the error:
http://rewind.sgconsulting.it/test-lab/test_LABjs.png

I also tried using //ajax.googleapis.com ... but the behavior is the same
Am I doing something wrong?

P.S. I sent an email directly to Kyle via Google+ a couple of days ago, but I think Google+ changed the formatting and it was unreadable so I'm reposting the issue here.

Add on ready functionality similar to $(document).ready(function(){});

Hi thank you for such a great plug-in I am using it at my company. Can you add a onready function that would be used in a similar way as we use document ready in jQuery something like


$LAB.ready(function(){
// do stuff...
});

This will allow inline scripting if needed at any point without having to be at the bottom of the page in a wait() function.

I created this temporary function for my company since they use a lot of inline JavaScript this because of the CMS architecture, and the many different pages that needs to be maintained


(function(llb){   
    var api = {     
        events: [],     
        registerEvent: function(e){
            api.events.push(e);
        },      
        executeAllEvents: function(){           
            var length = api.events.length;         
            for(var i = 0; i < length; i++){         
                if ( typeof api.events[i] === 'function' ) 
                    api.events[i]();
            }
        }
    }
    llb.ready = api.registerEvent;
    llb.run = api.executeAllEvents;
    window.llb = llb;   
})($LAB);

Then in the html I have this, where I run llb.run() at the bottom to execute the registered events


llb
.script("/includes/js/llbean/jquery.min.js").wait()
.script("/includes/js/llbean/jquery.cookie.min.js").wait(llb.run());

And now I can use something like this in any section of any page.


llb.ready(function(){
    alert($('#mio').attr('id'));
});

This was a very quick attempt to resolve some dependency issues on different pages (more than 1000 pages). I know you may come up with a better piece of code but the idea is that one can use a ready function that is triggered when javascript files are loaded and doesnt need to use the wait() function always.

I hope I am making any sense.

Thank you and thanks for contributing making the web faster. ;-)

JB

Strange situation

Hi.

We have used LabJS 1.2 in this method.

<script src="http://punbb.ru/include/js/min/punbb.common.min.js"></script>
<script>
    $LAB.setOptions({AlwaysPreserveOrder:false})
    .script("http://punbb.ru/extensions/pun_jquery/js/jquery-1.6.2.min.js").wait()
    .script("http://punbb.ru/extensions/fancy_jquery_addons/js/fancy_jquery_addons.min.js").wait();
</script>

LabJS in punbb.common.js

and in some pages i see error in console - jQuery not defined. Error come from fancy_jquery_addons.min.js which depends on jQuery. Error rare and sems to be happend when i click Back button in browser (Firefox 6)

In which cases jQuery may not loaded or be ready before fancy_jquery_addons.min.js loaded?

noConflict method will be very handy

Because more and more sites are starting to use LabJS it would be very handy to have noConflict in order to use in embedded widgets (something like disqus) and not to mess with LabJS defined on site.

confused by trailing wait()

I expected a trailing "wait()" (a-la example #8 in the labjs docs) to effectively block subsequent lines of code from executing until external javascript had loaded & run.

ie, assume "test.js" includes some code, with the final line being "console.log('test.js done now')"

console.log("before");
$LAB.script("test.js").wait();
console.log("after");

What i expected to see in the console was
before
test.js done now
after

What I actually see is:
before
after
test.js done now

I understand that I can get the behavior I want with:
$LAB.script('test.js').wait(function(){console.log("after"});

But it makes my code ugly & I'm still left with the question: what does a trailing wait() actually mean? And if it means nothing at all, why is it shown in example 8 of the docs?

Feature request: clearer documentation on multiple chains and on resuming chains

LABjs and the research you've put into it have been both useful and inspirational to me, but there are a couple of things I've come across that I think the documentation could stand to cover more explicitly.

I think it is implied in several places, and possibly explicity stated in an issue comment, that separate $LAB chains are independent of each other with regard to execution order, and that support for allowDuplicates=false across separate chains either was or is inconsistently . There is a comment on issue 2 that says multiple $LAB chains should be avoided. There are comments on issue 10 that indicate that storing and resuming a $LAB chain is not an explicitly supported use case and may or may not work, and that (at least for the use case in question) you didn't see why it would be desirable (I may have misinterpreted that part).

What I am requesting is that the main documentation address some of this more directly.

If separate chains are still recommended against, I couldn't find anything that seemed to say so in the documentation. To me, the separate existence of setGlobalDefaults and setOptions implies that multiple chains are just fine. Either way, I think at least a brief description of what happens with separate chains and maybe one example that uses them would be a good idea.

With respect to abandoning and resuming a chain, I think the need for actual documentation of whether it should work or not probably depends on how common this use case is--this was the reason I was looking for documentation on whether adding to a chain in multple places would work the way I expected.

The scenario is thus: on a website, a global header is used on all pages, and that header contains the script tag to load LABjs and the $LAB chain to load an event handling library and some default events. Additional events may need to be loaded depending on the actual page. A useful way to support this, if it works, is to store the $LAB chain that loads the event handling library in a (preferably namespaced) variable, so that additional .wait() calls can be added to it later. Thus, in header.php (yes, I use php), using my personal favorite event handling library as an example:

window.MyNamespace.EventLibChain = $LAB.script('//js/NWEvents.js')
    .wait().script('//js/NWMatcher.js')
    .wait(function(){
        //set up some events
    });

and then in page.php:

window.MyNamespace.EventLibChain.wait(function(){
    //set up some more events
});

I only went looking for something definite regarding whether this would work because I'm paranoid. Based on the documentation, I couldn't tell...the main reason I didn't just assume it would work was because I wasn't sure what I would expect to happen if .wait() were called on a chain when all preceding scripts had already not only loaded, but executed. Based on comments in issue 10, I gather that at least at one time, this use case was unreliable and unsupported, and that increasing support for it was not a major design goal. If my desired use case is something that a lot of people encounter (I don't know how to go about determining that), then I think it would be a good idea for the documentation to state whether it is expected to work, might work but sis unsupported or unreliable, is known not to work, or what have you.

Modules Management

any plans for modules management like the yui modules or dojo.
might be it could come as an extensions to the core LABjs

Feature: Fire a global error-callback on errors

This is a tricky one, and it's been asked before and I balked at it. But I can see that there's value in something like this, so we should investigate if there's a way to cleanly and reliably detect that the LABjs chain did or did not complete as expected.

It would likely need to be a per-chain option, specified at the beginning, which could only fire once, and once it fired, the rest of the chain would need to abort (if possible).

Images and $LAB

Hi,

I have a problem I am experiencing at the moment using the https://github.com/desandro/imagesloaded plugin with $LAB.

$.imagesLoaded() detects when images are loaded on a page however it isn't really working well with $LAB because $LAB fires immediately and can't detect when the images are finished loading on the page ?

How can I get the two to work well together, because at the moment - without DOM-Ready - $LAB fires when the images aren't ready [i.e. they're still loading] and therefore any image related code which requires images to be fully loaded doesn't bind to the images ?

Feature: fire a per-script callback if a "test" fails

Again, very tricky to do cleanly, but let's investigate if you could specify a "test" to be performed after a script finished executing, and if the test fails, then fire an error callback.

Not sure if it's possible to "abort" the chain at this point (which is what would be expected, likely), but at least you can know it happened.

Also, a variation of this might be to provide a timeout "test" where if the script takes too long, notify the callback of this potential "error".

DEBUG info in LAB.src.js

LAB.src.js 2.0 include START_DEBUG, END_DEBUG statements that not striped when use YUIcompressor 2.4.5.
We use own build system that work with non-minified version LAB.src.js.
I think all debug info must be striped from LAB.src.js OR must be exists Non-minified version without any debug.

Allow labelled scripts

Hey, first off awesome job so far. LABjs is a very cool piece of code.

One thing that's holding us back from using LABjs right now is the option to provide global labels to scripts and then reference them later in wait() statements. Some example code:

<script>
$LAB.script({'framework' : 'framework.js'});
</script>

... <div id='important'></div> ....

<script>
$LAB.wait({ 'framework' : function() {
    do_stuff()
});
</script>

This would be great because our do_stuff() function requires div#important to exist on the page. If the code above were implemented, I could be safe in assuming that both div#important and 'framework.js' were loaded before firing do_stuff(). Of course, you'd want the handlers to be queued so that multiple wait()s on 'framework' could be given and executed in the order they were added.

I think in general this would make LABjs a lot more flexible. What do you think?

Order of callbacks is incorrect

A chain like the following:

$LAB.script("test2.js")
.wait(function() {console.log('right after test2.js');})
.script("test.js");

The "right after test 2" doesn't seem to actually happen before "test.js" runs, for some browser scenarios (specifically seen in FF4+). Have to investigate. Might be related to use of setTimeout() for callback handling.

The new queueing system does not reserve order

I have this code:

<script src="/libraries/labjs/LAB.min.js"></script>
<script>
$LAB.setGlobalDefaults({AlwaysPreserveOrder:true});
$LAB.queueScript("/misc/jquery.js").queueWait();
</script>
<script>
$LAB.queueScript(function() {x = {};jQuery.extend(x, {test:1});});
</script>
<script>$LAB.runQueue();</script>

It does not work as expected (error: jQuery is undefined). Of course, when I remove queueWait() (because it is unnecessary where there is a AlwaysPreserveOrder option), it does not work, either.

How to check domready?

Hello,

Without LABjs, my script is something like this:
<script src="jquery.js"></script>
<script src="core.js"></script>
// in core.js there is
// List = new Array();
// $.domready(autorun())
// function autorun() {for each (List as f): run f();}
// and other things
<script>List.F1 = function() {...}</script>
<script>List.F2 = function() {...}</script>

With LABjs, it becomes
<script src="lab.js"></script>
<script src="core.js"></script>
<script>
$LAB.setGlobalDefaults({AlwaysPreserveOrder:true});
$LAB.script("jquery.js")
.script("core.js")
.script(List.F1 = ...)
.script(List.F2 = ...)
</script>

There are two problems:

  • With jQuery 1.3.2 and before: the classic problem, $.domready could be never detected in some case. However, I can add a .script(List.Fn = set a flag), then if flag is not set, code in $.domready(...) is not executed, we can execute it manually.
  • With jQuery 1.4+, it's better. But there is a new problem: I imagine that domready could fire right after .script(List.F1 = ...) and before .script(List.F2 = ...). Then when all functions in List are executed, F2 is not in that list. How can we handle that?

If I can change core.js, I'll remove the $.domready() and put it at the end of LABjs chain. I suppose that it's difficult to change core.js. Do you have a solution?

Strange IE errors when preloading more than 30 scripts in IE 8

When I try to preload more than 30 scripts in IE 8, i occasionally get strange javascript errors like "javascript error in line 30000000 - object expected" (this line count is certainly above the total line count of all my scripts). I don't get these errors when loading the scripts in a synchronous way.

Turning off the "UsePreloading"-options seems to improve the situation. Can be that this isn't lab.js fault at all (sometimes we access the page through our company proxy, which might defer the script downloads and cause a timeout in ie), but I would appreciate if lab.js offered
more debugging info for such cases (e.g. a timestamped log stored in the $LAB variable)

Loading CSS between wait() calls breaks on Firefox 3.6.8

I encountered follwing issue.

var asyncjs = $LAB
.script('some.file.js')
.wait(function() { alert('Scripts Loaded');});

// some html stuff

asyncjs.wait(function() { alert('first call');});
asyncjs.wait(function() { alert('second call');});

works fine. Now if we load some css via link:

and call again the function.

asyncjs.wait(function() { alert('third call');});

the third call only gets fired at own will.

Hanging image request delays DOM-ready

Hey,

Is it expected behavior that a hanging image request delays execution of DOM-ready code loaded by LABjs? I have a test page that requests an image that sleeps for 5 seconds and alerts on DOM-ready.

http://dl.dropbox.com/u/1125125/lab-js/LAB.html
http://dl.dropbox.com/u/1125125/lab-js/no-LAB.html

I found this post here, which touches on the problem and where you recommend adding a trailing .wait() method, but it didn't resolve the issue for me.
http://forum.jquery.com/topic/domready-and-loading-scripts-without-blocking-labjs

Tested in Chrome 11.0.696.68 and Firefox 4.0.1.

Thanks
Rob

Error interception.

Its posibble to add an interceptor (like .wait) for example .error, to detect loading issue, for example if my code load an external resource it could be fail and i need to notify that event.

sooo crazy ??

thks, good work with this lib =)

report run-time errors in .wait() callback handling

Currently, inside a .wait() callback, if a run-time error occurs, it is silently trapped and hidden (with a try/catch), so that the rest of the chain's processing can continue unabated. While I still think it's important to allow the chain to finish and not break early (I think that's more unexpected), I could investigate other ways of reporting run-time errors in a .wait().

Some options:

  1. Call console.error() or console.log() (if they exist, of course) with the error message from the .wait(). This will not preserve line-numbers or original context, but should at least help SOME in debugging of run-time errors in .wait() calls.
  2. Having some sort of chain-level "onerror" callback (specified in the global or per-chain options) which would receive the error object trapped by the try/catch.

I'm more in favor of 1 than 2, because it's much simpler. Feedback welcomed.

Any thought about Google Doubleclick

Well, I read and understand why LABjs is (currently) not for scripts that use document.write(). I'm looking forward to the next version of LABjs with DomWrite support. But is it possible now to solve a particular problem with Google Doubleclick for Publisher?

Google DFP requires that we put a few function calls in the place we want ads to appear. Those functions fetch data and display ads, which add extra delay. Can the problem be solved with LABjs?

I can't technically solve it, but I have a workaround. I put a DIV holder for each ad unit. Then at the page bottom, I put all ads call. Then I resize DIV holders to fit ad size, and move ads over the DIV holders. This way, the page layout "completes" first, then ads appear.

I'd love to see your idea about this.

lab.js 2.0 thinks leading-slash urls are relative

lab.js 2.0 seems to think that urls with leading slashes are relative:

---- /photos/index.html ----

$.LAB.script('/scripts/framework.js')


is resolved to /photos//scripts/framework.js (notice the double slash) instead of /scripts/framework.js

Dynamic CSS Loading

beging able to load css dynamically would also be a great addition to LABjs. might be could be add as an extension to LABjs incase some of them don't want this feature.

Script.aculo.us's own dynamic loader breaks in Chrome

Using LABjs to load Prototype and Scriptaculous from a CDN results sometimes in a blank page when using Chrome. The page is seen to load properly but after a fraction of a second the screen turns blank. The page is 'still there', that is inspecting the source reveals all the proper HTML. This behaviour is not consistent, sometimes it does work.

I tried setting AlwaysPreserveOrder to true, to no effect.
I tried moving off the CDN but that resulted in the dynamic libs (such as effects/builder/etc) not to be load at all. It would work when explicitly calling/loading these libs. The blanking would disappear. This makes me believe loading via XHR (UseLocalXHR) has some effect, which I do not know.

This behaviour can (sometimes as it's not consistent) be seen on our staging server at http://staging.delaagsterekening.nl.

The offending file is http://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js

Probably the solution is staring me in the face.

script_list.splice.call(script_list,splice_args);

there are two questions.

what difference between script_list.splice.call(script_list,splice_args) and script_list.splice(splice_args)?

$LAB.script(['test1.php',['test2.php','test3.php']]);

it's just load test1.php , if this statement is wrong ,why do that check the parameter is a array? line 386

Unable to use jquery validate plugin and $(document).ready(...) with LABjs

Hi,

I've been trying to use LABjs for some days now. It really does magic with normal script loading.
But, however, I've been having problems with validating a form in IE using jquery.validate plugin. :(

Below’s my code, please correct me wherever I’m wrong. Also, please accept my apologies for having to inspect my code
——

$LAB .script(“plugins/ckeditor/ckeditor.js”)
.wait(function(){eval(ckeditor_replace());}) // — assumption: ckeditor is independent of jquery and thus I think it can be loaded in parallel with jquery.

.script(“jquery.1.4.2.js”) // — assumption: the .script call above and this .script call load in parallel.

.block(function(){ // — .block here because all js files that are dependent on jquery are loaded in this block call.

$LAB 
.script(“hoverIntent.js”) 
.script(“superfish.js”) 
.wait(function(){ 
    $(“ul.sf-menu”).superfish({ animation: {height:’show’}, // slide-down effect without fade-in

            delay: 1200 // 1.2 second delay on mouseout
                }); // — this was initially in the documentReady block (for slide effect etc. in the jquery-based menu I’m using) – works fine. })

.script(“jquery.validate.js”)
.wait(function(){ // — assuming validate should run ONLY after jquery is loaded.

$(‘#form1′).validate({ // — this is the validate ruleset/messages
rules: {
competition_name:{required: true},
competition_exp_date:{required:true },
competition_prize:{required:true},
alt_tag:{required:true},
banner_link:{url:true}
},
messages: {
competition_name:{required: “Please input competition name”},
competition_exp_date:{required: “Please input competition expiry date”},
competition_prize: {required: “Please input competition prize”},
alt_tag: {required: “Please input babe banner alt tag”},
banner_link: {url: “Please input valid banner link”}
}
}); }) // — jquery validate plugin loaded here

.script(“jquery.datepick.js”) // — show a date picker (was on docReady initially) – works fine.
.wait(function(){ // — this was initially in $(document).ready block

var date= new Date();
var mindate = date.getFullYear() +”-”+ (date.getMonth()+1)+”-”+date.getDate();
$(‘#popupDatepicker’).datepick({ dateFormat: “yy-mm-dd”,
    closeAtTop: true,
    showOn: ‘both’,
    defaultDate: date.getFullYear() +”-”+ (date.getMonth()+1)+”-”+date.getDate(),
    minDate: mindate,
    rangeSelect: false,
    buttonImageOnly: true,
    buttonImage: ‘images/calendar.gif’
}); 
$(‘.successmsg’).slideUp(2000).fadeOut(’slow’); // — slides up a container containing a success msg – works fine. }) }); 

——

Intentionally I put a syntax error in javascript below the jquery validate codes and now I am able to see where the error is coming from:

It says “Object doesn’t support this property or method” inside jquery.validate.js – $(“.validated_form”).validate below:

$(document).ready(function(){
$(“.validated_form”).validate({
rules: { password: “required”,
confirm_password: { equalTo: “#password” }
},
messages:{
confirm_password:”Password confirmation did not match”
}
});
});

Hope this makes sense to you.

Thanks in advance.

Current minified version breaks in Safari

In Version 5.0.5 (6533.21.1) with AlwaysPreserveOrder on and UseLocalXHR off, if I do a very simple

$LAB.script([blah, blah, blah]).wait(callback)

LAB spirals into an infinite loop and never stops invoking callback.

I switched to the non-minified version to try and track down the source of the problem, and it went away. I think the minification may simply be a little overly aggressive for Safari's runtime, as this has resolved a couple other issues I had been experiencing with previous releases as well.

Enhancement: block rendering until loaded?

Im not sure if this is already possible, if so then pls advice...

The page

<script>
var $L = $LAB.script('http://evil-ad-server/adscript.js').wait(function(){
    bootstrap();
});
</script>

<div> Important stuff... </div>

<script>
$L.block_rendering(); //wait for ad server to finish bootstraping
ad_server_function_uses_doc_write();
</script>

<div id="footer">...</div>

ad_server_function_uses_doc_write() needs to execute exactly where it appears in the HTML since it is evil and uses document.write.

The goal here is to not override document.write as i previously did, rather to make sure that the bootstraping does not block the page rendering. This can be achieved by placing the bootstraping js below the important stuff... but im curious if i can use lab to start it sooner. Also, can i use LABjs as preloader? to download scripts and not execute them?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.