【问题标题】:Return a function from a rxjs subscription从 rxjs 订阅返回一个函数
【发布时间】:2018-03-08 15:38:42
【问题描述】:

这是一个关于使用 angular-l10n 翻译模块的问题,但由于它是一个更具体的打字稿问题,所以我在这里发布。

要动态配置模块(例如设置默认语言),我必须使用以下方法:

load(): Function {
  this.localeConfig.language = 'en';
  return () => this.l10nLoader.load();
}

localeConfigl10nLoader 都被注入了。

return () => this.l10nLoader.load();必须在最后执行才能真正显示配置后的页面。

我想做的是从 api 加载语言,然后设置配置。

我在一个返回 Observable 的服务中执行此操作,然后在 load() 函数中订阅它。

load(): Function {
  this.languageService.getDefaultLanguage().subscribe(
    lang => {
      this.localeConfig.language = lang;
      return ???
    }
  );
}

问题是:订阅结束时不知道如何返回this.l10nLoader.load();。如果我在函数结束时返回它,它会在订阅结束之前完成。

订阅完成后如何返回函数类型的东西?

【问题讨论】:

  • 你为什么不在那里调用this.l10nLoader.load() 而不是返回包装在箭头函数中的相同内容?退货有什么价值吗?
  • 在没有 return 语句的情况下做:load(): Function { this.localeConfig.language = 'en'; this.l10nLoader.load(); } 有什么问题吗?我试图在这里理解高阶函数的要求。
  • @sabithpocker 我想最简单的解释方法是如果我链接到文档:robisim74.github.io/angular-l10n/spec/configuration。它在“动态设置”下的第二部分“使用高级初始化”。

标签: javascript angular typescript rxjs


【解决方案1】:

return 不能这样做,因为load() 函数是异步的。我建议做的是将load() 返回值更改为Observable<Function> 并在其中创建new Observable

这里是sn-p的代码:

load(): Observable<Function> {
   return new Observable(observer => {
       this.languageService.getDefaultLanguage().subscribe(
          lang => {
             this.localeConfig.language = lang;
             observer.next(this.l10nLoader.load);
             observer.complete();
          }
       );
   });
}

之后你可以通过以下方式调用这个函数:

load().subscribe(fn => fn());

【讨论】:

  • 这似乎是正确的,但this.l10nLoader.load() 仍然在配置设置之前执行......这很奇怪,因为我不明白这是怎么发生的。我更改了observer.next(() =&gt; this.l10nLoader.load());,否则它将返回 Promise 而不是 Function。这和它有什么关系吗?
  • 其实我知道问题出在哪里。 load().subscribe(fn =&gt; fn()); 运行异步,我必须等待一切完成。否则页面在配置完成之前加载。
  • 如果您需要在加载其他所有内容之前先加载和设置语言环境,您应该查看解析器。在这里查看我的答案:stackoverflow.com/questions/47170450/…
【解决方案2】:

在 Vanilla JS 中,您为此使用回调。

例如,你可以这样做:

load(cb: Function): Function {
  this.languageService.getDefaultLanguage().subscribe(lang => {
    this.localeConfig.language = lang;
    cb(lang);
  });
}

现在,你可以这样调用你的函数:

this.myL10nService.load(lang => {
  console.log('selected language is ' + lang);
});

【讨论】:

  • 让我觉得在已经使用 rxjs 时不使用它毫无意义。为什么要回到普通的回调而不是使用订阅?
  • 因为你应该知道 Javascript 的基础知识,而当你开始时你不应该知道 rxjs。此外,本机代码总是比库或框架更快,并且您将通过不导入无用的库来减少包的大小。但这是我的观点,如果不分享我不介意!
  • 但是 rxjs 已经存在了。它被直接用于获取默认语言。
  • 没看到,但仍然没有改变关于性能和知识的观点!
  • 性能作为一个论点,坦率地说是荒谬的。在某种程度上,“知识”也是如此。如果出于知识原因使用香草 Javascript 更好,为什么要使用 any 框架?但我们不在这里讨论这个。
【解决方案3】:

我找到了一个可行的解决方案。
使用 .toPromise() 而不是 .subscribe() 然后返回 l10nLoader.load(); 作为 Promise 的结果解决了我的问题。

语言配置服务:

@Injectable()
export class LocalizationConfig {
  constructor(
      public l10nLoader: L10nLoader,
      @Inject(TRANSLATION_CONFIG) private translationConfig: TranslationConfig,
      @Inject(LOCALE_CONFIG) private localeConfig: LocaleConfig,
      private language: LanguageService
  ) { }

  load(): Promise<void> {
    return this.language.getUserLanguages().toPromise()
    .then(
      res => {
        this.localeConfig.language = res.language;
        return this.l10nLoader.load(); // this is important!!
      })
    .catch(  
      err => {
        // set default language or desired strategy
        return this.l10nLoader.load();   
      }
    );
  }
}

export function initLocalization(localizationConfig: LocalizationConfig): Function {
  return () => localizationConfig.load();
}

app.module:

providers: [
  ...
  {
    provide: APP_INITIALIZER,
    useFactory: initLocalization,
    deps: [LocalizationConfig],
    multi: true,
  },
  ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-20
    • 1970-01-01
    • 2019-08-20
    • 1970-01-01
    • 2018-09-04
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多