Skip to content

Commit

Permalink
Fixes #8, require([]) returns a promise
Browse files Browse the repository at this point in the history
  • Loading branch information
jrburke committed Jan 30, 2016
1 parent 16eab26 commit 52af527
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 16 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

This comment has been minimized.

Copy link
@jrburke

jrburke Jan 30, 2016

Author Member

Thinking more about it, I agree, filed #11 to fix it, should have an update out in the next day or two.

//require([], function() {}).catch(function(err) {});
});
```

## Running tests

The tests are pulled from almond and requirejs. All tests should be served
Expand Down
57 changes: 41 additions & 16 deletions alameda.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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' &&
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand All @@ -531,15 +550,15 @@ var requirejs, require, define;
return d;
}

function getDefer(name) {
function getDefer(name, errback) {
var d;
if (name) {
d = hasProp(deferreds, name) && deferreds[name];
if (!d) {
d = deferreds[name] = makeDefer(name);
}
} else {
d = makeDefer();
d = makeDefer(undefined, errback);
requireDeferreds.push(d);
}
return d;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
Expand Down Expand Up @@ -1019,6 +1042,8 @@ var requirejs, require, define;
if (!name) {
check(d);
}

return d.promise;
};

req = makeRequire(null, true);
Expand Down Expand Up @@ -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 = {
Expand Down
1 change: 1 addition & 0 deletions tests/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
7 changes: 7 additions & 0 deletions tests/promiseRequire/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
define(['bar'], function (bar) {
return {
name: 'app',
bar: bar
};
});

7 changes: 7 additions & 0 deletions tests/promiseRequire/bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// bar.js
define('bar', function(require) {
return {
name: 'bar'
};
});

105 changes: 105 additions & 0 deletions tests/promiseRequire/promiseRequire.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<!DOCTYPE html>
<html>
<head>
<title>alameda: promise from require</title>
<script src="../doh/runner.js"></script>
<script src="../doh/_browserRunner.js"></script>
<script src="../../alameda.js"></script>
<script>
var doneCount = 0;
var doneMax = 5;
var master = new doh.Deferred();
function done(err) {
if (err) {
return master.errback(err);
}

doneCount += 1;
if (doneCount === doneMax) {
master.callback(true);
}
}

// then with no initial callback.
require(['app'], function(app) {
doh.is('app', app.name);
doh.is('bar', app.bar.name);
return 'whatevs';
}).then(function(value) {
doh.is('whatevs', value);
done();
});

// then with no initial callback.
require(['app']).then(function(mods) {
var app = mods[0];
doh.is('app', app.name);
doh.is('bar', app.bar.name);
done();
});


// then with no initial callback.
require(['app'], function(app) {
doh.is('app', app.name);
doh.is('bar', app.bar.name);
throw new Error('Error inside a callback');
}).then(function(value) {
console.error('WHAT 1', value);
done(value);
}, function(err) {
doh.is(true, !!err);
done();
});

// then with no initial callback.
require(['app'], function(app) {
doh.is('app', app.name);
doh.is('bar', app.bar.name);
throw new Error('Error inside a callback');
}, function (err) {
console.error('WHAT 2: ', err);
done(err);
}).then(function(value) {
console.error('WHAT 3', value);
done(value);
}, function(err) {
doh.is(true, !!err);
done();
});

// catch usage.
require(['app'], function(app) {
doh.is('app', app.name);
doh.is('bar', app.bar.name);
throw new Error('Error inside a callback');
}).catch(function(err) {
doh.is(true, !!err);
done();
});

//Register the test
doh.register(
"promiseRequire",
[
{
name: "promiseRequire",
timeout: 3000,
runTest: function () {
return master;
}
}
]
);
doh.run();
</script>
</head>
<body>
<h1>alameda: promise from require</h1>

<p>Test require([]) returning a promise.
<a href="https://github.com/requirejs/alameda/issues/8">More info</a>.</p>

<p>Check console for messages</p>
</body>
</html>

0 comments on commit 52af527

Please sign in to comment.