【问题标题】:Can't save result from async function to object无法将异步函数的结果保存到对象
【发布时间】:2021-06-21 04:43:08
【问题描述】:

如果我知道如何解决它,我在家里。 我现在的问题是保存异步函数的结果。 如果我在该函数之后执行console.log,那么我将收到翻译后的值,但片刻之后,当我检查我的动词在打包成对象后的样子时,我将收到未翻译的值。有人知道为什么吗?

private translate(file: any) {

    const keys  = Object.keys(file)
    const values = Object.values(file) // [!] - English Value at start, it's ok

    values.forEach( async (value, index) => {
      if( typeof(value) === 'object') {
        value = this.translate(value)           
      } else {
        const translateResult = await this.GetTranslatedByResstring(keys[index], 1045).toPromise()
        value = translateResult.getPhrase() 
        console.log(value)  //  [!] <- Polish Value, it's ok
      }
    })

    const zipObj = xs => ys => xs.reduce( (obj, x, i) => ({ ...obj, [x]: ys[i] }), {})
    const obj = zipObj (keys) (values) 
    console.log(obj) //  [!] <- English Value, it's not ok, i need Polish value inside
    return obj
  }

#更新 1

调用翻译的地方:

public async getTranslatedJson(
    sourceFile: File,
    originLanguage: Language,
    destinatonLanguage: Language
  ): Promise<string> {
    const file = await this.getFile(sourceFile)
    const parsedFile = JSON.parse(file)
    const translatedFile = this.translate(parsedFile)
    return null
  }

#更新 2

我的 getFile 函数:

private getFile(
    sourceFile: File
  ): Promise<string> {
    return new Promise((resolve) => {
      const file = sourceFile[0]
      const fileReader = new FileReader();
      fileReader.onloadend = (e) => { 
        const testResult = fileReader.result.toString();
        resolve(testResult);
      }
      fileReader.readAsText(file, "UTF-8");
    });
  }

【问题讨论】:

  • 忽略.forEach() 不关心async 回调的事实......为什么还有.forEach()value 只会得到 values 中最后一个“值”的结果
  • 我只需要翻译该对象中的每个元素,我不在乎它是 foreach、for 还是其他类型的循环,我只需要翻译它们
  • 脚本中的任何内容都不会尝试更改values 的内容。看看Promise.all()How do I return the response from an asynchronous call?
  • 我尝试做任何事情但我厌倦了它,我工作了大约 1 个月。
  • 或许不需要将 observable 转换为 promise? translate() 函数是如何以及在哪里调用的?调用者如何期望响应?

标签: angular typescript object asynchronous


【解决方案1】:

从我的评论扩展,我认为没有必要在这里将 observable 转换为 Promise。您可以改为返回一个 RxJS forkJoin 函数,该函数并行触发多个可观察对象,并在需要响应的地方订阅它。

除了使用Object.keysObject.valuesArray#reduce,您还可以使用Object.entriesObject.fromEntries

试试下面的

import { of, forkJoin } from 'rxjs';
import { map } from 'rxjs/operators';

private translate(file: any): Observable<any> {                // <-- return `Observable` here
  return forkJoin(                                             // <-- `forkJoin` to trigger sources in parallel
    Object.entries(file).map(([key, value]) => {               // <-- `Object.entries` with `Array#map`
      if (typeof (value) === 'object')
        return of([key, this.translate(value)]);               // <-- use `of` to convert value to observable
      return this.GetTranslatedByResstring(value, 1045).pipe(
        map((res: any) => ([key, res.getPhrase()]))            // <-- map to the required format [key, value]
      );
    })
  ).pipe(
    map((res: any) => Object.fromEntries(res))                 // <-- convert back to object
  );
}

现在由于该函数返回一个 observable,您需要在需要响应的地方订阅它。

例如。

ngOnInit() {
  this.translate(file).subscribe({
    next: (value: any) => {
      // any statements that depend on the response must be here
    },
    error: (error: any) => {
      // handle error
    }
  })
}

更新 1

回到我的第一点,我认为这里没有必要将 observable 转换为 promise。因此,请避免 this.getFile() 函数中的 toPromise() 并从那里返回 observable。现在在getTranslatedJson() 函数中,您可以使用像switchMap 这样的高阶映射运算符从一个可观察对象映射到另一个对象。

public getTranslatedJson(
  sourceFile: File,
  originLanguage: Language,
  destinatonLanguage: Language
): Observable<any> {
  return this.getFile(sourceFile).pipe(
    switchMap((file: any) => 
      this.translate(JSON.parse(file))
    )
  );
}

在这种情况下,您将订阅需要响应的 getTranslatedJson() 函数。

ngOnInit() {
  this.getTranslatedJson(file, origLang, destLang).subscribe({
    next: (value: any) => {
      // any statements that depend on the response must be here
    },
    error: (error: any) => {
      // handle error
    }
  })
}

更新 2

如果由于某种原因 Object.entriesObject.fromEntries 不可用,您可以随时恢复为 .values.keysArray#reduce,就像您最初尝试的那样。

private translate(file: any): Observable<any> {                // <-- return `Observable` here
  return forkJoin(                                             // <-- `forkJoin` to trigger sources in parallel
    Object.values(file).map((value: any) => {                  // <-- `Object.values()` with `Array#map`
      if (typeof (value) === 'object')
        return of(this.translate(value));                      // <-- use `of` to convert value to observable
      return this.GetTranslatedByResstring(value, 1045).pipe(
        map((res: any) => res.getPhrase())                     // <-- map to the result from `getPhrase()`
      );
    })
  ).pipe(
    map((res: any) =>                                          // <-- convert back to object
      Object.keys(file).reduce((acc, curr, i) => 
        ({ ...acc, [curr]: res[i] }), 
        Object.create(null)
      );
    )
  );
}

更新 3

通过调整以前的答案,您可以为琐碎的任务找到大多数解决方案。

// credit: https://stackoverflow.com/a/48802804/6513921

private getFile(
  sourceFile: File
): Observable<any> {
  const file = sourceFile[0];
  const fileReader = new FileReader();

  return Observable.create((observer: Subscriber<any>): void => {
    fileReader.onloadend = ((ev: any): void => {
      observer.next(fileReader.result.toString());
      observer.complete();
    });
    
    fileReader.onerror = (error: any): void => {
      observer.error(error);
    }
  });

  fileReader.readAsText(file, "UTF-8");
}

【讨论】:

  • 如何修复它:“ObjectConstructor”类型上不存在属性“fromEntries”。您需要更改目标库吗?尝试更改 lib 编译器选项。
  • 我将它添加到 webconfig 但仍然出现错误,即使我尝试以该线程中提供的其他方式修复它
  • 我们触及了我帖子后面的另一个功能,所以我更新了我的问题,因为我无法在我的 getfile 上进行管道和映射
  • 当我研究了你的回复时,我认为它不会起作用。为什么?我告诉你用例。您上传 JSON 文件,在此之后,您的 JSON 由 Web 应用程序翻译,在此 JSON 需要准备好下载之后,所以最后一步制作问题,因为我订阅了内部服务,所以我的组件中不会有任何翻译我下载了我的新 json 文件。最简单的方法是蛮力将短语翻译成我的对象,但我仍然不知道该怎么做。
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2013-06-30
  • 2013-01-06
  • 2019-08-06
  • 1970-01-01
  • 2023-03-27
  • 2021-08-01
相关资源
最近更新 更多