我一直在使用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(返回已过滤的模型)解析为第二个。
有什么可以做的吗?
答案 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)
继ykaragol的answer之后,这是我使用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);
}
});
}
}
});