DefineJS is a lightweight implementation of AMD module format.
The Asynchronous Module Definition (AMD) API specifies a mechanism for defining modules such that the module and its dependencies can be asynchronously loaded.
Sorry for such a delay in manining DefineJS, by the end of this month the new version will be released ...
define.Promise.resolve(jQuery) .then(function * ($) { var db = {}, AsyncDB = yield require('asyncdb'), pkg = yield $.getJSON('package.json'); //Not relevant but it is worth noting that AsyncDB is an async local data storage based on IndexedDB AsyncDB.new('packages', db); var pageContent = yield $.get(pkg.repository.url); $(pageContent).appendTo('.container'); var versionEl = $('.container span.version'); return yield db.packages.insert({ name: pkg.name, version: pkg.version }); }) .then(function (packageId) { //a totally private and dedicated scope which has all it needs a packageId //... });
function * myFunc(collection){ var data = yield getData(collection); //Do something return data.app; }
Now to call the function and start the chain you could easily do:
myFunc.go('users') .then(function(app){ //The app object comes from the myFunc's return value })
Compared to a regular function .go()
is similar To a fn.call()
and to pass an array as the list of desired arguments similar to fn.apply()
DefineJS offers another function named: goWith()
:
myFunc.goWith(['users']) .then(function(app){ //The app object comes from the myFunc's return value })
But if there is no need to pass any argument to the function:
myFunc .goThen(function(app){ //The app object comes from the myFunc's return value })
require
block, you could code using either of the new styles that DefineJS offers. If you don't like using IIFEs or if you are tired of the Pyramid of Doom when dealing with callbacks:config.go() .then(firstPhase) .then(secondPhase) .then(finalPhase) .catch(lifecycleInterruption) .done(theEnd); function * sameLifecycle() { var message; try { var packageInfo = yield config.go(); var app = yield firstPhase.go(packageInfo); var shimModule2 = yield secondPhase.go(app); message = yield finalPhase.go(shimModule2); } catch (err) { message = yield lifecycleInterruption.go(err); } theEnd(message); }
Take a thorough look at the two code block above. They both do the exact same thing without us needing to create IIFEs and using callbacks.
Other than regular AMD module pattern, DefineJS also offers couple of nonstandard but usefull modular coding patterns. To make it more readable and getting to know the new features once they get released here we have top down list of DefineJS features list.
use()
with a similar approach to the standard require()
function which allows to have partial execution code blocks without having to use different main files.This hybrid syntax allows to write modules with a new syntax similar to CommonJS. This feature is now possible thanks to the ES6 generators.
Let's imagine a CommonJS module like:
//app.js var utils = require('utils'), $ = require('../vendor/jquery'); var app = { //... }; module.exports = app;
The DefineJS alternative is:
//app.js define(function* (exports, module) { var utils = yield require('utils'), $ = yield require('../vendor/jquery'); var app = { //... }; module.exports = app; });
As mentioned the new syntax is similar to the CommonJS coding style, with two specific differences. First the yield
keyword and the next is the define
wrapper with a ES6 function generator
.
This library provides you with a the possiblity of using ES6 generators and the yield
keyword along with promises. You can use yield
keyword to load your desired dependencies without getting through the callback hell.
//app.js define(function* () { var _, app; if(loadashIsNeeded){ _ = yield require('../vendor/lodash'); } else { _ = yield require('../vendor/underscore'); } app = { //... }; return app; });
Then in order to require this module, you could require
it as a regular AMD module:
//main.js require(['app'], function (app) { app.lunch(); });
Or use the new require
function like:
//main.js require(function* () { var app = yield require('app'); app.lunch(); });
Give that a try and let us know how it feels to implement an asynchronous module definition with a fully synchronous looking code.
Using the same AMD module style you can have privileged promise based modules. All you need to do is just returning a promise in your modules, to make them promised modules. To see how it works, just check out the simple-promised-module example in the examples folder.
In this example we have a promised module named: promisedModule.js which is responsible to wait for a specific global variable, then serve it as part of module's promised value.
//promisedModule.js define([ /*'dependency'*/ ], function ( /*dependency*/ ) { return new Promise(function (fulfill, reject) { //Here you expect to have a global variable named: myApp after 2 seconds //otherwise your module definition gets rejected setTimeout(function () { if (window.myApp !== undefined) { //fulfill when succeeded and pass the fulfillment value fulfill({ app: window.myApp, log: 'This is just a sample promised object to serve as a promised module!' }); } else { //reject in case of error or unsuccessful operations reject(new Error('No global myApp object found!!')); } }, 2000); }); });
Now you could easily require it, or add it as a dependency. What will happen is, it waits for your promise to get resolved then you will have the promised module object.
//main.js require(['promisedModule'], function(promisedModule){ console.log(promisedModule.log);//=>This is just a sample promised object! console.log(promisedModule.app); });
Note: we are still discussing about the proper way of handling the rejected state of a promised module. Any feedback or proposal is really appreciated.
You can also have the same modules flow using a new offered syntax by DefineJS:
use(['dependency1', 'dependency2']) .then(function(dependency1, dependency2){ //... return dependency1.util; }) .then(function(util){ //... //use util object if it has any useful functionality return util.map([/*...*/]); }) .catch(function(e){ //in case of having a rejected promised module or any async error console.error(e); });
You can define
and require
your modules using the regular AMD format:
myGlobal.define([/*'dependency'*/], function(/*dependency*/]){ function moduleFunction(){ //... } return moduleFunction; });
myGlobal.require([/*'moduleName'*/], function(/*moduleName*/]){ });Global define and require functions
To use AMD module definition functions(define and require) like what you have seen so far, as global functions, you could simply add the script tag like:
<script global="window" src="define.js"></script>
Then it could load any standard amd modules in your page.
Install with Bower:
bower install --save definejs
The component can be used as a Common JS module, an AMD module, or a global.
To use DefineJS in your JavaScript code, you could simply add it as a script tag:
<script src="define.js"></script>
Then you should call the definejs function to expose the amd modules functions to your desired global object:
The easier way of achieving this, is to pass your desired global object to the global
attribute of the script tag:
<script global="myGlobal" src="define.js"></script>
Or in case you need define and require functions as globals:
<script global="window" src="define.js"></script>
Based on the known JavaScript bad practice when defining global objects, this way with explicitly assigning the AMD functions to a specific global object or to the global scope you could be aware of the state of your global scope and also the possible consequences.
Note:
define.promise.js: To be able to use the latest DefineJS feature, which allows to use ES6 generators, instead of define.js
you should add define.promise.js
to your page:
<script global="window" src="define.promise.js"></script>
The other parts are exactly the same.
Promises polyfill: DefineJS doesn't reinvent the wheel but provides you with the official Promises polyfills from promisejs.org. You could find the latest version of the polyfill in the polyfills folder.
Install Node (comes with npm) and Bower.
From the repo root, install the project's development dependencies:
npm install
bower install
Testing relies on the Karma test-runner. If you'd like to use Karma to automatically watch and re-run the test file during development, it's easiest to globally install Karma and run it from the CLI.
npm install -g karma
karma start
To run the tests in Firefox, just once, as CI would:
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4