控制余烬承诺解决的顺序?

时间:2016-10-24 21:50:34

标签: javascript ember.js

我一直在使用ember 2.9.1,节点6.9.1,chrome 53.0.2785.143和OS / X 10.11.6来学习本教程。

当我创建此处描述的组件时: https://guides.emberjs.com/v2.8.0/tutorial/autocomplete-component/

我最终遇到了竞争条件。如果我将字符p输入到输入中并且非常快速地命中退格,我最终会得到由字符p过滤但在文本字段中没有输入的模型。

某些控制台日志记录表明这种情况正在发生,因为第二个promise(返回所有模型,因为输入为空)首先解析,第一个promise(返回已过滤的模型)解析为第二个。

有什么可以做的吗?

3 个答案:

答案 0 :(得分:1)

出于并发目的,有一个名为ember-concurrency的插件。您可以将它用于所有异步操作。

同样ember-power-select使用此插件。它是一个功能强大的自动完成选择组件。我可以建议你使用它。

编辑2016-10-25:这是使用ember-concurrency的更新代码,它解决了竞争条件(现在具有正确的属性名称):

import Ember from 'ember';
import { task } from 'ember-concurrency';

export default Ember.Component.extend({
  classNames: ['list-filter'],
  value: '',

  init() {
    this._super(...arguments);
    this.get('filter')('').then((results) => this.set('results', results));
  },

  handleFilterEntryTask: task(function * () {
    const filterInputValue = this.get('value');
    const filterAction = this.get('filter');

    const filterResults = yield filterAction(filterInputValue);
    this.set('results', filterResults);

  }).keepLatest(),

  actions: {
    handleFilterEntry() {
      this.get('handleFilterEntryTask').perform();
    }
  }
});

答案 1 :(得分:1)

ykaragolanswer之后,这是我使用ember-concurrency更新的代码,它解决了竞争条件:

import Ember from 'ember';
import { task } from 'ember-concurrency';

export default Ember.Component.extend({
  classNames: ['list-filter'],
  value: '',

  init() {
    this._super(...arguments);
    this.get('filter')('').then((results) => this.set('results', results));
  },

  handleFilterEntryTask: task(function * () {
    const filterInputValue = this.get('value');
    const filterAction = this.get('filter');

    const filterResults = yield filterAction(filterInputValue);
    this.set('results', filterResults);

  }).keepLatest(),

  actions: {
    handleFilterEntry() {
      this.get('handleFilterEntryTask').perform();
    }
  }
});

答案 2 :(得分:0)

刚刚提出了一个解决方案:存储针对组件的promise,并在解析它时检查它是否已被取代,只有在没有时才更改状态。是否有更好/更惯用的方式来做到这一点?

import Ember from 'ember';

export default Ember.Component.extend({
  classNames: ['list-filter'],
  value: '',
  currentPromise: null,

  init() {
    this._super(...arguments);
    this.get('filter')('').then((results) => this.set('results', results));
  },

  actions: {
    handleFilterEntry() {
      const filterInputValue = this.get('value');
      const filterAction = this.get('filter');

      const thePromise = filterAction(filterInputValue);
      this.set('currentPromise', thePromise);

      thePromise.then((filterResults) => {
        if (thePromise == this.get('currentPromise')) {
          this.set('results', filterResults);
        }
      });
    }
  }
});