cujojs / curl

curl.js is small, fast, extensible module loader that handles AMD, CommonJS Modules/1.1, CSS, HTML/text, and legacy scripts.
https://github.com/cujojs/curl/wiki
Other
1.88k stars 216 forks source link

Returning a promise instead of a value at the end of define() #89

Closed mbrowne closed 12 years ago

mbrowne commented 12 years ago

In the documentation, it's specified that you can use a promise instead of a function when defining modules?

define(['dep1', 'dep2', 'dep3' /* etc */], promise);

How would that work?

Also, in a blog post, John shows an example where a promise is returned at the end of a function passed to define():

// a module to convert some jsonp-based resources to AMD:
define(['require', 'mylib/Deferred'], function (req, Deferred) {
    var promise = new Deferred();
    req(['cdnlib/template?jsonp=define', 'cdnlib/data?jsonp=define'],
        function (template, data) {
            promise.resolve({ template: template, data: data });
        }
    );
    return promise; // could also use a callback function
});

http://unscriptable.com/2011/09/22/amd-module-patterns-singleton/

...but I haven't been able to get this to work (I tried both curl/_privileged and the when library to create the promise.)

This thread over at requirejs describes the goal pretty well: https://github.com/jrburke/requirejs/issues/253

I think that a simple check for a 'then' function as proposed there would be a useful solution to allow conditional loading of other modules within a module definition. For example, I'm currently working on a class that has a factory method to instantiate the appropriate subclass, but which subclass it should be isn't known until the code in the parent class can do some browser detection. I can explain my particular scenario in more detail if that would be helpful.

Thanks

unscriptable commented 12 years ago

Dang. I didn't realize that example is still in the README.

I had ripped out that functionality until we got some consensus in the AMD community. There is a way to make this work, but it involves a bit of trickery. (I just used this trick a few days ago.) The basic concept is to take advantage of the plugin API. Here's how it goes:

define(/* 'my/_subclass', */ ['when'], function (when) {
    return when.defer(); // or something more interesting :)
});
define(/* 'my/subclass', */ ['async!./_subclass'], function (_subclass) {
    return _subclass;
});
define(/* 'my/parent', */ ['my/subclass'], function (subclass) {
    // do something cool
});

So the trick is to hide the plugin in an intermediary wrapper module. Can you make this work in your project?

If not, maybe we can take a deeper look.

-- John