C’è un modo per creare elementi DOM in Web Worker?

Contesto: ho un’applicazione web che elabora e mostra enormi file di registro. Solitamente sono lunghi solo circa 100k linee, ma possono essere fino a 4 milioni di linee o più. Per poter scorrere il file di registro (sia avviato dall’utente che tramite JavaScript) e filtrare le linee con prestazioni decenti, creo un elemento DOM per ogni riga non appena arrivano i dati (in JSON tramite ajax). Ho trovato questo migliore per le prestazioni, quindi costruendo l’HTML sul back-end. Successivamente salvi gli elementi in un array e mostro solo le linee visibili.

Per un massimo di 100k linee questo richiede solo pochi secondi, ma tutto ciò richiede più di un minuto per 500k linee (escluso il download). Volevo migliorare ulteriormente le prestazioni, quindi ho provato a utilizzare Web Worker HTML5. Il problema ora è che non riesco a creare elementi in un Web Worker, nemmeno al di fuori del DOM. Così ho finito per fare solo la conversione json in HTML nel Web Workers e inviare il risultato al thread principale. Lì è creato e memorizzato in un array. Purtroppo questo ha peggiorato le prestazioni e ora ci vogliono almeno altri 30 secondi.

Domanda: Quindi c’è un modo, di cui non sono a conoscenza, per creare elementi DOM, al di fuori dell’albero DOM, in un Web Worker? Se no, perché no? Mi sembra che questo non possa creare problemi di concorrenza, poiché la creazione degli elementi potrebbe avvenire in parallelo senza problemi.

Bene, ho fatto ulteriori ricerche con le informazioni fornite da @Bergi e ho trovato la seguente discussione sulla mailing list del W3C:

http://w3-org.9356.n7.nabble.com/Limited-DOM-in-Web-Workers-td44284.html

E l’estratto che risponde perché non c’è accesso al parser XML o al parser DOM nel Web Worker:

Si presuppone che nessuno del codice di implementazione DOM utilizzi alcun tipo di oggetti non DOM, mai, o che, se lo fa, questi oggetti sono completamente sicuri. Questo non è il caso, almeno in Gecko.

Il problema in questo caso non è lo stesso object DOM che viene toccato su più thread. Il problema sono due oggetti DOM su thread diversi che toccano un terzo object globale.

Ad esempio, il parser XML deve fare alcune cose che in Gecko possono essere fatte solo sul thread principale (caricamento DTD, offhand, ce ne sono altre che ho già visto ma che non ricordo in anticipo).

Esiste tuttavia anche una soluzione alternativa, che utilizza un’implementazione di terze parti dei parser, di cui jsdom è un esempio. Con questo hai persino accesso al tuo documento separato.

Quindi c’è un modo, di cui non sono a conoscenza, per creare elementi DOM, al di fuori dell’albero DOM, in un Web Worker?

No.

Perchè no? Mi sembra che questo non possa creare problemi di concorrenza, poiché la creazione degli elementi potrebbe avvenire in parallelo senza problemi.

Non per averli creati, hai ragione. Ma per accodarli al document principale, dovrebbero essere inviati a una memoria diversa (come è ansible per i BLOB) in modo tale da essere inaccessibili dal lavoratore in seguito. Tuttavia, non c’è assolutamente alcuna gestione dei documenti disponibile in WebWorkers .

Creo un elemento DOM per ogni riga non appena arrivano i dati (in JSON tramite ajax). Successivamente salvi gli elementi in un array e mostro solo le linee visibili.

Costruire oltre 500k elementi DOM è un compito pesante. Prova a creare elementi DOM solo per le linee visibili. Per migliorare le prestazioni e mostrare le prime poche righe più velocemente, potresti anche ridurre la loro elaborazione in unità più piccole e utilizzare i timeout nel mezzo. Vedi Come fermare il ciclo intenso di Javascript dal blocco del browser

Devi capire la natura di un webworker. Programmare con i thread è difficile , soprattutto se si condivide la memoria; cose strane possono accadere. JavaScript non è in grado di gestire alcun tipo di interleaving thread-like.

