【发布时间】:2013-09-15 23:23:08
【问题描述】:
我有一个模块,它返回一个由 JSON 数据和图像对象组成的数组。由于加载 JSON(从其他文件)和图像对象都需要时间,因此我需要我的模块仅在两者都完成后才返回数组。
目前,该模块总是在其他模块中返回“未定义”,我相信这是因为该模块没有像我期望的那样等待返回(但我不确定)。或者,因为使用此 Atlas 模块的其他模块在返回任何内容之前将其声明为变量。
已编辑以显示我如何定义/需要模块 *再次编辑以显示更多代码*
The live code can be seen here.
这是我的 tile-atlas 模块:
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();
} );
这是我的库中的 loadJSON 函数:
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();
}
以及加载我的 tile-atlas 模块的模块:
define( ['data/tile-atlas'], function( tileAtlas ) {
function displayImages() {
// Code
};
// Returns undefined
console.log(tileAtlas);
displayKey();
} );
这是输出的样子:
[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"
“未定义”来自当我从另一个模块控制台记录我的 Atlas 模块时,这取决于 Atlas 模块。
我不确定是 Atlas 模块提前返回了某些东西,还是其他模块在返回之前将 Atlas 模块声明为变量。
但如果是后者,有没有办法让模块在它们的依赖项完成返回某些东西之前不会运行?
我对 Require.js 和 AMD 完全陌生:这种方法是否存在固有缺陷?我认为将 AMD 与加载敏感模块一起使用很常见。
感谢您的帮助。
编辑查看另一个游戏的源代码,我意识到我可以使用 require.js 文本插件加载我的 JSON 文件,而不是实现 XHR在我的模块中。这要简单得多,因为我不需要处理在模块中等待 XHR 的复杂性。 Here is how BrowserQuest does so.
【问题讨论】:
-
您能否展示完整的模块(即包括
define部分),以及它的使用位置示例(即requireing 模块的示例)? -
您好,我添加了定义部分,但省略了我认为与加载情况无关的代码。如果您也希望我添加省略的代码,请告诉我。谢谢。
-
loadAtlasJSON是如何实现的?这一点至关重要,因为只有当 this 返回并且解析结果时,您才能安全地从模块中返回任何内容。 -
嗨,我添加了其余的详细信息 + 一个指向实时代码的链接。我的 loadAtlasJSON 没有返回任何东西。它只是加载 JSON 并放入 tileAtlas[]。谢谢你的关注;非常感谢:)
标签: javascript json requirejs amd