Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it L'avatar di Jey
    Registrato dal
    Jan 2013
    Messaggi
    41

    Thread e funzioni asincrone

    Buongiorno a tutti!

    Il mio problema è il seguente: ho una pagina html che utilizzo per la visualizzazione di una grande quantità di dati.

    Per ricevere i dati faccio chiamate ajax asincrone al server e fin qui nessun problema.
    Una volta arrivati i dati, però, devo popolare molti grafici e tabelle con questi ( nell'ordine di 12 - 15 grafici e 5 - 10 tabelle organizzate su vari tabsheet ) e, nel momento della popolazione, il browser rimane completamente bloccato per vari secondi finchè non finisce di popolare tutto.

    Ora, per evitare questo, è possibile in javascript creare thread o chiamare funzioni in modo asincrono?

    Oppure esiste qualche funzione javascript che evita di bloccare il browser durante l'esecuzione del codice ( es. il metodo Application.ProcessMessages() di delphi, per chi conosce )?

  2. #2
    Utente di HTML.it L'avatar di carlomarx
    Registrato dal
    Oct 2009
    Messaggi
    1,669
    Originariamente inviato da Jey
    Ora, per evitare questo, è possibile in javascript creare thread o chiamare funzioni in modo asincrono?
    Esistono eccome! Sono metodi fichissimi e si chiamano Workers (https://developer.mozilla.org/en-US/...ng_web_workers). Solo che sei sfortunato: i workers non possono manipolare il DOM. Sorry.
    Se però i grafici sono immagini, puoi parzialmente risolvere il problema con una chiamata ricorsiva asincrona tramite l'evento onload di ciascuna immagine. Per le tabelle da riempire con HTML invece nessuna soluzione con questo metodo.
    Se invece vuoi affrontare il problema diversamente, spezzetta la mole di dati in più parti e crea delle chiamate ricorsive di setTimeout() con timer minimo, tipo 1 ms – non usare setInterval() in un caso come questo! Così facendo dovresti garantire un po' di respiro al tuo browser.

    EDIT: Forse mi è appena venuta in mente la soluzione migliore. Delega le chiamate AJAX a un worker (usa semrpe chiamate SINCRONE quando usi AJAX da un worker, mi raccomando!). Una volta che il worker riceverà i dati curerà di inviarli alla pagina un po' per volta, man mano che questa popola il DOM. Dovrebbe essere la via corretta…
    Tutto ciò che fai con jQuery puoi farlo meglio e con la metà del codice in puro JavaScript.

  3. #3
    Utente di HTML.it L'avatar di Jey
    Registrato dal
    Jan 2013
    Messaggi
    41
    Grazie per i workers, proverò a darci un occhio

    Ma per informazione, visto che sono ignorante rigardo questi, io per fare i grafici uso i TeeChart per HTML5 e per le tabelle uso il plugin dataTables per JQuery...

    In questo caso possono essermi utili i workers o perderei solo tempo?

  4. #4
    Utente di HTML.it L'avatar di carlomarx
    Registrato dal
    Oct 2009
    Messaggi
    1,669
    Originariamente inviato da Jey
    In questo caso possono essermi utili i workers o perderei solo tempo?
    Le librerie che usi sono scorciatoie per il DOM. I workers invece sono dei "programmini" in JavaScript che ti costruisci tu e che lavorano separatamente e indipendentemente dalla pagina principale. Devono svolgere compiti limitati e una volta svolti dialogano con la pagina principale, dove puoi continuare a utilizzare tutte le librerie che credi. Quindi non perdi tempo. La differenza è che la chiamata AJAX invece di farla con jQuery la fai in puro JavaScript dal worker. Una volta smistati i dati alla pagina principale potrai però tornare a utilizzare jQuery per popolare le tabelle e per tutto il resto.
    Tutto ciò che fai con jQuery puoi farlo meglio e con la metà del codice in puro JavaScript.

  5. #5
    Utente di HTML.it L'avatar di Jey
    Registrato dal
    Jan 2013
    Messaggi
    41
    Mi sa che non ci siamo capiti xD

    Ti illustro meglio la situazione: apro la pagina, questa si carica e comincia a chiedere i dati al server.
    Appena ottenuti i dati di un grafico ( per esempio ) io creo uno o più div dove inserisco titolo, grafico ecc...

    A ottenere i dati ( oggetti JSON ) dal server ci metto circa ( sparo ) 500 millisecondi...
    La parte lenta è quando creo i div e il Chart analizza il JSON per popolarsi ( siamo nell'ordine di vari secondi a grafico visto che sono molti dati )

    Nel worker quindi non mi serve fare la richiesta dei dati al server, ma la parte di creazione dei div e del grafico...

    E' possibile o non c'è scampo??? xD

  6. #6
    Utente di HTML.it L'avatar di carlomarx
    Registrato dal
    Oct 2009
    Messaggi
    1,669
    Un esempio vale più di mille parole…:

    pagina.html:

    codice:
    <!doctype html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Esempio</title>
    <script type="text/javascript">
    function faiQualcosa (oggetto) {
    	/* Qui arriveranno un po' alla volta i dati. In quest'esempio c'e' un alert. Nella tua pagina invece li lavorerai con le tue librerie. */
    	alert(oggetto.glossary.title);
    }
    
    var retrieveJSON = (function () {
    	function switchMsg (oEvent) {
    		if (oEvent.data === 0) {
    			alert("Ok, ho letto tutto correttamente. Chiudo il worker.");
    			this.terminate();
    			return;
    		}
    		if (isFinite(oEvent.data) && oEvent.data > 0) {
    			this.terminate();
    			if (confirm("Errore sconosciuto. Vuoi riprovare?")) {
    				initWorker();
    			}
    			return;
    		}
    		faiQualcosa(oEvent.data);
    		this.postMessage("continua");
    	}
    
    	function initWorker () {
    		oReader = new Worker("getjson.js");
    		oReader.onmessage = switchMsg;
    	}
    
    	var oReader;
    
    	return initWorker;
    })();
    
    onload = retrieveJSON;
    </script>
    </head>
     
    <body>
    
    </body>
    </html>
    getjson.js:

    codice:
    function switchMsg (oEvent) {
    	/* Decommenta la linea seguente se vuoi generare un errore ogni tanto per il debug. Quando avrai finito cancella pure questo commento. */
    	/* if (Math.floor(Math.random() * 3) === 2) { postMessage(1); return; } */
    	if (oEvent.data === "continua") {
    		nextDispatch();
    	}
    }
    
    function getData () {
    	oMyData = JSON.parse(this.responseText);
    	nextDispatch();
    }
    
    function switchError (oErr) {
    	/* Se vuoi raffinare la gestione degli errori, invia un numero maggiore di zero univoco a seconda di oErr... */
    	postMessage(1);
    }
    
    function nextDispatch () {
    	if (!oMyData) { return; }
    	if (nIdx >= oMyData.length) {
    		postMessage(0);
    		return;
    	}
    	postMessage(oMyData[nIdx++]);
    }
    
    var
    	oMyData, nIdx = 0, oReq = new XMLHttpRequest();
    
    onmessage = switchMsg;
    onerror = switchError;
    
    oReq.onload = getData;
    oReq.onerror = switchError;
    oReq.open("get", "tuofile.json", true);
    oReq.send();
    tuofile.json:

    codice:
    [
    	{
    		"glossary": {
    			"title": "example glossary #1",
    			"GlossDiv": {
    				"title": "S",
    				"GlossList": {
    					"GlossEntry": {
    						"ID": "SGML",
    						"SortAs": "SGML",
    						"GlossTerm": "Standard Generalized Markup Language",
    						"Acronym": "SGML",
    						"Abbrev": "ISO 8879:1986",
    						"GlossDef": {
    							"para": "A meta-markup language, used to create markup languages such as DocBook.",
    							"GlossSeeAlso": ["GML", "XML"]
    						},
    						"GlossSee": "markup"
    					}
    				}
    			}
    		}
    	}, {
    		"glossary": {
    			"title": "example glossary #2",
    			"GlossDiv": {
    				"title": "S",
    				"GlossList": {
    					"GlossEntry": {
    						"ID": "SGML",
    						"SortAs": "SGML",
    						"GlossTerm": "Standard Generalized Markup Language",
    						"Acronym": "SGML",
    						"Abbrev": "ISO 8879:1986",
    						"GlossDef": {
    							"para": "A meta-markup language, used to create markup languages such as DocBook.",
    							"GlossSeeAlso": ["GML", "XML"]
    						},
    						"GlossSee": "markup"
    					}
    				}
    			}
    		}
    	}, {
    		"glossary": {
    			"title": "example glossary #3",
    			"GlossDiv": {
    				"title": "S",
    				"GlossList": {
    					"GlossEntry": {
    						"ID": "SGML",
    						"SortAs": "SGML",
    						"GlossTerm": "Standard Generalized Markup Language",
    						"Acronym": "SGML",
    						"Abbrev": "ISO 8879:1986",
    						"GlossDef": {
    							"para": "A meta-markup language, used to create markup languages such as DocBook.",
    							"GlossSeeAlso": ["GML", "XML"]
    						},
    						"GlossSee": "markup"
    					}
    				}
    			}
    		}
    	}
    ]
    Come vedi una parte del tuo lavoro consisterà nel decidere come spezzettare i dati. Il mio JSON di esempio è un array di tre elementi, quindi è facile spezzettarlo in tre invii. La funzione che se ne occupa è nextDispatch().
    Io non so com'è fatto il tuo file JSON, in ogni caso dovrai trovare un modo per spezzettarlo. Il punto non è il tempo che ci impieghi a leggere i dati, ma è il tempo che impieghi a riempire i grafici. E il worker sta lì ad aspettare che tu abbia finito prima di inviare un secondo pacchetto di dati. Spero sia tutto chiaro.


    Originariamente inviato da Jey
    Nel worker quindi non mi serve fare la richiesta dei dati al server, ma la parte di creazione dei div e del grafico...

    E' possibile o non c'è scampo??? xD
    No. il worker non può accedere al DOM della pagina principale. Ma spero ti sia chiaro che non è necessario.

    P.S. La gestione degli errori qui è grossolana: per qualsiasi tipo di errore riavvio il worker. Tu però puoi decidere di raffinarla inviando un codice numerico diverso a seconda del tipo di errore e, per esempio, nel caso di errore nella lettura del file puoi semplicemente far ripartire solamente AJAX invece dell'intero worker. Ma si tratta di sottigliezze: generalmente gli errori non ci dovrebbero proprio essere!
    Oppure puoi decidere di rimuovere del tutto la gestione degli errori.
    Tutto ciò che fai con jQuery puoi farlo meglio e con la metà del codice in puro JavaScript.

  7. #7
    Utente di HTML.it L'avatar di Jey
    Registrato dal
    Jan 2013
    Messaggi
    41
    Grazie dell'esempio, mi ha chiarito molto le idee!

    Ho fatto un po' di test e sembra fare quello che serve a me, ora provo a implementare tutto.

    Grazie mille!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.