This project is read-only.

Async Resources

Topics: Core
May 17, 2013 at 4:41 PM
Edited May 17, 2013 at 4:42 PM
Asynchronous resource loading using scripts such as yepnope.js should be baked in. That way, we can use the existing ResourceManager API to Require and Include scripts, but with additional options, e.g. .Async().

Example usage:
Example output:
<script type="text/javascript'>
Loaders such as yepnope.js support advanced options, such as conditions and browser prefixes. The current Orchard Resources API could be mapped into those options.

I'm maintaining a fork here for prototyping:

An issue for this feature request has been created here:

This thread is intended to discuss architectural design decisions.
May 17, 2013 at 4:47 PM
Currently I'm hardcoding yepnope.js in. A couple of questions I have myself:
  1. Should this script be part of Orchard.Core/Common/Scripts, next to html5 and base.js?
  2. Should the script loader system be pluggable? That is, should a developer be able to 'swap out' yepnope.js with his own implementation?
May 18, 2013 at 9:28 AM
I think there are lots of nice ways this can be implemented.

I did something similar to this when I needed some scripts to be brought in asynchronously but not always.

I made it so that when I do Script.Require(), I can add .Async() there and have an alternate shape used instead of the default script tag.

My method was to modify the StaticFileBindingStrategy so that the call to WriteResource is actually done in the concrete subclass.

Then using an additional subclass together with some shape methods and extension methods, we can pull this off.

It's probably best for me to show you what I did. I can't give the code directly because it belongs to the company i wrote it for but i can write it again in a clean room so it wont be exactly the same and then contribute it.
May 18, 2013 at 3:57 PM
Edited May 18, 2013 at 3:59 PM
+1 This is a great idea! It would definitely be a really useful core feature.

My 2 cents:
  1. It seems like extensibility/pluggability is a must-have if we're going to put this into the core.
  2. We should use the most common library for the base implementation (I'd go with RequireJS instead of YepNope).
  3. Handling dependencies
    • how would we manage script dependencies between async- and non async-loaded scripts?
    • should all dependent resources load as Async when a given resource is loaded this way?
    • what should happen when you have the same resource required as async and non-async in different places? Should async take precedence?
I would also add a way to inject code to execute after a given resource is loaded. Most of the script loaders have a way to do that.
May 19, 2013 at 12:01 PM
harmony7 wrote:
It's probably best for me to show you what I did. I can't give the code directly because it belongs to the company i wrote it for but i can write it again in a clean room so it wont be exactly the same and then contribute it.
Yes, please create a fork so we can have a look at it. Thanks!
May 19, 2013 at 12:17 PM
Edited May 19, 2013 at 12:18 PM
@Piotr: Excellent points! I actually counted 6 cents. :)

Absolutely, each theme should be able to decide which loader to use. Since AsyncResources is a shape method, it can be easily overridden in the theme. For example, the following view could be added and tweaked:

