Question

I am an ActionScript 3 developer who is just making his first way in building a large-scale JavaScript app. So I understand modules and understand that AMD is a good pattern to use. I read about RequireJS and implemented it. However, what I still don't understand is how to achieve Cross-Module communication. I understand that there should be some kind of mediator... I read articles and posts and still couldn't understand how to implement it simply. Here is my code, simplified:

main.js

require(["Player", "AssetsManager"], function (player, manager) {
    player.loadXML();
});

Player.js

define(function () {
    function parseXml(xml)
    {
        // NOW HERE IS THE PROBLEM -- how do I call AssetsManager from here???

        AssetsManager.queueDownload($(xml).find("prop").text());
    }

    return {
        loadXML: function () {
            //FUNCTION TO LOAD THE XML HERE, WHEN LOADED CALL parseXml(xml)
        }

    }

});

AssetsManager.js

define(function () {
    var arrDownloadQueue = [];

    return {
        queueDownload: function(path) {
            arrDownloadQueue.push(path);
        }
    }
});

Any "for dummies" help will be appreciated :) Thank you.

Was it helpful?

Solution

To load up modules from another modules that you define(), you would simply set the first parameter as an array, with your module names in it. So let's say, in your code, you wanted to load Player.js into AssetsManager.js, you would simply include the string Player in the array.

This is simply possible because define's abstract implementation is equivalent to require, only that the callback passed to define expects a value to be returned, and that it will add a "module" to a list of dependencies that you can load up.

AssetsManager.js

define(['Player'], function (player) {
    //... Your code.
});

However, if I can add to it, I personally prefer the use of require inside of the callback passed to define to grab the dependency that you want to load, instead of passing parameter to the callback.

So here's my suggestion:

define(['Player'], function () {
    var player = require('Player');
});

And this is because it's much more in tune with CommonJS.

And this is how main.js would look like formatted to be more CommonJS-friendly:

require(["Player", "AssetsManager"], function () {
    var player = require('Player');
    var manager = require('AssetsManager');
    player.loadXML();
});

But the CommonJS way of doing things is just a personal preference. My rationale for it is that the order in which you input the dependency names in the array might change at any time, and i wouldn't want to have to step through both the array and the parameters list.

Another rationale of mine (though, it's just pedantic), is that I come from the world of Node.js, where modules are loaded via require().

But it's up to you.

OTHER TIPS

(This would be a reply to skizeey's answer, but I don't have enough reputation for that)

Another way of solving this problem without pulling in Player's AssetManager dependency via require is to pass the AssetManager instance that main.js already has around. One way of accomplishing this might be to make Player's loadXML function accept an AssetManager parameter that then gets passed to parseXml, which then uses it. Another way might be for Player to have a variable to hold an AssetManager which gets read by parseXml. It could be set directly or a function to store an AssetManager in the variable could be used, called say, setAssetManager. This latter way has an extra consideration though - you then need to handle the case of that variable not being set before calling loadXml. This concept is generally called "dependency injection".

To be clear I'm not advising this over using AMD to load it in. I just wanted to provide you with more options; perhaps this technique may come in handier for you when solving another problem, or may help somebody else. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top