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

コールバックから promise を返す場合then、キューのように動作する一連の promise を作成できます。

まず、解決済みのコールバックから始めて、それを「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

于 2013-10-18T07:55:51.197 に答える