我有一个模块返回一个由 JSON 数据和图像对象组成的数组。由于加载 JSON(从其他文件)和图像对象都需要时间,所以我需要我的模块仅在两者完成后才返回数组。
目前,该模块总是在其他模块中返回“undefined”,我相信这是因为该模块没有像我预期的那样等待返回(但我不确定)。或者,因为使用此 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"
'undefined' 来自于我从另一个模块控制台记录我的 Atlas 模块,这取决于 Atlas 模块。
我不确定是 Atlas 模块在它应该返回的东西之前返回了一些东西,还是其他模块在它返回一些东西之前将 Atlas 模块声明为变量。
但如果是后者,有没有办法让模块在它们的依赖项完成返回某些东西之前不会运行?
我对 Require.js 和 AMD 完全陌生:这种方法是否存在固有缺陷?我认为将 AMD 与加载敏感模块一起使用是很常见的。
感谢您的帮助。
编辑 查看另一个游戏的源代码,我意识到我可以只使用 require.js 文本插件加载我的 jSON 文件,而不是在我的模块中实现 XHR。这要简单得多,因为我不需要处理在模块内等待 XHR 的复杂性。 Here is how BrowserQuest does so .
最佳答案
好的,我检查了您的代码并进行了一些观察。
除非您确切地知道自己在做什么(或者这样做是为了了解 XHR),否则我不会直接使用 XMLHttpRequest。这个对象有几个跨浏览器陷阱,所以我会使用 JS 库来帮助解决问题,jQuery 是最明显的库之一。
我还会尝试使用延迟/ promise 方法而不是回调。同样,图书馆会在这里帮助你。 jQuery has these for ajax ,其他图书馆也是如此 when.js .
考虑到这一点,这里是 some jsfiddle code你可能想看看,这可能会给你一些想法。
首先,在一个新模块中有一个ajax抽象,它使用了when.js deferreds。该模块将根据 XHR 是否成功来解决或拒绝延迟。请注意,我没有直接使用 XHR,但我建议改用 JS 库。
// --------------------------------------------------
// New module
// Using https://github.com/cujojs/when/wiki/Examples
// --------------------------------------------------
define("my-ajax", ["when"], function (when) {
// TODO - Fake id only for testing
var id = 0;
function makeFakeJSFiddleRequestData(fileName) {
var data = {
fileName: fileName
};
data = "json=" + encodeURI(JSON.stringify(data));
var delayInSeconds = Math.floor(8 * Math.random());
data += "&delay=" + delayInSeconds;
return data;
}
return function loadJSON(args) {
// Create the deferred response
var deferred = when.defer();
var xhr = new XMLHttpRequest();
xhr.overrideMimeType("application/json");
var url = args.fileName;
// TODO - Override URL only for testing
url = "/echo/json/";
// TODO - Provide request data and timings only for testing
var start = +new Date();
var data = makeFakeJSFiddleRequestData(args.fileName);
// TODO - POST for testing. jsfiddle expects POST.
xhr.open("POST", url, true);
xhr.onreadystatechange = function () {
// TODO - duration only for testing.
var duration = +new Date() - start + "ms";
if (xhr.readyState == 4) {
if (xhr.status === 200) {
// Check that response is valid JSON
var json;
try {
json = JSON.parse(xhr.responseText);
} catch (e) {
console.log("rejected", args, duration);
deferred.reject(e);
return;
}
console.log("resolved", args, duration);
// TODO - Fake id only for testing
json.id = ("id" + id++);
deferred.resolve(json);
} else {
console.log("rejected", args, duration);
deferred.reject([xhr.status, args.fileName]);
}
}
}
// TODO - Provide request data only for testing
xhr.send(data);
// return the deferred's promise.
// This promise will only be resolved or rejected when the XHR is complete.
return deferred.promise;
};
});
现在你的 atlas 模块看起来有点像这样(为清楚起见删除了图像代码):
// --------------------------------------------------
// Your module
// Image stuff removed for clarity.
// --------------------------------------------------
define("tile-atlas", ["my-ajax", "when"], function (myAjax, when) {
var tilesheetPaths = [
"tilesheets/ground.json",
"tilesheets/ground-collision.json",
"tilesheets/objects-collision.json"];
// TODO - Changed to {} for Object keys
var tileAtlas = {};
function loadAtlasJSON() {
var deferreds = [];
// Save up all the AJAX calls as deferreds
for (var i = 0; i < tilesheetPaths.length; i++) {
deferreds.push(myAjax({
fileName: tilesheetPaths[i]
}));
}
// Return a new deferred that only resolves
// when all the ajax requests have come back.
return when.all(deferreds);
};
function addToTileAtlas(atlas) {
console.log("addToTileAtlas", atlas);
tileAtlas[atlas.id] = atlas;
}
function tileAtlasesReady() {
console.log("tileAtlasesReady", arguments);
var ajaxResponses = arguments[0];
for (var i = 0; i < ajaxResponses.length; i++) {
addToTileAtlas(ajaxResponses[i]);
}
return tileAtlas;
};
function loadAtlases() {
// When loadAtlasJSON has completed, call tileAtlasesReady.
// This also has the effect of resolving the value that tileAtlasesReady returns.
return when(loadAtlasJSON(), tileAtlasesReady);
}
// Return an object containing a function that can load the atlases
return {
loadAtlases: loadAtlases
};
});
您的应用(或我的假演示)可以按以下方式使用此代码:
// --------------------------------------------------
// App code
// --------------------------------------------------
require(["tile-atlas"], function (atlas) {
console.log(atlas);
// The then() callback will only fire when loadAtlases is complete
atlas.loadAtlases().then(function (atlases) {
console.log("atlases loaded");
for (var id in atlases) {
console.log("atlas " + id, atlases[id]);
}
});
});
并将以下类型的信息转储到控制台:
Object {loadAtlases: function}
resolved Object {fileName: "tilesheets/ground-collision.json"} 3186ms
resolved Object {fileName: "tilesheets/ground.json"} 5159ms
resolved Object {fileName: "tilesheets/objects-collision.json"} 6221ms
tileAtlasesReady [Array[3]]
addToTileAtlas Object {fileName: "tilesheets/ground.json", id: "id1"}
addToTileAtlas Object {fileName: "tilesheets/ground-collision.json", id: "id0"}
addToTileAtlas Object {fileName: "tilesheets/objects-collision.json", id: "id2"}
atlases loaded
atlas id1 Object {fileName: "tilesheets/ground.json", id: "id1"}
atlas id0 Object {fileName: "tilesheets/ground-collision.json", id: "id0"}
atlas id2 Object {fileName: "tilesheets/objects-collision.json", id: "id2"}
关于Javascript - 在 Require.js 中延迟模块返回/声明?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18749604/
假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于
作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c