编写具有外部依赖性的服务

时间:2016-03-09 12:37:27

标签: ember.js

我正在编写一项服务,以便为我的应用程序包含几个Google Places API调用。

类似的东西:

import Ember from 'ember';

export default Ember.Service.extend({
  googleAutocompleteService: null,
  placePredictions(query) {
    var self = this;
    return new Ember.RSVP.Promise(function(resolve, reject){
      ...
      self.get('googleAutocompleteService').getPlacePredictions(request, callback);
    });
  },
  init(){
    this._super(...arguments);
    this.set('googleAutocompleteService',
             new google.maps.places.AutocompleteService());
  },
});

现在我显然需要加载Google Maps API。目前我已将其纳入我的index.html

<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    {{content-for 'body'}}

    <script src="https://maps.googleapis.com/maps/api/js?key=...&libraries=places" async defer></script>

    ...

    {{content-for 'body-footer'}}
  </body>
</html>

有时我的服务会在map API初始化之前加载,从而导致错误。我可以简单地从标记中删除async defer并同步加载它,但必须有办法让我的服务加载外部库作为依赖项?

2 个答案:

答案 0 :(得分:4)

您可以将Google服务设置为计算的承诺属性。这是一种干净的方式,可以确保它只会延迟加载一次。

npm i ember-inject-script --save-dev

import Ember from 'ember';
import injectScript from 'ember-inject-script';

const {
  getOwner,
  computed,
  PromiseProxyMixin
  Service
} = Ember;

const ObjectPromiseProxy = ObjectProxy.extend(PromiseProxyMixin);
const GOOGLE_PLACES_SCRIPT_URL = 'https://maps.googleapis.com/maps/api/js?key=...&libraries=places';

export default Service.extend({
  googleAutocompleteService: computed(function() {
    return ObjectPromiseProxy.create(getOwner(this).ownerInjection(), {
      promise: injectScript(GOOGLE_PLACES_SCRIPT_URL).then(() => {
        return new window.google.maps.places.AutocompleteService();
      })
    });
  }),
  placePredictions(query) {
    return this.get('googleAutocompleteService').then((resolvedService) => {
      //...
      resolvedService.getPlacePredictions( /* ... */ );
      //...
      return {}; // return whatever you want the promise to resolve;
    });
  }
});

答案 1 :(得分:1)

我处理此问题的一种方法是在组件或路由生命周期挂钩中。

如果您在特定路线上使用地图,则可以在getScript / beforeModel挂钩中添加afterModel

beforeModel() {
   return Ember.$.getScript('https://maps.googleapis.com/maps/api/js?key=...&libraries=places');
}

现在,我不完全确定这是否能解决服务中的问题。

如果您的所有映射工作都包含在组件中,您可以使用didInitAttrs()挂钩尝试相同的操作。

在服务init()钩子中也可能值得尝试,但我不知道如果有一种方法让init等待承诺履行。