Object JavaScript – Using Q Promises Inside a RequireJS AMD Module

image613As you are thinking more about your Web page being an app, you look for ways to reduce the complexity by using modules. In earlier post Getting Started with Modules Using RequireJS , you learned how RequireJS provides a great way to think of your app in modules and to asynchronously load and run your app.

RequireJS helps your describe the dependencies of a module and make sure you load them before executing your script.

But what happens when your module is long running? You can certainly turn that portion into a module and the require the completion before continuing. But in my case, I want think about my AMD module as an object and then call long-running methods on that module after it has been loaded.

This snippet expands on Asynchronous JavaScript Promises Using Q  and shows how you can use a promise inside your module that will have some long running asynchronous method.

687474703a2f2f6b7269736b6f77616c2e6769746875622e696f2f712f712e706e67When you make an asynchronous call, you can use a promise to handle both successful completion of the work and potential errors that may arise during execution. Upon the successful completion of one asynchronous call, you may want to pass the result to make another request.

The solution combines the promises of Q.js with the Asynchronous Module Definition (AMD) of Require.JS.

Getting Started

Get Q and RequireJS from their websites or through NuGet in your Visual Studio project.

In this application, you will need:

  • HTML file
  • Scripts folder with two files: q.js and require.js
  • Scripts/app folder with files: main.js and sampleQ.js

Load JavaScript files

In the first step, create an HTML page that loads require.js and starts the main.js file.


<!DOCTYPE html>
<html>
<head>
<title>Require + Q</title>
</head>
<body>
<script data-main="Scripts/app/main" src="scripts/require.js"></script>
<script>
console.log("on home page");
</script>
</body>
</html>

Scripts/app/main.js

Create a main.js file that sets up the libraries that you will need.  Use require.confg() to point to where to load the JavaScript libraries.


// ====== set up require.js ================
(function () {
"use strict";
require.config({
baseUrl: 'Scripts',
paths: {
// "underscore": "lodash",
// "jquery": "jquery-2.0.3",
"q": "q"
}
});
})();

You’ll come back to main.js to call your module in a later step.

Create Your Module

Create a module in Scripts/app/sampleQ.js. Define your module. In this case, you’ll define it as a function. In the example, you canuse the CommonJS syntax. If there are a lot of requirements, this syntax can be used to help you not get the parameters confused.

Then create a private method that returns a promise using Q’s deferreds.. If successful, it uses the Q’s resolve method. If unsuccessful, it uses Q’s reject method.

Finally, the module returns the methods that are publicly accessible.

Scripts/app/sampleQ.js


define(function (require) {
"use strict";
// using simplified CommonJS syntax so it is clear what vars I can use in this
// function and not to confuse the order of them
var Q = require('q');
// Add other libraries such a: var amplify = require('amplify');
// a private method that delays
var count = function (beginningNumber, endingNumber) {
var deferral = Q.defer();
var newNumber = 0;
if (endingNumber < beginningNumber) {
deferral.reject("endingNumber before beginningNumber");
}
// do something that takes some time
for (var i = beginningNumber; i < endingNumber; i++) {
Q.delay(10);
newNumber += i;
}
console.log("in sampleQ: " + newNumber + typeof(newNumber));
deferral.resolve(newNumber);
return deferral.promise;
}; return {
count: count
};
});

Now I can call the count method in the module.

Calling the Module Using Promises

Now you can call into the module, which requires the module and q and any other libraries needed by the module. You can then call the publicly accessible methods. When they return a promise, you can handle the results for success or errors.


require(['app/sampleQ', 'q'], function (sample, Q) {
// do something with the sample object
sample.count(10, 20).then(function (countResponse) {
console.log("count successful" + countResponse);
});
// catch an error
sample.count(20, 10).then(function (countResponse) {
console.log("count successful" + countResponse);
}).catch(function (error) {
console.log("error in sample: " + error);
});
});

Sample Code

Sample code for this post is available in the DevDays GitHub repository at: https://github.com/devdays/single-page-app/tree/master/LoadTemplates

See the samples at 4a-RequirePlusQTest.html, Scripts/app/SampleQ.js, and Scripts/app/samplemain.js.

Resources