У меня есть «виртуальный атрибут» в модели, и я хочу, чтобы установщик дождался обещания, прежде чем возвращать значение:
idShop:Ember.computed('shop',function(){
get(key){
return this.get('shop').id;
},
set(k,v){
this.get('store').findRecord('shop',key)
.then(shop =>{
this.set('shop', shop)
})
}
})
В наборе мне нужно вернуть либо k (ключ), либо shop.id после того, как findRecord и его then решены. Как я могу это сделать?





Так что это отличный вариант использования Ember Concurrency.
Параллелизм Ember (EC) использует функции генератора function * () {} внутри своего метода task(), чтобы упростить управление такими вещами. Задача также предоставляет несколько служебных свойств, чтобы показать, является ли он в настоящее время running или idle (также известный как загрузка данных или загрузка данных завершена).
Вот как я это настроил (код для ember 2.17 и новее)
import {task} from 'ember-concurrency';
import {computed} from '@ember/object';
# skip ahead to later in the code...
shop: null,
loadShop: task(function*(key) {
let shop = yield this.get('store').findRecord('shop', key)
this.set('shop', shop)
}),
shopId: computed('shop', function() {
if (this.get('shop') {
return this.get('shop.id);
} else {
return null;
}
})
В зависимости от вашего конкретного варианта использования вы должны вызвать this.get('loadShop').perform(id), когда знаете, какой будет идентификатор (вероятно, в ловушке инициализации или в отдельном методе)
(Примечание: это плохая практика изменять свойства как часть вычисляемого свойства. Вычисляемые свойства действительно не должны иметь состояния.)
С точки зрения дизайна это большой красный флаг. Я бы не стал использовать сеттер в этом случае, потому что он зависит от выполнения асинхронной задачи. Я вижу два варианта:
PromiseProxyMixin. (Это сильно усложнило бы ситуацию, и я бы не рекомендовал в этом случае)Было бы легче рассуждать, если бы вы отправили модель в это свойство вместо ключа. Если это проблема из-за того, что вы придерживаетесь помощника по вводу с двусторонней привязкой, посмотрите версию этого селектора DDAU, чтобы он вызывал действие, а не устанавливал свойство. Или оберните это в компонент, который знает, как преобразовать ключ в модель, а затем установить модель в связи после ее разрешения.
Я думаю, что @ donald-wasserman предлагал последнее в своем примере тлеющий параллелизм. Однако в вашем случае это не обязательно. Это дало бы некоторые преимущества (отмена), но я бы не увлекся частью решения, связанной с параллелизмом, а только дизайном того, как и где вы выполняете асинхронный поиск.
Об асинхронных зависимостях гораздо легче рассуждать, когда они выполняются как действие, а не как побочные эффекты вычисляемых свойств. CP на самом деле не предназначены для асинхронных вещей. Я знаю, что в некоторых случаях это может сойти с рук, используя прокси (например, ember-data), но он вводит уровень когнитивной нагрузки, который может быстро выйти из-под контроля. По умолчанию используются действия для асинхронных нужд.
Для ванильного выбора у вас должен быть слой перевода (следовательно, компонент), который может преобразовывать строковый ключ в поиск модели. Некоторые избранные надстройки сделают это за вас (например, уголь-сила-выбор). За перевод поиска отвечает компонент, а не модель, поэтому, вероятно, вы столкнулись с трудностями.
Что касается добавления метода к модели для выполнения асинхронного поиска: вы можете это сделать, но я бы сказал, что это, вероятно, плохой выбор дизайна, поскольку он смешивает / размывает линию ответственности. (т.е. Принцип единственной ответственности S.O.L.I.D.)
Другими словами, потребности избранного - это проблема презентации. Тот факт, что существует необходимость преобразовать строку (для логики представления) в модель (для бизнес-логики), на самом деле не является обязанностью модели. Модель должна просто хранить отношения. Это компонент, который отображает выборку, которая отвечает за преобразование моделей в формат, подходящий для целей отображения, и обратно.
вы пробовали использовать шаблон async / await?