Массовый асинхронный поиск или создание с помощью ember.js

Как выполнить массовый поиск или создание с помощью ember.js? Это было бы просто сделать синхронно (foreach... continue, если существует). Но работа с асинхронным хранилищем ember создает много накладных расходов на отслеживание состояния операции.

В частности, у меня есть переменная для отслеживания количества объектов, ожидающих обработки (createIfNotExistTaskCounter), поэтому я могу проверить, когда хранилище закончило работу со всеми объектами, которые нужно сохранить. И я использую массив для отслеживания элементов, хранящихся до сих пор (createIfNotExistQueue) - я не могу позволить магазину справиться с этой задачей, потому что я не могу рассчитывать на то, что элемент будет найден после его сохранения.

Вот мое лучшее решение ниже (также на JS Bin). Есть ли более простой способ сделать это?

App = Ember.Application.create({});

App.LSAdapter = DS.LSAdapter.extend({
    namespace: 'whitespace'
});

App.Store = DS.Store.extend({
    adapter: App.LSAdapter
});

App.Fruit = DS.Model.extend({
    name: DS.attr("string")
});


App.IndexRoute = Ember.Route.extend({
  createIfNotExistTaskCounter: 0, // store number of items waiting to be processed
  createIfNotExistQueue: [],      // store a list of the items being added, to prevent duplicate adds

  setupController: function(controller) {
    /* This is a simplified version of a real task I'm trying to acomplish. The code adds a list of objects to the store, only creating them if they don't exist. After the list has been processed, the contents of the store are shown.

    To achieve this end I've used a counter and a queue to keep track of the operations' state. Is there a simpler way to do this? These overheads seem excessive for such a straightforward bulk insert operation.
    */
    var fruitToStore = ["apple", "pear", "banana", "apple"],
      store = this.get('store');

    this.set('createIfNotExistTaskCounter', fruitToStore.length);

    for(var i=0; i<fruitToStore.length; i++) {
      this.createIfNotExist(fruitToStore[i]);
    }
  },

  createListener: function() {
    if(this.get('createIfNotExistTaskCounter') !== 0) return;

    this.get('store').find('fruit').then(function(results) {

      // should only print three fruits, one of each type
      for (var i = 0; i < results.content.length; i++) {
        console.log(results.content[i].get('name'));
      };
    });

  }.observes('createIfNotExistTaskCounter'),


  createIfNotExist: function(f) {
    var store = this.get('store'),
      queue = this.get('createIfNotExistQueue'),
      that = this;

    // prevent duplicate records being created by adding every (distinct) item to a queue
    // the queue is used because there seems to be no way to tell if an item is already (asynchonously) being found / created / saved
    if(queue.indexOf(f) !== -1) {
      that.decrementProperty('createIfNotExistTaskCounter');
      return;
    }
    queue.push(f);


    // find or create
    store.find('fruit', {name: f}).then(function(results) {

      // found...
      if(results.get('length') !== 0) {
        that.decrementProperty('createIfNotExistTaskCounter');
        return;
      }

      // ...else create
      var fruit = store.createRecord('fruit', {name: f});
      fruit.save().then(function() {
        that.decrementProperty('createIfNotExistTaskCounter');
      }, function() {
        console.log("save failed!");
      });

    });

  }
});

person Ollie Glass    schedule 17.10.2013    source источник


Ответы (1)


Если вы возвращаете обещание из обратного вызова then, вы можете создать цепочку обещаний, которая ведет себя как очередь.

Сначала вы начинаете с уже разрешенного обратного вызова, затем вы продолжаете заменять его объектом, способным «затем».

queue: new Ember.RSVP.resolve,
addToQueue: function() {
  this.queue = this.queue.then(function() {
    return new Ember.RSVP.Promise(function(resolve, reject){
      // something that eventually calls resolve
    })
  })
}

Вот мой обновленный JSBin вашего кода: http://jsbin.com/OtoZowI/2/edit?html,console

Вероятно, есть способ сделать это намного меньше, если вы сможете найти способ вернуть существующие обещания поиска/сохранения вместо создания нового. Я немного поиграл с этим, но мне нужно вернуться к работе: P

Кроме того, вы можете собрать кучу обещаний с помощью RSVP.all и решить только после того, как все они будут разрешены. В зависимости от вашего фактического кода это может быть гораздо более чистое решение - выполните все поиски, подождите, пока они все не будут разрешены, а затем создайте недостающие объекты.

В документах RSVP есть хороший пример этого здесь: https://github.com/tildeio/rsvp.js/blob/master/README.md#arrays-of-promises

person zaius    schedule 18.10.2013