外部承诺需要等待内部嵌套承诺

时间:2017-11-04 17:18:06

标签: javascript angular typescript promise angular-promise

我有这个用例,我希望做到以下几点:

  1. 在indexDb中设置元数据
  2. 迭代一系列图像
  3. 查看img是否已在indexDb中设置
  4. 如果是,则不执行任何操作,如果没有,请下载img
  5. 在indexDb
  6. 中设置下载的img(作为blob)
  7. 最后提升所有处理过的图像事件
  8. 广告数据:

    [{
    ETag:"",
    S3URL:"",
    duration:30,
    filename:"",
    linear-gradient:"",
    status:"",
    timerRequired:"yes"
    }]
    

    我的代码:

     this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
          for (let idx in ads) { //Step 2
            this.localforage.getItem(ads[idx]['filename']).then(blob => {
               if(!blob){ //Step 3
                 LSPromise = imgSrcToBlob(ads[idx]['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
                  return this.localforage.setItem(ads[idx]['filename'], blob); //Step 5
                });
                LSPromises.push(LSPromise);
               }
            });
          }  
        }).then(() => { 
          if(LSPromises.length) {
            Promise.all(LSPromises).then((data) => {
              this.TvLSkeyCount = LSPromises.length;
              this.fireLoadAssetsEvent(); //Step 6
            });
          } 
        });
    

    我面临的问题:

    在解决了设置元数据的承诺后,它立即转到then()块,到那时LSPromisesnull。当然我理解内部嵌套的承诺尚未解决。

    我尝试过的决议:

    稍后返回LSGetter承诺并下载图像。这也不起作用。

    我试过的代码:

    this.Tvlocalforage.setItem('meta', newMeta).then(() => { 
          for (let idx in ads) {
            let p = this.Tvlocalforage.getItem(ads[idx]['filename']);
            LSPromises.push({'promise' : p, 'filename' : ads[idx]['filename'], 'url' : ads[idx]['S3URL']});
          }
      }).then(() => { 
        if(LSPromises.length){
          Promise.all(LSPromises.map(obj => {
            obj['promise'].then(blob => {
              if(!blob){
                  imgSrcToBlob(obj['url'], undefined, 'Anonymous', 1).resolve(blob => {
                    return this.Tvlocalforage.setItem(obj['filename'], blob);
                });   
              }
            });
          })).then((data) => {this.fireLoadAssetsEvent();});
        }
    

    我尝试了另外两种方法来包装,并尝试从内部返回promise.all下载步骤尝试将resolve设置下载的图像return promise.all转换为LS。但它没有用。

3 个答案:

答案 0 :(得分:1)

摆脱for()循环,因为idx不会是你希望它在promise回调中的内容,因为循环将在promises之前完成

可以使用map()代替使用闭包创建数组

类似的东西:

this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1

  let LSPromises = ads.map(ad => {
    return this.localforage.getItem(ads[idx]['filename']).then(blob => {
      if (!blob) { //Step 3
        return imgSrcToBlob(ad['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
          return this.localforage.setItem(ad['filename'], blob); //Step 5
        });
      }
      return null
    });
  });

  return Promise.all(LSPromises).then((data) => {
    this.TvLSkeyCount = data.filter(o => o).length;
    this.fireLoadAssetsEvent(); //Step 6
    // not sure what needs to be returned here
  });

});

答案 1 :(得分:0)

可能还有其他错误,但缺少return

this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
      for (let idx in ads) { //Step 2
        LSPromises.push(this.localforage.getItem(ads[idx]['filename']).then(blob => {
           if(!blob){ //Step 3
             return /* added return */ imgSrcToBlob(ads[idx]['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
              return this.localforage.setItem(ads[idx]['filename'], blob); //Step 5
            });
            // LSPromises.push(LSPromise);
           }
        }));
      }  
     // }).then(() => { 
      if(LSPromises.length) {
        return /* <<<=== */ Promise.all(LSPromises).then((data) => {
          this.TvLSkeyCount = LSPromises.length;
          this.fireLoadAssetsEvent(); //Step 6
        });
      } 
    });

如果未返回Promise.all()返回的承诺,则调用者无法等待它完成。

答案 2 :(得分:0)

我无法对此进行测试,但您应该尝试将嵌套展平,将then s链接在最外层。您可以使用Promise.all甚至更多,以便将ad值与解析后的值一起传递到链中:

this.Tvlocalforage.setItem('meta', newMeta).then(() => // Step 1
    Promise.all(ads.map( ad => // Step 2
        Promise.all(ad, this.localforage.getItem(ad.filename))
    ))
).then(blobs => 
    blobs.filter( ([ad, blob]) => !blob ) // Step 3
).then(blobs =>
    Promise.all(blobs.map( ([ad]) => 
        [ad, imgSrcToBlob(ad.S3URL, undefined, 'Anonymous', 1)] // Step 4
    ))
).then(blobs =>
    Promise.all(blobs.map( ([ad, blob]) =>
        this.localforage.setItem(ad.filename, blob) // Step 5
    ))
).then(data => {
    this.TvLSkeyCount = data.length;
    this.fireLoadAssetsEvent(); // Step 6
});