diff --git a/README.md b/README.md index aa21278..8fdf20b 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,27 @@ alameda supports [the requirejs API](http://requirejs.org/docs/api.html). It eve declares `requirejs`, to make passing the requirejs tests easier. alameda also has a good chance of becoming requirejs in a far-future requirejs version. +There are some differences with requirejs though: + +### require promise + +`require([])` will return a promise. + +### require errback + +alameda differs from requirejs in this case: + +```javascript +require(['something'], function(something) { + throw new Error('oops'); +}, function (err) { + //requirejs will call this errback function if the callback to require([]) + //throws. However, alameda does not, to match behavior with promises and their + //errbacks. If you want to catch this error in alameda: + //require([], function() {}).catch(function(err) {}); +}); +``` + ## Running tests The tests are pulled from almond and requirejs. All tests should be served diff --git a/alameda.js b/alameda.js index 63b34c3..0d59623 100644 --- a/alameda.js +++ b/alameda.js @@ -22,7 +22,8 @@ var requirejs, require, define; urlRegExp = /^\/|\:|\?|\.js$/, commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, - jsSuffixRegExp = /\.js$/; + jsSuffixRegExp = /\.js$/, + slice = Array.prototype.slice; if (typeof requirejs === 'function') { return; @@ -343,17 +344,19 @@ var requirejs, require, define; } //Support require(['a']) - callback = callback || function () {}; + callback = callback || function () { + // In case used later as a promise then value, return the + // arguments as an array. + return slice.call(arguments, 0); + }; //Complete async to maintain expected execution semantics. - asyncResolve.then(function () { - //Grab any modules that were defined after a - //require call. + return asyncResolve.then(function () { + //Grab any modules that were defined after a require call. takeQueue(); - main(undef, deps || [], callback, errback, relName); - }); - return req; + return main(undef, deps || [], callback, errback, relName); + }); }; req.isBrowser = typeof document !== 'undefined' && @@ -474,6 +477,8 @@ var requirejs, require, define; } function defineModule(d) { + d.factoryCalled = true; + var name = d.map.id, ret = d.factory.apply(defined[name], d.values); @@ -510,11 +515,25 @@ var requirejs, require, define; } } - function makeDefer(name) { + function makeDefer(name, errback) { var d = {}; d.promise = new Promise(function (resolve, reject) { d.resolve = resolve; - d.reject = reject; + d.reject = function(err) { + if (!name) { + requireDeferreds.splice(requireDeferreds.indexOf(d), 1); + } + if (errback && (!name && !d.factoryCalled)) { + try { + err = errback(err); + resolve(err); + } catch (e) { + reject(e); + } + } else { + reject(err); + } + }; }); d.map = name ? makeMap(name, null, true) : {}; d.depCount = 0; @@ -531,7 +550,7 @@ var requirejs, require, define; return d; } - function getDefer(name) { + function getDefer(name, errback) { var d; if (name) { d = hasProp(deferreds, name) && deferreds[name]; @@ -539,7 +558,7 @@ var requirejs, require, define; d = deferreds[name] = makeDefer(name); } } else { - d = makeDefer(); + d = makeDefer(undefined, errback); requireDeferreds.push(d); } return d; @@ -871,7 +890,7 @@ var requirejs, require, define; //It is possible to disable the wait interval by using waitSeconds of 0. expired = waitInterval && (startTime + waitInterval) < (new Date()).getTime(); - if (loadCount === 0) { + if (loadCount === 0) { //If passed in a deferred, it is for a specific require call. //Could be a sync case that needs resolution right away. //Otherwise, if no deferred, means it was the last ditch @@ -935,7 +954,7 @@ var requirejs, require, define; } calledDefine[name] = true; - var d = getDefer(name); + var d = getDefer(name, errback); //This module may not have dependencies if (deps && !Array.isArray(deps)) { @@ -946,7 +965,11 @@ var requirejs, require, define; deps = []; } - d.promise.catch(errback || delayedError); + // Only use delayedError if there is not an errback specified. If + // if there is an errback, it means it will handle the error. + if (name && !errback) { + d.promise.catch(delayedError); + } //Use name if no relName relName = relName || name; @@ -1019,6 +1042,8 @@ var requirejs, require, define; if (!name) { check(d); } + + return d.promise; }; req = makeRequire(null, true); @@ -1162,7 +1187,7 @@ var requirejs, require, define; topReq.contexts = contexts; define = function () { - queue.push([].slice.call(arguments, 0)); + queue.push(slice.call(arguments, 0)); }; define.amd = { diff --git a/tests/all.js b/tests/all.js index 8a32628..6b0f12e 100644 --- a/tests/all.js +++ b/tests/all.js @@ -22,3 +22,4 @@ doh.registerUrl("specialDeps", "../specialDeps/specialDeps.html"); doh.registerUrl("hasOwnPropertyTests", "../hasOwnProperty/hasOwnProperty.html"); doh.registerUrl("dataMainBaseUrl", "../dataMainBaseUrl/dataMainBaseUrl.html"); doh.registerUrl("emptyRequire", "../emptyRequire/emptyRequire.html"); +doh.registerUrl("promiseRequire", "../promiseRequire/promiseRequire.html"); diff --git a/tests/promiseRequire/app.js b/tests/promiseRequire/app.js new file mode 100644 index 0000000..5a623d4 --- /dev/null +++ b/tests/promiseRequire/app.js @@ -0,0 +1,7 @@ +define(['bar'], function (bar) { + return { + name: 'app', + bar: bar + }; +}); + diff --git a/tests/promiseRequire/bar.js b/tests/promiseRequire/bar.js new file mode 100644 index 0000000..9d1559b --- /dev/null +++ b/tests/promiseRequire/bar.js @@ -0,0 +1,7 @@ +// bar.js +define('bar', function(require) { + return { + name: 'bar' + }; +}); + diff --git a/tests/promiseRequire/promiseRequire.html b/tests/promiseRequire/promiseRequire.html new file mode 100644 index 0000000..07c7e8f --- /dev/null +++ b/tests/promiseRequire/promiseRequire.html @@ -0,0 +1,105 @@ + + +
+Test require([]) returning a promise. + More info.
+ +Check console for messages
+ +