I have a module that returns an array comprised of JSON data and image objects. Since both loading the JSON (from other files) and the image objects takes time, I need my module to only return the array once both are completed.
Currently, the module is always returning 'undefined' in other modules, and I believe it is because the module is not waiting to return like I expect it to (but I'm not sure). Or, because the other module using this Atlas module is declaring it as a variable before it has returned anything.
Editted to show how I am defining/requiring modules *Editted again to show more code*
The live code can be seen here.
Here is my tile-atlas module:
define( function() {
var tilesheetPaths = [
"tilesheets/ground.json",
"tilesheets/ground-collision.json",
"tilesheets/objects-collision.json"
];
var tileAtlas = [ ];
function loadAtlasJSON() {
for (var i = 0; i < tilesheetPaths.length; i++) {
loadJSON(
{
fileName: tilesheetPaths[ i ],
success: function( atlas ) {
addToTileAtlas( atlas );
}
}
);
}
};
function addToTileAtlas( atlas ) {
atlas.loaded = false;
var img = new Image();
img.onload = function() {
atlas.loaded = true;
};
img.src = atlas.src;
// Store the image object as an "object" property
atlas.object = img;
tileAtlas[ atlas.id ] = atlas;
}
// Returns tileAtlas[ ] once everything is loaded and ready
function tileAtlasReady() {
if ( allJSONloaded() && allImagesLoaded() ) {
console.log("TileAtlas ready");
return tileAtlas;
}
console.log("TileAtlas not ready");
setTimeout(tileAtlasReady, 10);
};
// Checks to make sure all XMLHttpRequests are finished and response is added to tileAtlas
function allJSONloaded() {
// If the tilesheet count in tileAtlas !== the total amount of tilesheets
if ( Object.size(tileAtlas) !== tilesheetPaths.length ) {
// All tilesheets have not been loaded into tileAtlas
console.log("JSON still loading");
return false;
}
console.log("All JSON loaded");
return true;
};
// Checks that all img objects have been loaded for the tilesheets
function allImagesLoaded() {
for ( var tilesheet in tileAtlas ) {
if (tileAtlas[tilesheet].loaded !== true) {
console.log("Images still loading");
return false;
}
}
console.log("All images loaded");
return true;
};
// Loads the JSON/images
loadAtlasJSON();
// Module should only return when tileAtlasReady() returns
return tileAtlasReady();
} );
And this is my loadJSON function from my lib:
window.loadJSON = function( args ) {
var xhr = new XMLHttpRequest();
xhr.overrideMimeType( "application/json" );
xhr.open( "GET", args.fileName, true );
xhr.onreadystatechange = function () {
if ( xhr.readyState == 4 ) {
if ( xhr.status == "200" ) {
// Check that response is valid JSON
try {
JSON.parse( xhr.responseText );
} catch ( e ) {
console.log( args.fileName + ": " + e );
return false;
}
args.success( JSON.parse(xhr.responseText) );
// xhr.status === "404", file not found
} else {
console.log("File: " + args.fileName + " was not found!");
}
}
}
xhr.send();
}
And the module loading my tile-atlas module:
define( ['data/tile-atlas'], function( tileAtlas ) {
function displayImages() {
// Code
};
// Returns undefined
console.log(tileAtlas);
displayKey();
} );
And here is what the output looks like:
[12:14:45.407] "JSON still loading"
[12:14:45.407] "TileAtlas not ready"
[12:14:45.408] undefined
[12:14:45.428] "JSON still loading"
[12:14:45.428] "TileAtlas not ready"
[12:14:45.469] "All JSON loaded"
[12:14:45.470] "Images still loading"
[12:14:45.470] "TileAtlas not ready"
[12:14:45.481] "All JSON loaded"
[12:14:45.481] "Images still loading"
[12:14:45.481] "TileAtlas not ready"
[12:14:45.492] "All JSON loaded"
[12:14:45.492] "All images loaded"
[12:14:45.492] "TileAtlas ready"
The 'undefined' is from when I console.log my Atlas module from a different module, that depends on the Atlas module.
I'm not sure if it is the Atlas module returning something before it should, or the other modules declaring the Atlas module as a variable before it has returned something.
But if it is the latter, is there a way to make it so that modules will not run until their dependencies are finished returning something?
I am completely new to Require.js and AMD: Is this approach inherently flawed? I would think that using AMD with loading-sensitive modules is common.
Thanks for your help.
EDIT Looking at the source code of another game, I realized that I can just load my jSON files with the require.js text plugin, instead of implementing an XHR in my module. This is much simpler, as I won't need to deal with the complexity of waiting for XHRs within a module. Here is how BrowserQuest does so.