2013-02-11 11 views
41

Mam pytanie dotyczące ładowania i buforowania odległych obiektów za pomocą Ember. Zajmuję się tworzeniem aplikacji Ember, która wykorzystuje pamięć masową po stronie serwera za pośrednictwem interfejsu API REST. Niektóre z pobieranych danych rzadko się zmieniają, więc pobieranie ich z serwera za każdym razem, gdy aplikacja się ładuje, jest niepotrzebne. Jest to jednak również pytanie dotyczące aplikacji, które muszą pracować w trybie offline i nadal zapisywać dane na serwerze.Buforowanie danych zdalnych w pamięci lokalnej za pomocą EmberData

Ember Data ma wbudowaną kartę pamięci do utrzymywania modeli za pośrednictwem interfejsu API REST, a także jest an adapter for Local Storage (jak wskazał Ken poniżej). Problem (jeśli jest to problem) polega na tym, że model ma tylko jedną kartę pamięci i nie istnieje żadna koncepcja buforowania pobranych modeli innych niż przechowywanie ich w pamięci.

Znalazłem podobne żądania w tym Ember wishlist iw komentarzach do tego talk by Tom Dale, ale nie znalazłem żadnych wskazań, że byłaby to istniejąca funkcja w Ember.

Mam dwa pytania (pierwszy będąc ważny):

  1. Jaki jest najlepszy sposób - dziś - wdrożenie modeli buforowane w pamięci lokalnej i synchronizowania ich z odległych danych, ile potrzeba?
  2. Czy jest to funkcja zaplanowana do uwzględnienia w Ember, czy przynajmniej coś, co zdaniem opiekunów powinno zostać ostatecznie dodane?

Kiedy przychodzi do 1), mogę myśleć o kilka strategii:

a) rozszerzyć istniejącą kartę i dodać niestandardową Mechanizm zdalnego Sync:

App.Store.registerAdapter('App.Post', DS.LSAdapter.extend({ 
    // do stuff when stuff happens 
})); 

b) utrzymuje oddzielne klasy modeli - jeden zestaw dla obiektów zdalnych i jeden zestaw dla obiektów lokalnych - i w razie potrzeby zsynchronizuj między nimi. Ze standardowym przypadku Todo:

RemoteTodo –*sync*– Todo 
        | 
        UI 

jestem trochę nadzieję, że to jest prawdziwe pytanie noobem i że nie jest to dobry wzór ustalony dla tego produktu.

Zaktualizowane: Znaleziono this similar question. Ma dobrą odpowiedź, ale jest to trochę teoretyczne. Myślę, że potrzebuję kilku praktycznych wskazówek lub wskazówek do przykładowych wdrożeń.

Odpowiedz

3

Istnieje implementacja lokalnej karty pamięci, która może okazać się przydatna. Wystarczy popatrzeć na https://github.com/rpflorence/ember-localstorage-adapter

+0

Dzięki za wskazówki - I rzeczywiście th Powinien, że adapter był częścią właściwego Ember Data. Odpowiednio zaktualizuję moje pytanie.To naprawdę nie rozwiązuje mojego problemu, ponieważ szukam dobrego sposobu na użycie backendu REST z buforowaniem LS - nie przechowuj moich danych wyłącznie w LS. –

+0

Możesz użyć innego adaptera w tej samej aplikacji, aby przypisać wybrany adapter do określonego modelu. – ken

+4

Yup. Tak właśnie wdrożysz b) w moim pytaniu. Nadal zastanawiam się nad najlepszym podejściem. –

5

tylko „podbić” ten wątek się trochę, bo był to jeden z najlepszych wyników, kiedy badałem rozwiązania dla ember lokalnej pamięci podręcznej spokojny API itp .:

Dan Gebhardt wydaje zrobić krwawą dobrą robotę z Orbit.js i jego integracji Ember: https://github.com/orbitjs/ember-orbit

Orbit jest samodzielnym biblioteki za koordynację dostęp do źródeł danych i utrzymywanie ich zawartości zsynchronizowane.

Orbit stanowi podstawę do budowania zaawansowanych funkcji w aplikacji po stronie klienta, takich jak offline, eksploatacji, konserwacji i synchronizacji lokalnej pamięci podręcznej, cofania/powtarzania stosy i doraźne edycji konteksty.

Orbit.js cechy:

  • Pomoc dowolną liczbę różnych źródeł danych w aplikacji i zapewnić dostęp do nich za pośrednictwem wspólnych interfejsów.

  • Umożliwia spełnienie żądań z różnych źródeł, w tym możliwość określenia planów priorytetów i planów awaryjnych.

  • Umożliwia równoczesne istnienie rekordów w różnych stanach w różnych źródłach.

  • Transformacje współrzędnych dla różnych źródeł. Uchwyt łączy się automatycznie w miarę możliwości, ale pozwala na pełną kontrolę niestandardową.

  • Umożliwia blokowanie i nie blokowanie transformacji.

  • Zezwalaj na żądania synchroniczne i asynchroniczne.

  • Obsługa transakcji i cofanie/ponawianie przez śledzenie inwersji operacji.

  • Praca ze zwykłymi obiektami JavaScript.