L’approccio dei webworkers è che non c’è memoria condivisa . Ciò ovviamente porta alla conclusione che non è ansible accedere al DOM.

Non esiste un modo diretto per accedere al DOM attraverso i Web Worker. Recentemente ho rilasciato @ cycle / sandbox, è ancora WIP, ma si dimostra con l’architettura Cycle JS che è abbastanza semplice dichiarare il comportamento dell’interfaccia utente nel Web Worker. Il DOM corrente viene solo sfiorato nel thread principale, ma gli ascoltatori di eventi e gli aggiornamenti DOM vengono dichiarati indirettamente nel worker e un object evento sintetizzato viene inviato quando succede qualcosa su quegli ascoltatori. Inoltre, è in grado di montare questi componenti di ciclo regolari lato-a-fianco con i componenti del ciclo di lavorazione sandbox.

http://github.com/aronallen/-cycle-sandbox/

Non vedo alcun motivo per cui non sia ansible build stringhe html usando i web-worker. Ma penso anche che non ci sarebbe molto di un aumento delle prestazioni.

Questo non è legato ai Web-Worker, ma si riferisce al problema che stai cercando di risolvere. Ecco alcune cose che potrebbero aiutare ad accelerare le cose:

  1. Usa DocumentFragments. Aggiungi gli elementi quando arrivano i dati e aggiungi i frammenti al DOM a intervalli (come una volta al secondo). In questo modo non devi toccare il DOM (e sostenere un ridisegno) ogni volta che viene caricata una riga di testo.

  2. Esegui il caricamento in background e analizza solo le righe mentre l’utente raggiunge la parte inferiore dell’area di scorrimento.

Secondo https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers non c’è accesso al DOM da un web worker, sfortunatamente.

Hai un paio di anti-pattern nel tuo design:

  1. La creazione di un object DOM ha un notevole overhead e ne stai creando potenzialmente milioni in una volta .
  2. Cercare di convincere un web worker a gestire il DOM è esattamente ciò a cui non servono i web worker. Fanno tutto il resto così il ciclo di eventi DOM rimane reattivo.

È ansible utilizzare un modello di cursore per scorrere insiemi di dati arbitrariamente grandi .

  1. DOM invia un messaggio al lavoratore con posizione iniziale e numero di righe richieste (cursore).
  2. I log degli accessi casuali del web worker, restituiscono le righe recuperate (dati del cursore).
  3. DOM aggiorna un elemento con l’evento di risposta del cursore asincrono.

In questo modo, il lavoro pesante viene eseguito dall’operatore, il cui ciclo di eventi viene bloccato durante il recupero anziché nel DOM, il che si traduce in felici utenti non bloccati che si meravigliano della fluidità di tutte le animazioni.

Quindi non puoi creare direttamente DOM in un webworker – tuttavia, potrebbe esserci un’altra opzione per fare un bel po ‘di elaborazione al di fuori del thread principale.

Dai un’occhiata a questo jsPerf che ho appena creato: http://jsperf.com/dom-construction-obj-vs-str

Essenzialmente, potresti emettere POJSO che hanno tutti gli stessi valori che ottieni da un DOM e convertirlo in oggetti DOM dopo aver ricevuto il messaggio (questo è ciò che stai facendo quando ottieni il codice HTML, dopo tutto; i POJSO sono appena inferiori sovraccarico, in quanto non richiede un’ulteriore elaborazione delle stringhe). In questo modo si potrebbero anche fare cose come emettere listener di eventi e simili (ponendo, ad esempio, il prefisso del nome dell’evento con “!” E il valore mappare a un argomento di visualizzazione fornito dal modello).

Nel frattempo, senza il parser DOM disponibile, avrai bisogno di una tua parte per convertire un modello al bisogno, o per compilarne uno in un formato che sia veloce.

No, non è ansible creare elementi DOM in un web worker, ma è ansible creare una funzione che accetta il messaggio postale da quel web worker, che crea gli elementi DOM. Penso che il degno che tu stia cercando si chiama “chucking”. E avresti bisogno di mescolarlo con il modello di progettazione del web worker.