2012-05-05 17 views
5

Introduzione
Ho una (principalmente) pagina singola application creata con BackboneJS e un backend Rails.Come migliorare le prestazioni dell'applicazione a pagina singola?

Poiché la maggior parte dell'interazione avviene su una pagina dell'app Web, quando l'utente visita per la prima volta la pagina, in pratica, devo estrarre una tonnellata di informazioni dal database in un'unica grande query profondamente unita.

Questo mi causa dei tempi di caricamento piuttosto estremi su questa pagina.

load times

NewRelic sembra essere a dirmi che la maggior parte dei miei problemi sono a causa di 457 singole chiamate metodo veloce.

fast methid calls

ora ho fatto tutto il eager loading posso fare (ho controllato con il Bullet gem) e ho ancora un problema.

Queste chiamate di metodo si verificano molto probabilmente nel mio serializzatore Rabl che utilizzo per serializzare un gruppo di JSON da incorporare nella pagina per l'inizializzazione di Backbone. Non è necessario comprendere tutto questo, ma è sufficiente dire che potrebbe aggiungere fino a 457 chiamate di metodo.

object @search 
attributes :id, :name, :subscription_limit 

# NOTE: Include a list of the members of this search. 
child :searchers => :searchers do 
    attributes :id, :name, :gravatar_icon 
end 

# Each search has many concepts (there could be over 100 of them). 
child :concepts do |search| 
    attributes :id, :title, :search_id, :created_at 

    # The person who suggested each concept. 
    child :suggester => :suggester do 
    attributes :id, :name, :gravatar_icon 
    end 

    # Each concept has many suggestions (approx. 4 each). 
    node :suggestions do |concept| 
    # Here I'm scoping suggestions to only ones which meet certain conditions. 
    partial "suggestions/show", object: concept.active_suggestions 
    end 

    # Add a boolean flag to tell if the concept is a favourite or not. 
    node :favourite_id do |concept| 
    # Another method call which occurs for each concept. 
    concept.favourite_id_for(current_user) 
    end 
end 

# Each search has subscriptions to certain services (approx. 4). 
child :service_subscriptions do 
    # This contains a few attributes and 2 fairly innocuous method calls. 
    extends "service_subscriptions/show" 
end 

Quindi sembra che io debba fare qualcosa a riguardo ma non sono sicuro di quale approccio adottare. Ecco un elenco di potenziali idee che ho:

Idee di miglioramento delle prestazioni

Dumb-Down dell'interfaccia
forse posso trovare dei modi per presentare le informazioni per l'utente che non richiedono l'attuale i dati devono essere presenti Non vedo perché dovrei assolutamente farlo, altre app a pagina singola come Trello hanno interfacce incredibilmente complicate.

Impaginazione del concetto
Se impagina i concetti ridurrà la quantità di dati che vengono estratti dal database ogni volta. Produrrebbe comunque un'interfaccia utente inferiore.

Caching
Al momento, l'aggiornamento della pagina estrae nuovamente l'intera ricerca dal DB. Forse posso memorizzare nella cache parti dell'app per ridurle sugli hit di DB. Ciò sembra complicato, anche perché non molti dei dati con cui ho a che fare sono statici.

richiesto più
è tecnicamente male per servire la pagina senza incorporare il JSON nella pagina, ma forse l'utente si sentirà come le cose stanno accadendo più velocemente se io caricare la pagina non popolata e quindi recuperare i dati.

Indici
Dovrei assicurarmi di avere indici su tutte le mie chiavi esterne. Dovrei anche provare a pensare a luoghi in cui sarebbe utile avere indici (come i preferiti?) E aggiungerli.

Move Method Chiama nel DB
Forse posso memorizzare nella cache alcuni dei risultati dell'iterazione che faccio nel mio livello di vista nel DB e semplicemente estrarli invece di calcolarli.O potrei sincronizzare le cose su scrittura piuttosto che su lettura.

Domanda
Qualcuno ha qualche suggerimento su cosa dovrei spendere il mio tempo su?

risposta

1

Questa è una domanda difficile a cui rispondere senza essere in grado di vedere l'interfaccia utente reale, ma vorrei concentrarmi sul caricamento esattamente solo quanti dati necessari per visualizzare l'interfaccia iniziale. Ad esempio, se l'utente deve eseguire il drill-down per vedere alcuni dei dati che si presentano, è possibile caricare tali dati su richiesta, anziché caricarli come parte del payload iniziale. Hai detto che una ricerca può avere fino a 100 "concetti", forse non hai bisogno di recuperare tutti questi concetti inizialmente?

In conclusione, non sembra che il tuo problema sia davvero sul lato client - sembra che il tuo codice lato server stia rallentando, quindi vorrei esplorare che cosa puoi fare per recuperare meno dati, o rimandare le query complesse fino a quando non sono assolutamente necessarie.

1

Si consiglia di separare il codice JS in moduli caricati in modo dinamico utilizzando un patrimoniale come RequireJS. In questo modo non avrai molte XHR attive al momento del caricamento.

Quando è necessario un modulo specifico, è possibile caricarlo e inizializzarlo in un momento opportuno anziché ogni carico di pagina.

Se complicate un po 'il vostro codice, ogni modulo dovrebbe essere in grado di avviarsi e fermarsi. Pertanto, se si verificano eventi in codice polling o complessi, è possibile arrestare il modulo per aumentare le prestazioni e ridurre il carico di rete.

+0

Mentre concordo sul fatto che l'ottimizzazione dell'assegnazione delle risorse è un passo importante verso l'aumento delle prestazioni, non penso che sia il problema principale che ho qui. Mentre c'è un'accensione di JS nell'app, è gzip, minimizzato e arriva a ~ 100kb. Dovrebbe inoltre essere memorizzato nella cache sul lato client in modo che il costo del caricamento sia ridotto al minimo per i visitatori abituali. –

Problemi correlati