i nie przegap swoją wielką mowę i slajdy o orbita:
Introduction to Orbit.js

(UPDATE: dodałem trochę bardziej opisowe informacje ze stron orbicie, jako mój wpis został downvoted dla "tylko" odwoływania się do zasobów zewnętrznych i niezawierającego samego rozwiązania, ale Orbit wydaje mi się rozwiązaniem, a jedynym sposobem na "uwzględnienie" tego jest link.)

+0

Podczas gdy te linki mogą odpowiedzieć na pytanie, lepiej umieścić tutaj istotne części odpowiedzi i podać link do odsyłacza. Odpowiedzi dotyczące linków mogą stać się nieprawidłowe, jeśli strona z linkami się zmieni. – Onik

1

Oto sposób na zrobienie tego. Mixin dla twoich adapterów, z metodą localStoreRecord możesz użyć do buforowania rekordu, na końcu inicjalizatora do wstępnego załadowania sklepu.

Pamięć lokalna jest po prostu kluczem: magazyn wartości dla obiektów usztywnionych, dzięki czemu możemy przechowywać wszystkie dane aplikacji pod jednym kluczem.

Uwaga: to jest za pomocą modułów ES6

// app/mixins/local-storage.js 
 

 
import Ember from 'ember'; 
 

 
export default Ember.Mixin.create({ 
 
    appName: 'myApp', 
 
    // how many records per model to store locally, can be improved. 
 
    // needed to prevent going over localStorage's 5mb limit 
 
    localStorageLimit: 5, 
 
    localStoreRecord: function(record) { 
 
    var data = JSON.parse(localStorage.getItem(this.appName)); 
 
    data = data || {}; 
 
    data[this.modelName] = data[this.modelName] || []; 
 
    var isNew = data[this.modelName].every(function(rec) { 
 
     rec.id !== record.id; 
 
    }); 
 
    if (isNew) { 
 
     data[this.modelName].push(record); 
 
     if (data[this.modelName].length > this.localStorageLimit) { 
 
     data[this.modelName].shift(); 
 
     } 
 
     localStorage.setItem(this.appName, JSON.stringify(data)); 
 
    } 
 
    } 
 
});

// app/adapters/skateboard.js 

import DS from 'ember-data'; 
import Ember from 'ember'; 
import LocalStorageMixin from '../mixins/local-storage'; 

export default DS.RESTAdapter.extend(LocalStorageMixin, { 
    modelName: 'skateboard', 
    find: function(store, type, id) { 
    var self = this; 
    var url = [type,id].join('/'); 
    return new Ember.RSVP.Promise(function(resolve, reject) { 
     Ember.$.ajax({ 
     url: 'api/' + url, 
     type: 'GET' 
     }).done(function (response) { 
     // cache the response in localStorage 
     self.localStoreRecord(response); 
     resolve({ type: response }); 
     }).fail(function(jqHXR, responseStatus) { 
     reject(new Error(type + 
     ' request failed with status=' + reponseStatus); 
     }); 
    }); 
    }, 
    updateRecord: function(store, type, record) { 
    var data = this.serialize(record, { includeId: true }); 
    var id = record.get('id'); 
    var url = [type, id].join('/'); 
    return new Ember.RSVP.Promise(function(resolve, reject) { 
     Ember.$.ajax({ 
     type: 'PUT', 
     url: 'api/' + url, 
     dataType: 'json', 
     data: data 
     }).then(function(data) { 
     // cache the response in localStorage 
     self.localStoreRecord(response); 
     resolve({ type: response }); 
     }).fail(function(jqXHR, responseData) { 
     reject(new Error(type + 
     ' request failed with status=' + reponseStatus); 
     }); 
    }); 
    } 
}); 

// app/initializers/local-storage.js 
 

 
export var initialize = function(container/*, application*/) { 
 
    var appName = 'myApp'; 
 
    var store = container.lookup('store:main'); 
 
    var data = JSON.parse(localStorage.getItem(appName)); 
 
    console.log('localStorage:',data); 
 
    if (!data) { 
 
    return; 
 
    } 
 
    var keys = Object.keys(data); 
 
    if (keys.length) { 
 
    keys.forEach(function(key) { 
 
     console.log(key,data[key][0]); 
 
     store.createRecord(key, data[key][0]); 
 
    }); 
 
    } 
 
}; 
 

 
export default { 
 
    name: 'local-storage', 
 
    after: 'store', 
 
    initialize: initialize 
 
};

+1

Byłoby dobrze dodać trochę wyjaśnienia. –

Powiązane problemy