Skip to content

Delayed definition of modules (asynchronous exports) #17

@ghost

Description

AMD is not really asynchronous

The only thing which is asynchronous is the loading of dependencies.


But the definition itself is not really asynchronous. According to the specification the module is defined when factory function is executed and exports is detected.


Bad example:
A module depends on a module which provides only a method to call your callback on a delayed ready state, but your module also wants to provide a ready state.

And what if an other module depends on my example module?
We will run in a crazy chain of such modules ...

define(["domReady"], function (domReady) {
    var isReady = false,
        cbStack = [];

    domReady(function () {
        isReady = true;
        while (cbStack.length >= 1) {
            (cbStack.unshift())();
        }
    });

    return function (callback) {
        if (isReady) {
            callback();
        } else {
           cbStack.push(callback);
        }
    });
});

Asynchronous definition

So the module should be able to say: I'm done.

The defined status of a module should be asynchronous according to the factory function.


The idea of an asynchronous definition is, to delay the detection of exports. If the detection of exports is done, the definition of the module is done too.


Two known implementations

Currently there are 2 pull requests on RequireJS with implementations of asynchronous exports. Both are closed because we should discuss this on the amdjs-api first.


@demurgos - #1078 - A new distinct resolution dependency named delay

define(["delay"], function (delay) {
    var Module = {};

    setTimeout(function () {
        delay(Module);
    }, 1000);
});

pro:

  • simply to use, just set this dependency, the exports is defined as asynchronous

contra:

  • the name of a new distinct resolution dependency could cause conflicts in existing projects
  • current implementation doesn't take care for exports priority

@evanvosberg - #1075 - A new property on the module dependency

define(["module"], function (module) {
    var asynchronousExports = module.async(),
        Module = {};

    setTimeout(function () {
        asynchronousExports(Module);
    }, 1000);
});

pro:

  • low risk of conflicts in existing projects by providing a method on the existing distinct resolution dependency module

contra:

  • one more call within the factory function to get the asynchronous exporter

Priority of different exports (low - high):

If factory is a function:

  • if ["exports"] is in the dependencies list exports will be exported
  • if ["module"] is in the dependencies list module.exports will be exported, note that module.exports and exports are the same object if module.exports is not reassigned within the factory
  • if the call of asynchronousExports hands over one parameter (an object, function, or any value that coerces to true) it will be exported
  • if factory function returns a value (an object, function, or any value that coerces to true) it will be exported

If factory is an object

  • factory itself will be exported

Indication of support

Additional property on the define.amd object. Name should be discussed, here is one suggestion.

define.amd = {
    async: true
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions