异步代码在TS中没有按预期顺序工作

时间:2017-08-04 06:04:55

标签: typescript asynchronous dependency-injection async-await ionic3

尝试使用Provider从firebase服务器获取数据,该服务器使用4级嵌套回调函数。以下是我的提供商的样子。

import { Injectable } from '@angular/core';

declare var window;

@Injectable()
export class SettingsProvider {

  constructor() {

  }

  public async getFireBaseRemoteConfig(): Promise<any> {
    if (window["FirebasePlugin"]) {
      await window["FirebasePlugin"].fetch(600, async result => {
        // activate the fetched remote config
        console.log(JSON.stringify(result)); //Always "OK"
        await window["FirebasePlugin"].activateFetched( async (bool) => {

          await this.getSliderImageURLs().then((d) => {
            console.log("d", d);
            return d;
          });
        });
      })
    }
  }

  public async getSliderImageURLs(): Promise<any> {

    var urls = [];

    await window["FirebasePlugin"].getValue("slider_images", result => {
      urls = JSON.parse(result);
      console.log("FROM getSliderImageURLs()");
      console.log(urls)
      return Promise.resolve(urls);
    })
  }
}

我期望执行的顺序是getFireBaseRemoteConfig函数仅在getSliderImageURLs函数获取数据并返回时才返回。

根据文档,函数应按此顺序执行:

fetch - &gt; activateFetched - &gt;的getValue

在我的页面中,我正在使用它。

console.log(this.settingsProvider.getFireBaseRemoteConfig()); // Just for testing

我做错了什么?任何帮助都非常感谢。

编辑:添加了控制台日志

OK
d undefined
FROM getSliderImageURLs()
["","","",""] //this is my URLs array

1 个答案:

答案 0 :(得分:2)

看起来你正在使用传统的promise结构和async / await错误地在一起。您可以或使用Async / await(下面的答案1,但是你必须将回调转换为promises)或者你可以使用传统的promises(回答2),或者使用新的离子本机firebase插件(回答3)来转换回复承诺给你。

  1. 异步/等待结构
  2. 当你使用异步等待时,代码将像同步一样执行,因此不需要在异步等待中使用.then()。你的代码将变成这样的东西。

      public async getFireBaseRemoteConfig(): Promise<any> {
            if (window["FirebasePlugin"]) {
              let remoteConfig = await window["FirebasePlugin"].fetch(600);
              let sliderImageUrls = await this.getSliderImageURLs();
              // From here you can do whatever you want with remoteConfig & sliderImageUrls, as they are resolved with async/await
              return sliderImageUrls;
        }
    
        public async getSliderImageURLs(): Promise<any> {
            let sliderImagesJson = await window["FirebasePlugin"].getValue("slider_images")
            let sliderImages = JSON.parse(sliderImagesJson);
              return Promise.resolve(sliderImages);
            })
          }
    

    这种await / async方法仅在链接promises时才会优先,在你的情况下链接回调。因此,对于这个工作的答案,你需要将回调更改为这样的承诺:

    //Convert the fetch Remote Config callback to a promise
      public getRemoteConfig(cacheExpirationSeconds:number=600):Promise<any> {
        return new Promise<boolean>((resolve, reject) => {
          window["FirebasePlugin"].fetch(cacheExpirationSeconds,(result) => resolve(result))
        });
      }
    

    在您的示例中,我建议采用更传统的承诺结构,如下所示:

    1. 传统承诺结构(没有异步/等待)

       public getFireBaseRemoteConfig(): Promise<any> {
      return new Promise<any>((resolve, reject) => {
        if (window["FirebasePlugin"]) {
          window["FirebasePlugin"].fetch(600, (result) => {
            // activate the fetched remote config
            console.log(JSON.stringify(result)); //Always "OK"
            window["FirebasePlugin"].activateFetched((bool) => {
              this.getSliderImageURLs().then((d) => {
                console.log("d", d);
                resolve(d);
              });
            });
          })
        }
        else {
          reject();
        }
      });
      

      }

    2. // getSlider函数:

       public getSliderImageURLs(): Promise<any> {
          return new Promise<any>((resolve, reject) => {
            var urls = [];
            window["FirebasePlugin"].getValue("slider_images", (result) => {
              urls = JSON.parse(result);
              console.log("FROM getSliderImageURLs()");
              console.log(urls)
              resolve(urls);
            });
          });
        }
      
      1. 使用Ionic native firebase
      2. 使用新的(目前处于测试阶段)firebase原生插件,它已经将回调转换为承诺,因此您可以使用答案1.

        编辑:一个澄清传统承诺与传统之间差异的例子。同步/等待

        传统承诺结构中的一个例子:

        getPrice(currency: string): Promise<number> {
          return this.http.get(this.currentPriceUrl).toPromise()
            .then(response => response.json().bpi[currency].rate);
        }
        

        与async / away相同:

        async getPrice(currency: string): Promise<number> {
          const response = await this.http.get(this.currentPriceUrl).toPromise();
          return response.json().bpi[currency].rate;
        }
        

        example

        的来源

        希望这有帮助