Выполнение обещания извне отложить выполнение программы - PullRequest
0 голосов
/ 01 мая 2018

Мой угловой сервис содержит объект _mapView, который инициализируется после загрузки всего приложения со всеми его компонентами и зависимостями. Однако пользователь может уже нажимать кнопки и т. Д., Что приводит к вызовам get этого объекта mapView до полной загрузки приложения, поскольку mapView загружается асинхронно.

Моя цель состоит в том, чтобы, если объект еще не был инициализирован, программа возобновит работу после инициализации mapView.

@Injectable()
export class MapService {
   private _mapViewPromiseResolveFx;
   private _mapView: Promise<__esri.MapView> = new Promise(function(res, rej){
       this._mapViewPromiseResolveFx = res;
   }.bind(this)); // save a reference to the resolve function so the promise can be resolved from outside its function scope    

   public resolveMapView(mapView: __esri.MapView) {
      this._mapViewPromiseResolveFx(mapView);
   }

   public getMapView() {
      return this._mapView;
   }
}

Иногда при инициализации AppComponent эта переменная инициализируется:

self.mapService.resolveMapView(new MapView(mapViewProperties));

Итак, когда мне нужно mapView, я делаю:

this.mapService.getMapView().then(function(mapView) {

Кажется, это работает, но похоже на очень "хакерский" подход и неправильное использование обещаний. Какие еще лучшие варианты у меня есть?

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Это то, для чего используется отложенный шаблон. Он был реализован в jQuery и может быть antipattern , но имеет свои применения.

По существу, отложенное может быть возвращено вместо обещания, это похоже на то, что в настоящее время делает MapService, но будет один отложенный объект, который отвечает за обработку этого обещания:

class Deferred<T = {}> {
  resolve!: (val: T) => void;
  reject!: (err: any) => void;
  promise = new Promise<T>((resolve, reject) => {
    this.resolve = resolve;
    this.reject = reject;
  });
}

@Injectable()
export class MapService {
   mapView = new Deferred<__esri.MapView>();
}

Поскольку это вопрос Angular, следует заметить, что RxJS постоянно используется в приложениях Angular. Это может быть воспринято как альтернатива обещаниям, которые делают все, что обещания делают, и даже больше. Прямой аналог отсрочек и в RxJS - AsyncSubject. Когда тема завершена, она выдает подписчикам одно значение.

Так будет:

@Injectable()
export class MapService {
   mapView = new AsyncSubject<__esri.MapView>();
}

Это должно быть решено с помощью:

mapService.mapView.next(...);
mapService.mapView.complete();

Если оно уже используется в качестве обещания, AsyncSubject можно легко переключить на обещание, поскольку это наблюдаемое, которое дополняется одним значением:

const view = await mapService.mapView.toPromise();

В представлениях как наблюдаемые, так и обещания могут обрабатываться async pipe, {{ mapService.mapView | async }}.

Кажется, это работает, но похоже на очень "хакерский" подход и неправильное использование обещаний.

Существует вероятность того, что обещание используется не по назначению, и это превращается в антипаттерн, как это часто бывает в случае отсрочек.

Служба Angular может выступать в качестве модели MV *, поэтому MapService не должен принимать картографические данные извне, но должен отвечать за инициализацию и содержание картографических данных. В этом случае он должен создавать экземпляр MapView во время инициализации приложения и предоставлять обещание MapView экземпляр.

0 голосов
/ 01 мая 2018

Это нормально и явно разрешено, хотя в целом нецелесообразно выполнять ввод / вывод неявно.

Чего не хватает:

  • Вы хотите сделать this._mapView.catch(() => {}), чтобы не показывать необработанные отклонения (когда вы создаете обещание по практическому правилу, всегда обрабатывайте случай, когда оно заканчивается отклонением.
  • Как правило, ввод / вывод в процессе инициализации или конструктора сбивает с толку. Я бы сказал, что это нарушает «принцип наименьшего удивления».

Я бы порекомендовал что-то вроде статического init асинхронного метода, который инициализирует обещание при первом вызове, когда потребители имеют возможность обрабатывать ошибки.

...