• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

CommonJS Module mit Browser laden

Junkee[]

Lounge-Member
Code:
var require = function() {
    var args = arguments;
    if(!args.callee.moduleLoad)
        args.callee.moduleLoad = {};
    var moduleLoad = args.callee.moduleLoad;
    if(!args.callee.modules)
        args.callee.modules = {};
    if(!args.callee.modulesDir) {
        var scripts = document.getElementsByTagName("script");
        for(var i=0; i<scripts.length; i++) {
            if(/^.*\/require\.js(&.*)?$/.test(scripts[i].src)) {
                var src = scripts[i].src.indexOf("?") == -1 ? scripts[i].src : scripts[i].substr(0, scripts[i].src.indexOf("?"));
                args.callee.modulesDir = src.substr(0, src.lastIndexOf("/")) + "/modules/";
            }
        }
    }
    function createXHR() {
        var req;
	    try{
	        req = new XMLHttpRequest();
	    }
	    catch (e){
		    try{
		        req = new ActiveXObject("Msxml2.XMLHTTP");
		    } 
		    catch (e){
			    try{
			        req = new ActiveXObject("Microsoft.XMLHTTP");
			    } 
			    catch (failed){
				    req = null;
			    }
		    }
	    }
	    return req;
	}
    if(typeof arguments[arguments.length-1] == "function" && arguments.length > 1) { // async
        var modules = [];
        var counter = 0;
        
        for(var i=0; i<arguments.length-1; i++) {
        
            if(typeof args[i] != "string")
                throw new Error(args[i].toString() + " is no string");
                
            if(typeof args.callee.modules[args[i]] != "undefined") {
                if(args.callee.modules[args[i]].loaded == false) {
                    moduleLoad[args[i]] = function(obj) {
                        modules.push(obj);
                        if(++counter == args.length-1) {
                            return args[args.length-1].apply(window, modules);
                        }
                    }
                }
                else {
                    modules.push(args.callee.modules[args[i]].obj);
                    if(++counter == args.length-1) {
                        return args[args.length-1].apply(window, modules);
                    }
                }
                continue;
            }
            args.callee.modules[args[i]] = {loaded:false};
            
            (function(i) {
                var req = createXHR();
                req.open("get", args.callee.modulesDir + args[i] + ".js", true);
                
                req.onreadystatechange = function() {
                    if(req.readyState == 4) {
                        if(req.status != 200)
                            throw new Error("Required file \"" + args[i] + "\" could not be loaded (" + req.status + ")");
                            
                        var export = {};
                        eval(req.responseText);
                        modules[i] = export;
                        args.callee.modules[args[i]] = {loaded:true , obj:export};
                        
                        
                        if(moduleLoad[args[i]])
                            moduleLoad[args[i]](export);
                        
                        if(++counter == args.length-1) {
                            return args[args.length-1].apply(window, modules);
                        }
                    }
                }
                req.send(null);
            })(i);
        }
    }
    else if(typeof args[0] == "string") { // sync
    
        if(typeof args.callee.modules[args[0]] != "undefined" && args.callee.modules[args[0]].loaded === true)
            return args.callee.modules[args[0]].obj;
            
        req = createXHR();
        req.open("get", args.callee.modulesDir + arguments[0] + ".js", false);
        req.send(null);

        if(req.status != 200)
            throw new Error("Required file \"" + args[0] + "\" could not be loaded (" + req.status + ")");
        
        var export = {};
        eval(req.responseText);
        args.callee.modules[args[0]] = {loaded:true, obj:export};
        return export;
    }
    else
        throw new Error("Wrong use of require; see docu or cry when there is no docu");
}
lässt sich synchron und asynchron benutzen:
Code:
synchron:
var module1 = require("module1");
var module2 = require("module2");

