【问题标题】:Recursively call promises递归调用承诺
【发布时间】:2018-01-19 11:50:48
【问题描述】:

我已经在网上搜索了很长一段时间了。

我正在为 Ionic 应用程序制作 Angular 服务的原型。此服务的目的是下载图像。现在这是一个问题,在标准 JS 中,我想通过一些递归调用来解决,以避免重复代码。

我尝试使用 Promise 来编写它,以使我对 Promises 的概念感兴趣,这让我很难过。

考虑以下代码:

public getBgForName = (name: string) => {
  name = name.toLowerCase();
  var instance = this;
  var dir = this.file.dataDirectory;
  return new Promise(function (fulfill, reject) {
    instance.file.checkDir(dir, name).then(() => {
      // directory exists. Is there a bg file?
      dir = dir + '/' + name + '/';
      instance.file.checkFile(dir, 'bg.jpg').then(() => {
        console.log('read file');
          fulfill(dir + '/' + 'bg.jpg')
      }, (err) => {
        // dl file and re-call
        console.log('needs to download file!')
        instance.transfer.create().download(encodeURI('https://host.tld/'+name+'/bg.jpg'), dir + 'bg.jpg', true, {})
          .then((data) => {
            return instance.getBgForName(name).then((url) => {return url});
          }, (err) => {
            console.log(err)
          })
      })
    }, (err) => {
      // create dir and re-call
      instance.file.createDir(dir, name, true).then(() => {
          instance.getBgForName(name).then((url) => {fulfill(url)});
      })
    })

  });
}

当被调用时,承诺永远不会完全解决。我认为,在阅读this article 之后,问题在于我的承诺解决没有正确传递给“原始”承诺链 - 因此它解决了解决水平,但不是一直到顶部。当保证以下内容时,promise 支持正确解析:

  • 目录已经创建

  • 文件已下载

所以我认为 return 语句以某种方式破坏了此处的链接,导致在第一次递归调用后未解决承诺。

什么是递归调用promise的正确方法,确保原始调用者在准备好时收到结果?

编辑:按照 David B. 代码应该是在项目列表上调用的函数。对于每个项目,都有一个可用的背景图像,该图像存储在服务器上。此背景图像将在本地缓存。此处使用递归调用的目的是,无论状态如何(已下载,未下载),函数调用都将始终返回本地文件系统上图像的 url。具体步骤如下:

  • 为当前项目创建目录
  • 下载文件到这个目录
  • 返回下载文件的本地 URL

此后的后续调用只会直接从磁盘返回图像(在检查它是否存在之后),不再下载。

【问题讨论】:

  • 更重要的是,你想做什么?您能否像“1. 检查目录是否存在。2. 如果不存在,请执行此操作.. 等等等等”那样概述所需的结果。以这种方式理解和重构代码会容易得多! :)
  • 有什么理由不使用async/await? TypeScript 与递归 async/await 一起正常工作。
  • @DanielB 我补充了,谢谢。
  • @AkashKava 我将不得不阅读这一点,感谢您的提示。

标签: javascript typescript recursion ionic-framework es6-promise


【解决方案1】:

在阅读了 async/await 优于 promises 的好处(并且爱上了更简洁的语法)之后,我使用 async/await 重写了它。重构(但不完美!)的代码如下所示:

public getBgForName = async (name: string) => {
  name = name.toLowerCase();
  let instance = this;
  let dir = this.file.dataDirectory;

  try{
    await instance.file.checkDir(dir, name)
    dir = dir + name + '/';
    try{
      await instance.file.checkFile(dir, 'bg.jpg')
      return dir + 'bg.jpg';
    }catch(err) {
      // download file
      await instance.transfer.create().download(encodeURI('https://host.tld/'+name+'/bg.jpg'), dir + 'bg.jpg', true, {})
      return this.getBgForName(name);
    }
  }catch(err) {
    // not catching the error here since if we can't write to the app's local storage something is very off anyway.
    await instance.file.createDir(dir, name, true)
    return this.getBgForName(name);
  }
}

并按预期工作。

【讨论】:

    猜你喜欢
    • 2021-11-21
    • 2014-06-14
    • 2014-02-04
    • 1970-01-01
    • 2018-05-29
    • 2019-03-10
    • 2017-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多