javascript 等待递归API调用完成

vwkv1x7d  于 2023-03-16  发布在  Java
关注(0)|答案(1)|浏览(149)

我正在使用DeepL API来翻译文档。正如您在他们的documentation中所看到的,在使用要翻译的文件调用API之后,您可以调用一个端点来了解翻译的状态。此端点返回剩余秒数的估计值。当此端点返回“完成”状态时,您可以下载翻译后的文件。
我已经设法递归调用端点来检查转换的状态,并在状态完成时调用download。现在我想要的是在转换完成时显示一个弹出窗口。因此,我在第一次调用之前将showLoaderPopup状态添加为true。但我需要等待所有操作完成才能将状态设置为false。问题是对TranslateFile方法的调用在文件下载之前返回,所以承诺中的某些东西一定没有被很好地配置。
这是我的代码:

async TranslateFile(files: FileList, inputLang: string, outputLang: string){
    const formData = new FormData();
    if(inputLang) formData.append('source_lang', inputLang);
    formData.append('target_lang', outputLang);
    formData.append('file', files.item(0), files.item(0).name);
    const documentType = files.item(0).type;

    const requestOptions = this.getRequestFileOpt(formData);

    return await this.getFileResponse(requestOptions, documentType);
}

// FUNCTION THAT SEND THE FILE TO TRANSLATE AND CALL RECURSIVE FUNC FOR THE FIRST TIME
async getFileResponse(requestOptions: RequestInit, documentType: string) {
    const myHeaders = new Headers();
    myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
    await fetch(`https://api.deepl.com/v2/document?auth_key=${apiKey}`, requestOptions)
        .then(result => result.json())
        .then(async (document: any) => {
            await setTimeout(async() => {
                return await this.checkDocumentTranslationState(document, documentType);
            }, 2000);
        })
}

// RECURSIVE FUNCTION TO CHECK TRANSLATION STATE
async checkDocumentTranslationState(document: any, documentType: string): Promise<boolean> {
    const myHeaders = new Headers();
    return await fetch(`https://api.deepl.com/v2/document/${document.document_id}?auth_key=${apiKey}&document_key=${document.document_key}`,{method: 'POST', headers: myHeaders})
        .then(result => result.json())    
        .then(async (documentState: any) => {
            if(documentState.status === "done") 
                return this.downloadToClient(await fetch(`https://api.deepl.com/v2/document/${document.document_id}/result?auth_key=${apiKey}&document_key=${document.document_key}`,{method: 'POST', headers: myHeaders}), documentType);
            else if(documentState.status === "error") return false;    
            else {
                let seconds_remaining = Number(documentState.seconds_remaining);
                setTimeout(async () => {
                    return await this.checkDocumentTranslationState(document, documentType);
                }, (seconds_remaining && !Number.isNaN(seconds_remaining) && (seconds_remaining < 5000)) ? (seconds_remaining) : 2000);
            }
        });  
}

// FUNCTION TO DOWNLOAD FILE
async downloadToClient(response: any, documentType: string): Promise<boolean> {
    const blob = await response.blob();
    const url = window.URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    let fileName = "TranslatedFile";
    if(documentType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document") fileName += ".docx";
    else if(documentType === "application/vnd.openxmlformats-officedocument.presentationml.presentation") fileName += ".pptx";
    else if(documentType === "application/pdf") fileName += ".pdf";
    else fileName += ".txt";
    link.setAttribute('download', fileName);
    document.body.appendChild(link);
    link.click();
    return true;
}
zhte4eai

zhte4eai1#

我认为你面临的主要问题是你混淆了async await和Promise then的概念,尽量坚持一个概念,避免使用递归。
我为你清理了代码,也许现在它更容易理解和调试你的错误,如果它甚至存在了。

async TranslateFile(
  files: FileList,
  inputLang: string,
  outputLang: string
): Promise<boolean> {
  const formData = new FormData();
  if (inputLang) formData.append("source_lang", inputLang);
  formData.append("target_lang", outputLang);
  formData.append("file", files.item(0), files.item(0).name);
  const documentType = files.item(0).type;
  const requestOptions = this.getRequestFileOpt(formData);
  return await this.getFileResponse(requestOptions, documentType);
}

async getFileResponse(
  requestOptions: RequestInit,
  documentType: string
): Promise<boolean> {
  const myHeaders = new Headers();
  myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
  const result = await fetch(
    `https://api.deepl.com/v2/document?auth_key=${apiKey}`,
    requestOptions
  );
  const document = await result.json();
  await this.awaiter(2000);
  return await this.checkDocumentTranslationState(document, documentType);
}

async checkDocumentTranslationState(
  document: any,
  documentType: string
): Promise<boolean> {
  const myHeaders = new Headers();
  while (true) {
    try {
      const result = await fetch(
        `https://api.deepl.com/v2/document/${document.document_id}?auth_key=${apiKey}&document_key=${document.document_key}`,
        { method: "POST", headers: myHeaders }
      );
      const documentState = await result.json();
      if (documentState.status === "done") {
        const response = await fetch(
          `https://api.deepl.com/v2/document/${document.document_id}/result?auth_key=${apiKey}&document_key=${document.document_key}`,
          { method: "POST", headers: myHeaders }
        );
        const blob = await response.blob();
        return this.downloadToClient(blob, documentType);
      } else if (documentState.status === "error") {
        return false;
      } else {
        const seconds_remaining = Number(documentState.seconds_remaining);
        await this.awaiter(
          seconds_remaining &&
            !Number.isNaN(seconds_remaining) &&
            seconds_remaining < 5000
            ? seconds_remaining
            : 2000
        );
      }
    } catch (e) {
      console.log(e);
      return false;
    }
  }
}

async downloadToClient(blob: Blob, documentType: string): Promise<boolean> {
  const url = window.URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  let fileName = "TranslatedFile";
  if (
    documentType ===
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
  )
    fileName += ".docx";
  else if (
    documentType ===
    "application/vnd.openxmlformats-officedocument.presentationml.presentation"
  )
    fileName += ".pptx";
  else if (documentType === "application/pdf") fileName += ".pdf";
  else fileName += ".txt";
  link.setAttribute("download", fileName);
  document.body.appendChild(link);
  link.click();
  return true;
}

awaiter(millis: number): Promise<void> {
  return new Promise((res) => {
    setTimeout(res, millis);
  });
}

相关问题