asynchron:
require("module1", "module2", ..., function(module1, module2, ...) {
  
});
Die module werden aus dem Ordner ./modules geladen (relativ zu dem Script oben). Die Module werden nur einmal geladen:
Code:
var x1 = require("x");
var x2 = require("x");
alert(x1 === x2); // true
Wenn die asynchrone Methode benutzt wird, werden die Module in beliebiger Reihenfolge geladen aber auch nie zwei mal das gleiche.
Code:
var gx1, gx2
require("x", function(x1) {
  gx1 = x1;
});
require("x", function(x2) {
  gx2 = x2;
});
window.setTimeout(function() {
  alert(gx1 === gx2); // true
}, 1000);
Informationen zu Modulen; http://www.commonjs.org/specs/modules/1.0/
Verbesserungsvorschläge? Fragen?
 
OK - da hast du ja schon einiges verbessert, was ich an der letzten Version nicht so toll fand (mehrmaliges Herausfinden der Basisurl, queueing beim asynchronen Laden, kein cache bei Asynchronizität) - aber da ist noch ein bisschen was:
1. Deine RegExp für die URL ist nicht optimal - so hab' ich das gemacht:
Code:
	var scripts = document.getElementsByTagName("script");
	var checkRE = /(^.*?)[^\/]*require\.js(?:$|\?)/, match;
	var base = "";
	for (var i = 0; i < scripts.length; i++){
		if ((match = checkRE.exec(scripts[i].src)) !== null){
			base = match[1];
			break;
		}
	}
