递归调用promises

时间:2018-01-19 11:50:48

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

我已经在网上浏览了很长一段时间了。

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

我已经尝试用承诺写下它,让我对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的正确方法是什么,确保原始调用者在准备好后收到结果?

编辑:根据David B.的建议概述所需的结果。 代码应该是在项列表上调用的函数。对于每个项目,都有一个可用的背景图像,存储在服务器上。此背景图像将在本地缓存。在这里使用递归调用的目的是,无论状态(下载,未下载),函数调用将始终返回本地文件系统上的图像的URL。其步骤如下:

  • 为当前项目创建目录
  • 将文件下载到此目录
  • 将本地网址返回到下载的文件
之后的后续调用只会直接从磁盘返回图像(在检查它存在之后),不再下载。

1 个答案:

答案 0 :(得分:0)

在阅读了async / await over 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);
  }
}

按预期工作。