2016-10-24 8 views
1

Я слежу за учебником, используя ember 2.9.1, узел 6.9.1, chrome 53.0.2785.143 и OS/X 10.11.6.Контролировать порядок разрешения обещаний ember?

Когда я создаю компонент, описанный здесь: https://guides.emberjs.com/v2.8.0/tutorial/autocomplete-component/

Я в конечном итоге с условием гонки. Если я ввожу символ p во вход и очень быстро ударяю назад, я получаю модели, отфильтрованные символом p, но не вводят в текстовое поле.

Некоторое консольное ведение журнала предполагает, что это происходит, потому что второе обещание (которое возвращает все модели, поскольку вход пуст) разрешает сначала, и первое обещание (возврат фильтрованных моделей) разрешается вторым.

Есть ли что-нибудь, что можно сделать по этому поводу?

ответ

1

Для целей параллелизма, есть аддон: ember-concurrency. Вы можете использовать его для всех своих асинхронных операций.

Также ember-power-select использует этот аддон. Это мощный, автоматически заполняемый компонент. Я могу предложить вам использовать его.

Edit 2016-10-25: вот обновленный код с помощью уголек-параллелизм, который решает состояние гонки (теперь с правильным именем свойства):

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

я собираюсь принять это, но я хотел бы, чтобы отправить полученный исходный код тоже! Я поставлю его в другом ответе, но не стесняйтесь копировать его в свои. –

+0

Если вы хотите, не стесняйтесь редактировать мой ответ. – ykaragol

+0

Обратите внимание, что вы можете удалить избыточность операции 'handleFilterEntry', просто выполнив' handleFilterEntryTask' и просто используйте 'perform handleFilterEntryTask' где угодно, вы бы хотели использовать' action 'handleFilterEntry''. Кроме того, в более поздних Embers (я думаю,> = 2.4?) Вы можете просто использовать 'action handleFilterEntryTask', и это сработает. –

0

Только что придумал одно решение: сохраните обещание против компонента и убедитесь, что он не был заменен при его разрешении, только если он не изменил состояние. Есть ли лучший/более идиоматический способ сделать это?

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); 
     } 
     }); 
    } 
    } 
}); 
1

В дополнение к ykaragol «s 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(); 
    } 
    } 
});