2. Dein Requesterzeugen gibst du null zurück, wenn es nicht unterstützt wird - dadurch erzeugst du dann bei req.open einen Fehler... besser gleich eine passende Fehlermedlung werfen:
Code:
	function getRequest(){
		var req;
		if (window.XMLHttpRequest){
			req = new XMLHttpRequest();
		}
		else if(window.ActiveXObject){
			var tries = ['Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
			for (var i = 0; i < tries.length; i++){
				try{
					req = new ActiveXObject(tries[i]);
					break;
				}
				catch (e){}
			}
		}
		if (!req){
			throw new Error('Error creating request object!');
		}
		return req;
	};
(außerdem erzeugst du dein createXHR bei jedem Funktionsaufruf neu - das geht performanter)

3. Ausprobieren:
Code:
typeof new String("hallo");
4. Überleg' dir, was passiert, wenn du ein Modul asynchron laden willst, das "toString" heißt.
5. das eval ist doch etwas zu ungeschützt - stell' dir mal vor, in irgendeinem Modul wird die globale Variable modules beschrieben... besser eval aus dem Scope herausnehmen (s.u.)
6. das mit dem moduleLoad ist eine gute Idee (hab' mich mit dem gleichzeitigen Laden von Modulen auch schon beschäftigt - bin aber noch zu keinem wirklich befriedigendem Ergebnis gekommen - Probleme macht mir noch die Mischung aus einem asynchronen Laden und einem synchronen Laden in einem der Module) aber bei drei asynchronen Ladevorgängen des gleichen Moduls killst du den Callback des zweiten damit, da du das moduleLoad[args] überschreibst.
7. ... und durch das modules.push bekommst du eine undefinierte Reihenfolge deiner exports-Objekte in modules.
8. Die letzte Fehlermeldung ist gut. ;)

So - zu guter letzt will ich meinen Code auch noch zur Diskussion freigeben:
Code:
var require = (function(){
	function getRequest(){
		var req;
		if (window.XMLHttpRequest){
			req = new XMLHttpRequest();
		}
		else if(window.ActiveXObject){
			var tries = ['Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
			for (var i = 0; i < tries.length; i++){
				try{
					req = new ActiveXObject(tries[i]);
					break;
				}
				catch (e){}
			}
		}
		if (!req){
			throw new Error('Error creating request object!');
		}
		return req;
	};
	
	var scripts = document.getElementsByTagName("script");
	var checkRE = /(^.*?)[^\/]*require\.js(?:$|\?)/, match;
	var base = "";
	for (var i = 0; i < scripts.length; i++){
		if ((match = checkRE.exec(scripts[i].src)) !== null){
			base = match[1];
			break;
		}
	}
	
	var cache = {};
	
	return function require(module, callbackFn){
		if (typeof callbackFn == "function" || callbackFn instanceof Function){
			if (!(module instanceof Array)){
				module = [module];
			}
			var reqFinished = 0, req;
			var exportsArr = [];
			for (var i = 0; i < module.length; i++){
				if (cache.hasOwnProperty(module[i])){
					exportsArr[i] = cache[module[i]];
					reqFinished++;
					if (reqFinished == module.length){
						callbackFn.apply(undefined, exportsArr);
					}
					continue;
				}
				req = getRequest();
				req.open("GET", base + module[i] + ".js", true);
				req.i = i;
				req.onreadystatechange = function(){
					var i = this.i;
					if (this.readyState == 4){
						if (this.status != 200){
							throw new Error("Module " + module[i] + " not found! (HTTP status code " + this.status + ")");
						}
						else {
							var exports = {};
							require.eval(exports, this.responseText);
							cache[module[i]] = exports;
							exportsArr[i] = exports;
							reqFinished++;
							if (reqFinished == module.length){
								callbackFn.apply(undefined, exportsArr);
							}
						}
					}
				};
				req.send(null);
			}
			return exportsArr;
		}
		else {
			if (cache.hasOwnProperty(module)){
				return cache[module];
			}
			else {
				var req = getRequest();
				req.open("GET", base + module + ".js", false);
				req.send(null);
				if (req.status != 200){
					throw new Error("Module " + module + " not found! (HTTP status code " + req.status + ")");
				}
				else {
					var exports = {};
					require.eval(exports, req.responseText);
					cache[module] = exports;
					return exports;
				}
			}
		}
	}
})();

require.eval = function(exports, code){
	eval(code);
}
- bei gleichzeitigem Laden ist die Eindeutigkeit der Module noch nicht gewährleistet (also das mit dem moduleLoad), aber ich denke daran.

Ach - und der asynchrone Aufruf ist bei mir anders:
Code:
require(["m1", "m2"], function(m1, m2){});
 
Zuletzt bearbeitet:
So... hab' mich jetzt nochmal drangesetzt und auch die Mischung zwischen synchron und asynchron hinbekommen:
Code:
var require = (function(){
	// get base-url (the url of this script)
	var scripts = document.getElementsByTagName("script");
	var checkRE = /(^.*?)[^\/]*require\.js(?:$|\?)/, match;
	var base = "";
	for (var i = 0; i < scripts.length; i++){
		if ((match = checkRE.exec(scripts[i].src)) !== null){
			base = match[1];
			break;
		}
	}
	
	// caching issues
	function LoadingModule(name){
		this.name = name;
		this.queue = [];
	}
	LoadingModule.prototype = {
		constructor: LoadingModule,
		addOnload: function(func){
			this.queue.push(func);
		},
		onload: function(exports){
			for (var i = 0; i < this.queue.length; i++){
				this.queue[i](exports);
			}
			this.queue = [];
			delete loadingModules[this.name];
		}
	};
	
	var loadingModules = {};
	var cache = {};
	
	function finishRequest(module, code){
		if (cache.hasOwnProperty(module)) return cache[module];
		var exports = {};
		require.eval(exports, code);
		cache[module] = exports;
		if (loadingModules.hasOwnProperty(module)){
			loadingModules[module].onload(exports);
		}
		return exports;
	};
	
	// perform XHR-request
	function doRequest(module, asynch){
		var req;
		if (window.XMLHttpRequest){
			req = new XMLHttpRequest();
		}
		else if(window.ActiveXObject){
			var tries = ['Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
			for (var i = 0; i < tries.length; i++){
				try{
					req = new ActiveXObject(tries[i]);
					break;
				}
				catch (e){}
			}
		}
		if (!req){
			throw new Error('Error creating request object!');
		}
		req.open("GET", base + module + ".js", asynch);
		
		function onRSChange(){
			if (this.readyState == 4){
				if (this.status != 200){
					throw new Error("Module " + module + " not found! (HTTP status code " + this.status + ")");
				}
				else {
					return finishRequest(module, this.responseText);
				}
			}
		};
		if (asynch) req.onreadystatechange = onRSChange;
		req.send(null);
		if (!asynch) return onRSChange.call(req);
		return req;
	};
	
	return function(module, callbackFn){
		if (typeof callbackFn == "function" || callbackFn instanceof Function){
			if (!(module instanceof Array)){
				module = [module];
			}
			var reqFinished = 0, req = false;
			var exportsArr = [];
			function getOnloadFunction(i){
				return function(exports){
					exportsArr[i] = exports;
					reqFinished++;
					if (reqFinished == module.length){
						// perform in next tic to avoid synchronity-problems
						window.setTimeout(function(){
							callbackFn.apply(undefined, exportsArr);
						}, 0);
					}
				}
			}
			for (var i = 0; i < module.length; i++){
				if (cache.hasOwnProperty(module[i])){
					getOnloadFunction(i)(cache[module[i]]);
					continue;
				}
				if (!loadingModules.hasOwnProperty(module[i])){
					loadingModules[module[i]] = new LoadingModule(module[i]);
					doRequest(module[i], true);
				}
				loadingModules[module[i]].addOnload(getOnloadFunction(i));
			}
			return exportsArr;
		}
		else {
			if (cache.hasOwnProperty(module)){
				return cache[module];
			}
			else {
				return doRequest(module, false);
			}
		}
	}
})();

require.eval = function(exports, code){
	eval(code);
}
 
Code:
var require = (function(){
	var modulesDir = "./modules/";
	
	// get base-url (the url of this script)
	var base = modulesDir;
	if(modulesDir.substr(0,2) == "./") {
		var scripts = document.getElementsByTagName("script");
		var checkRE = /(^.*?)[^\/]*require\.js(?:$|\?)/, match;
		for (var i = 0; i < scripts.length; i++){
			if ((match = checkRE.exec(scripts[i].src)) !== null){
				base = match[1] + modulesDir.substr(2);
				break;
			}
		}
	}
	
	// caching issues
	function LoadingModule(name){
		this.name = name;
		this.queue = [];
	}
	LoadingModule.prototype = {
		constructor: LoadingModule,
		addOnload: function(func){
			this.queue.push(func);
		},
		onload: function(exports){
			for (var i = 0; i < this.queue.length; i++){
				this.queue[i](exports);
			}
			this.queue = [];
			delete loadingModules[this.name];
		}
	};
	
	var loadingModules = {};
	var cache = {};
	var usableXHRObjs = [];
	
	function getXHRObject() {
		if(usableXHRObjs.length > 0)
			return usableXHRObjs.shift();
		var req;
		if (window.XMLHttpRequest){
			return new XMLHttpRequest();
		}
		else if(window.ActiveXObject){
			var tries = ['Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
			for (var i = 0; i < tries.length; i++){
				try{
					return new ActiveXObject(tries[i]);
				}
				catch (e){}
			}
		}
		if (!req){
			throw new Error('Error creating request object!');
		}
	}
	
	function finishRequest(module, code){
		if (cache.hasOwnProperty(module)) return cache[module];
		var exports = {};
		require.eval(exports, code);
		cache[module] = exports;
		if (loadingModules.hasOwnProperty(module)){
			loadingModules[module].onload(exports);
		}
		return exports;
	};
	
	// perform XHR-request
	function doRequest(module, asynch){
		var req = getXHRObject();
		req.open("GET", base + module + ".js", asynch);
		
		function onRSChange(){
			if (this.readyState == 4){
				usableXHRObjs.push(this);
				if (this.status != 200){
					throw new Error("Module " + module + " not found! (HTTP status code " + this.status + ")");
				}
				else {
					return finishRequest(module, this.responseText);
				}
			}
		};
		if (asynch) req.onreadystatechange = onRSChange;
		req.send(null);
		if (!asynch) return onRSChange.call(req);
		return req;
	};
	
	return function(module, callbackFn){
		if (typeof callbackFn == "function" || callbackFn instanceof Function){
			if (!(module instanceof Array)){
				module = [module];
			}
			var reqFinished = 0, req = false;
			var exportsArr = [];
			function getOnloadFunction(i){
				return function(exports){
					exportsArr[i] = exports;
					reqFinished++;
					if (reqFinished == module.length){
						// perform in next tic to avoid synchronity-problems
						window.setTimeout(function(){
							callbackFn.apply(undefined, exportsArr);
						}, 0);
					}
				}
			}
			for (var i = 0; i < module.length; i++){
				if(typeof module[i] != "string" && !(module[i] instanceof String))
					throw new Error(module[i] + " is not a string");
				if (cache.hasOwnProperty(module[i])){
					getOnloadFunction(i)(cache[module[i]]);
					continue;
				}
				if (!loadingModules.hasOwnProperty(module[i])){
					loadingModules[module[i]] = new LoadingModule(module[i]);
					doRequest(module[i], true);
				}
				loadingModules[module[i]].addOnload(getOnloadFunction(i));
			}
			return exportsArr;
		}
		else {
			if(typeof module != "string" && !(module instanceof String))
				throw new Error(module + " is not a string");
			if (cache.hasOwnProperty(module)){
				return cache[module];
			}
			else {
				return doRequest(module, false);
			}
		}
	}
})();

require.eval = function(exports, code){
	eval(code);
}
XHR Objekte wiederbenutzen und Fehlermeldungen hinzugefügt :)
Außerdem gibt es jetzt die Variable modulesDir. Wenn modulesDir mit ./ anfängt wird ./ mit dem Pfad zum Ordner ersetzt, in dem sich das Skript befindet
Code:
// wenn das Skript den Pfad http://example.com/komische/url/zum/skript.js hat und die html Datei in http://example.com/html/index.html liegt:
var modulesDir = "./modules/";
http://example.com/komische/url/zum/modules/

var modulesDir = "/modules/";
http://example.com/modules/

var modulesDir = "modules/";
http://example.com/html/modules/
 
;) zusammen bekommen wir da noch die bestmögliche Lösung hin.

Bin noch am überlegen, ob man noch eine Ladereihenfolge einführen soll - also wenn das Modul am ersten Ort nicht gefunden wird, im zweiten Ort nachsehen, usw...
 
Ist zwar denkbar aber wir müssten zuerst abwarten, ob das Modul existiert, bevor wir an der nächsten Stelle suchen. Das wiederum würde sehr viel Zeit in Anspruch nehmen... Wenn man aber gleichzeitig an allen Orten sucht ensteht ein großer Overhead, was auch nicht so toll ist...
 
Hmm... hast irgendwie schon Recht... und beim gleichzeitigen Suchen könnte es zu undefiniertem Verhalten führen, wenn an zwei der Orte gleichnamige Dateien mit unterschiedlichem Inhalt gibt - es bliebe also wirklich nur das sequenzielle Abklappern der unterschiedlichen Orte.
Muss ich mir wirklich noch durch den Kopf gehen lassen.

PS: was wir aber auf jeden Fall machen könnten ist, dass wir z.B. bei einem Slash vor dem Modulnamen ("/m1") wirklich im Root suchen lassen... und bei "./m1" im Ordner der offenen Seite.
 
Also nicht so eine Variable wie modulesDir benutzen sondern direkt beim Laden bestimmen woher das Modul genommen wird? Wenn du das so meinst +1!
 
Hab's grad mal eingebaut:
Code:
var require = (function(){
	// get base-url (the url of this script)
	var scripts = document.getElementsByTagName("script");
	var checkRE = /(^.*?)[^\/]*require\.js(?:$|\?)/, match;
	var base = "";
	for (var i = 0; i < scripts.length; i++){
		if ((match = checkRE.exec(scripts[i].src)) !== null){
			base = match[1] + base;
			break;
		}
	}
	
	// caching issues
	function LoadingModule(name){
		this.name = name;
		this.queue = [];
	}
	LoadingModule.prototype = {
		constructor: LoadingModule,
		addOnload: function(func){
			this.queue.push(func);
		},
		onload: function(exports){
			for (var i = 0; i < this.queue.length; i++){
				this.queue[i](exports);
			}
			this.queue = [];
			delete loadingModules[this.name];
		}
	};
	
	var loadingModules = {};
	var cache = {};
	var useableXHRObjects = [];
	
	function finishRequest(module, code){
		if (cache.hasOwnProperty(module)) return cache[module];
		var exports = {};
		require.eval(exports, code);
		cache[module] = exports;
		if (loadingModules.hasOwnProperty(module)){
			loadingModules[module].onload(exports);
		}
		return exports;
	};
	
	function getXHRObject(){
		if (useableXHRObjects.length){
			return useableXHRObjects.pop();
		}
		var req;
		if (window.XMLHttpRequest){
			req = new XMLHttpRequest();
		}
		else if(window.ActiveXObject){
			var tries = ['Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
			for (var i = 0; i < tries.length; i++){
				try{
					req = new ActiveXObject(tries[i]);
					break;
				}
				catch (e){}
			}
		}
		if (!req){
			throw new Error('Error creating request object!');
		}
		return req;
	}
	
	// perform XHR-request
	function doRequest(module, asynch){
		var req = getXHRObject();
		req.open(
			"GET",
			(/^\.{0,2}\//.test(module)? "": base) + module + ".js",
			asynch
		);
		
		function onRSChange(){
			if (this.readyState == 4){
				if (this.status != 200){
					throw new Error("Module " + module + " not found! (HTTP status code " + this.status + ")");
				}
				else {
					return finishRequest(module, this.responseText);
				}
				useableXHRObjects.push(this);
			}
		};
		if (asynch) req.onreadystatechange = onRSChange;
		req.send(null);
		if (!asynch) return onRSChange.call(req);
		return req;
	};
	
	return function(module, callbackFn){
		if (typeof callbackFn == "function" || callbackFn instanceof Function){
			if (!(module instanceof Array)){
				module = [module];
			}
			var reqFinished = 0;
			var exportsArr = [];
			function getOnloadFunction(i){
				return function(exports){
					exportsArr[i] = exports;
					reqFinished++;
					if (reqFinished == module.length){
						// perform in next tic to avoid synchronity-problems
						window.setTimeout(function(){
							callbackFn.apply(undefined, exportsArr);
						}, 0);
					}
				}
			}
			for (var i = 0; i < module.length; i++){
				if (typeof module[i] != "string" && !(module[i] instanceof String)){
					throw new Error("module parameter is not a string");
				}
				if (cache.hasOwnProperty(module[i])){
					getOnloadFunction(i)(cache[module[i]]);
					continue;
				}
				if (!loadingModules.hasOwnProperty(module[i])){
					loadingModules[module[i]] = new LoadingModule(module[i]);
					doRequest(module[i], true);
				}
				loadingModules[module[i]].addOnload(getOnloadFunction(i));
			}
			return exportsArr;
		}
		else {
			if (typeof module != "string" && !(module instanceof String)){
				throw new Error("module parameter is not a string");
			}
			if (cache.hasOwnProperty(module)){
				return cache[module];
			}
			else {
				return doRequest(module, false);
			}
		}
	}
})();

require.eval = function(exports, code){
	eval(code);
}

PS: die Recycling-Idee ist eigentlich nicht schlecht... muss der Garbage-Collector weniger aufräumen - ABER dadurch werden die Resource, die die Objekte benötigen erst wieder beim Schließen der Seite freigegeben... aber lässt sich ja schnell auskommentieren.
 
Zuletzt bearbeitet:
Das größte am XHR Objekt ist eigentlich responseText. Wenn man responseText = null; setzt solle es von den Resourcen her gehen...?
 
Mit dem responseText könntest du Recht haben...

Warum sollte man in einem Module kein anderes Modul synchron laden können? Hast du das ausprobiert? Wenn ja: Testlink oder Code.
 
Mach' doch um das alert mal einen Timeout - zu diesem Zeitpunkt kann y ja noch gar nicht geladen sein, da es ja asynchron ist - ist ja Absicht, dass zuerst alles Aynchrone ausgeführt wird und dann erst das Synchrone.
 
Ist schon klar aber wenn ich etwas synchron lade, dann gehe ich davon aus, dass ich das Objekt sofort benutzen kann...
 
Code:
var require = (function(){
	// get base-url (the url of this script)
	var scripts = document.getElementsByTagName("script");
	var checkRE = /(^.*?)[^\/]*require\.js(?:$|\?)/, match;
	var base = "";
	for (var i = 0; i < scripts.length; i++){
		if ((match = checkRE.exec(scripts[i].src)) !== null){
			base = match[1] + base;
			break;
		}
	}
	
	// caching issues
	function LoadingModule(name){
		this.name = name;
		this.queue = [];
	}
	LoadingModule.prototype = {
		constructor: LoadingModule,
		addOnload: function(func){
			this.queue.push(func);
		},
		onload: function(exports){
			for (var i = 0; i < this.queue.length; i++){
				this.queue[i](exports);
			}
			this.queue = [];
			delete loadingModules[this.name];
		}
	};
	
	var loadingModules = {};
	var cache = {};
	var useableXHRObjects = [];
	
	function finishRequest(module, code){
		if (cache.hasOwnProperty(module)) return cache[module];
		var exports = {};
		require.eval(exports, code);
		cache[module] = exports;
		if (loadingModules.hasOwnProperty(module)){
			loadingModules[module].onload(exports);
		}
		return exports;
	};
	
	function getXHRObject(){
		if (useableXHRObjects.length){
			return useableXHRObjects.pop();
		}
		var req;
		if (window.XMLHttpRequest){
			req = new XMLHttpRequest();
		}
		else if(window.ActiveXObject){
			var tries = ['Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'Msxml2.XMLHTTP.3.0', 'Msxml2.XMLHTTP', 'Microsoft.XMLHTTP'];
			for (var i = 0; i < tries.length; i++){
				try{
					req = new ActiveXObject(tries[i]);
					break;
				}
				catch (e){}
			}
		}
		if (!req){
			throw new Error('Error creating request object!');
		}
		return req;
	}
	
	// perform XHR-request
	function doRequest(module, asynch){
		var req = getXHRObject();
		req.open(
			"GET",
			(/^\.{0,2}\//.test(module)? "": base) + module + ".js",
			asynch
		);
		
		function onRSChange(){
			if (req.readyState == 4){
				if (req.status != 200){
					throw new Error("Module " + module + " not found! (HTTP status code " + req.status + ")");
				}
				else {
					return finishRequest(module, req.responseText);
				}
				useableXHRObjects.push(req);
			}
		};
		if (asynch) req.onreadystatechange = onRSChange;
		req.send(null);
		if (!asynch) return onRSChange.call(req);
		return req;
	};
	
	return function(module, callbackFn){
		if (typeof callbackFn == "function" || callbackFn instanceof Function){
			if (!(module instanceof Array)){
				module = [module];
			}
			var reqFinished = 0;
			var exportsArr = [];
			function getOnloadFunction(i){
				return function(exports){
					exportsArr[i] = exports;
					reqFinished++;
					if (reqFinished == module.length){
						// perform in next tic to avoid synchronity-problems
						window.setTimeout(function(){
							callbackFn.apply(undefined, exportsArr);
						}, 0);
					}
				}
			}
			for (var i = 0; i < module.length; i++){
				if (typeof module[i] != "string" && !(module[i] instanceof String)){
					throw new Error("module parameter is not a string");
				}
				if (cache.hasOwnProperty(module[i])){
					getOnloadFunction(i)(cache[module[i]]);
					continue;
				}
				if (!loadingModules.hasOwnProperty(module[i])){
					loadingModules[module[i]] = new LoadingModule(module[i]);
					doRequest(module[i], true);
				}
				loadingModules[module[i]].addOnload(getOnloadFunction(i));
			}
			return exportsArr;
		}
		else {
			if (typeof module != "string" && !(module instanceof String)){
				throw new Error("module parameter is not a string");
			}
			if (cache.hasOwnProperty(module)){
				return cache[module];
			}
			else {
				return doRequest(module, false);
			}
		}
	}
})();

require.eval = function(exports, code){
	eval(code);
}
in der Funktion onRSChange this mit req ersetzt, weil this bei IE6 anscheinend ein anderes Object zurück gibt...
 
mhh... komisch, weil mein ie6 auf virtualbox hatte probleme damit... aber soweit ich weiß ist da gerade mal sp1 drauf.
 
Zurück
Oben