Newsgroup: it.comp.lang.javascript
Titolo: Eseguire codice quando più eventi terminano

Ciao a tutti.
 
Ho la necessità di eseguire una porzione di codice non semplicemente 
quando un evento occorre, ma solo se ne occorrono due o più.
 
Ad esempio, ho, in un dato istante, la necessità di eseguire un codice 
solo se l'utente ha cliccato su un bottone e una certa chiamata ajax è 
ritornata. 
 
Normalmente uso jQuery e credevo di poter usare le deferred, ma mi sembra 
che siano componibili solo con eventi ajax, mi mi sembra di poter 
attaccare il bind di un click utente. Inoltre mi sembra che l'unico modo 
per comporre le deferred sia tramite $.when() (
http://api.jquery.com/
 
jQuery.when/) che richiede che tutte le deferred da "combinare" siano 
lanciate contemporaneamente (o comunque gli oggetti che le rappresentano 
siano presenti nella stessa funzione).
 
 
Ho creato la funzione sotto, che sembra funzionare, ma mi chiedevo se sto 
sbagliando approccio e se posso in qualche modo utilizzare qualche 
soluzione terza...
 
 
 
/**
 * Consente di eseguire una funzione quando più eventi sono accaduti
 * 
 * uso:
 * 	var join = new Join()
 * 			.check('a')
 * 			.check('b')
 * 			.check('c')
 * 			.atexit(doSomething);
 * 
 * 	// in callbacks
 * 	join.done('a'); / join.done('b'); / join.done('c');
 * 
 * quando *tutte* le chiavi marcate nel check sono state segnate come
 * done, verrà chiamata doSomething()
 * 
 * @param exit:function (opzionale) funzione da chiamare quando tutti gli
 * 	eventi sono accaduti
 * @returns istanza
 */
function Join(exit) {
	var checks = {};
 
	/**
	 * segna di controllare un particolare evento, indicato tramite
	 * una chiave di tipo stringa
	 * 
	 * @param k:string chiave da verificare
	 * @returns istanza
	 */
	this.check = function check(k) {
		checks[k] = k;
		return this;
	};
 
	/**
	 * marca come effettuato un particolare evento, indicato tramite
	 * una chiave di tipo stringa.
	 * 
	 * Se non ci sono altri eventi da controllare, esegue la funzione
	 * 
	 * @param k:string chiave terminata
	 * @returns istanza
	 */
	this.done = function done(k) {
		delete checks[k];
		for (var _ in checks)
			return _, this;
		return exit && exit(), this;
	};
 
	/**
	 * imposta la funzione da invocare quando tutti gli eventi sono
	 * terminati
	 * 
	 * @param fun:function funzione da invocare
	 * @returns istanza
	 */
	this.atexit = function atexit(fun) {
		exit = fun;
		return this;
	};
};
 
-- 
By ZeD

 soluzione terza...
 
Usare le promises mi sembra la cosa migliore. Nel tuo caso ad esempio,
tutte le funzioni sono dipendenti da una variabile esterna, che è il
`join` creato: a mio avviso hai fatto un miscuglio tra event bus e
promises, reinventando la ruota ma mischiando il tutto.
 
Tra l'altro quello che hai fatto col tuo "Join", se ho inteso bene il
codice, può essere fatto benissimo con le promises, e se proprio vuoi
avere una "variabile esterna" a cui riferirti non è un problema:
 
    var join = {
        "a" : $.Deferred(),
        "b" : $.Deferred(),
        "c" : $.Deferred()
    };
 
    $.when(join.a, join.b, join.c).then(doSomething);
 
    // in callbacks
    join['a'].resolve(); / join['b'].resolve(); / join['c'].resolve();
 
Quindi non ci vedo poi tutta questa differenza con il tuo approccio.