2

如何使用 ember.js 执行批量查找或创建?这很容易同步进行(foreach...如果存在则继续)。但是使用 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!");
      });

    });

  }
});
4

1 回答 1

2

如果你从回调中返回一个thenPromise,你可以创建一个行为类似于队列的 Promise 链。

首先你从一个已经解决的回调开始,然后你继续用一个“then”-able对象替换它。

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 收集一堆 Promise,并仅在它们全部解决后才解决。根据您的实际代码,这可能是一个更简洁的解决方案 - 完成所有查找,等到它们全部解决,然后创建丢失的对象。

RSVP 文档在这里有一个很好的例子:https ://github.com/tildeio/rsvp.js/blob/master/README.md#arrays-of-promises

于 2013-10-18T07:55:51.197 回答