@using Orchard.UI.Resources
    var resources = (IEnumerable<ResourceRequiredContext>) Model.Resources;
    var defaultSettings = (RequireSettings) Model.DefaultSettings;
    var appPath = (string)Model.AppPath;
    var paths = resources.Select(x => {
        var url = x.GetResourceUrl(defaultSettings, appPath);
        if (VirtualPathUtility.IsAppRelative(url)) {
            url = VirtualPathUtility.ToAbsolute(url);
        return url;
<script type="text/javascript">
    yepnope(['@Html.Raw(String.Join("',\r\n'", paths))']);
So you say RequireJS is more commonly used? What do you think are the pros and cons when you compare RequireJS with YepNope?

Good points on handling dependencies, and it needs more thinking and testing and tinkering.
I imagine that if a synchronously loaded script has a dependency on an asynchronously loaded script, that script configured to load synchronously (the default) should be loaded asynchronously as well, otherwise it will likely break.
I would say that async should take precedence if the same resource is being included twice. Do you foresee any issues with that?
May 19, 2013 at 4:18 PM
Edited May 19, 2013 at 4:18 PM
All right guys, I put together some code based on a similar mechanism as what I did in the past, and also adapted it to using yepnope to make it load scripts asynchronously. I have pushed it, as well as a small demo, in my fork here (please look at the recent 3 commits):

I added the RequireSettings functionality and dependency tracking for Async to core, but left the script loading up to a module so that anyone can provide their own and use whatever loader they would like (And if none is enabled, the scripts marked as async are just loaded synchronously in their natural safe order).

The YepnopeAsyncScripts project provides an example of such an implementation, using yepnope. The example does use yepnope because I was influenced by this discussion, but you will see it is very easily swapped out for another since it's in a module.

Additionally, the YepnopeAsyncScriptsDemo project provides a test page and some example resources for experimentation. Once you enable the demo project, it can be accessed at /YepnopeAsyncScriptsDemo/TestPage and you can view the source and/or network traffic to see the async loading. The view file for this just has a bunch of Script.Require lines and is designed to be experimented with.

The two projects can be enabled independently to show what happens when you use the Async settings without an async loader module enabled.

Let me know what you think.
May 19, 2013 at 4:20 PM
By the way, if you are wondering why the async scripts show up twice in network traffic, it's due to the way yepnope is designed:
May 19, 2013 at 4:41 PM
As for the dependencies discussion, I gave it some thought and came to these conclusions:
  1. Conflicting synchronicity declarations should give non-async precedence, because non-async scripts can have other non-async scripts that depend on them. For this reason it is only safe to honor the "Async-ness" when, at the end of the dependency tracking, the script is determined to still have both ResourceSynchronicity.Asynchronous and ResourceLocation.Unspecified.
  2. Dependency scripts have their synchronicity affected by the settings of their dependent scripts.
    2a. If A is a dependency of B, and B is not marked as Async(), then that means B will load as a normal script tag. And since the dependency means A should be loaded before B, regardless of whether A is marked Async(), A should load as a normal script tag.
  3. Explicit and implicit references should probably matter.
    3a. For example, if I have inline script on a view with using(Script.Foot()) or whatever along with a Script.Require, then the inline script could hold a dependency on the Required script. Therefore, it is not safe to assume that the Required script can be safely loaded asynchronously (or we risk breaking lots and lots of sites out there).
    3b. However, if I bring in just jQuery UI using Async, and jQuery UI depends on jQuery, and there are no other explicit references to jQuery, then jQuery is an implicit reference. Since the user assumes jQuery UI is Async, then it should also be safe to bring in the other implicit references asynchronously as well.
    3c. If scripts A and B each depend on Z, and a view refers to A as Async but B as not (with no explicit reference to Z), then B will prevent Z from loading synchronously. This means that when an implicit reference is being brought in by conflicting synchronicity settings, then non-async should win.
May 19, 2013 at 4:47 PM
Edited May 19, 2013 at 4:47 PM
Injecting code to execute after given resource is something we definitely have to think about, because it's not safe to call anything in the asynchronously-loaded scripts until then. It might be something similar to the using(Script.Foot()) syntax. Since the script will be tied to one or more individual resources, maybe something like this?
  var s1 = Script.Require("abc").Async();
  var s2 = Script.Require("def").Async();

// Should probably take a params RequireSettings[].  Any non-Async scripts in this list can be ignored.
@using(Html.AfterLoad(s1, s2)) {
  /* Script goes here */
Jul 11, 2014 at 4:06 AM
@harmony - I agree with what you said on the dependencies. I am going to take your fork and try it out - thank you.
Jul 12, 2014 at 9:48 AM
I took harmony's fork as a start, and added some modifications to support RequireJS as well (I didn't include a yepnope.js implementation). Essentially, we need to be able to completely override the way a collection of resources are rendered, so that in the case of RequireJS a script body could be rendered based on the resources.
The changes are pushed to the feature/asyncscripts branch (on the main fork).