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

Javascript 外部承诺需要等待内部嵌套的承诺,javascript,angular,typescript,promise,angular-promise,Javascript,Angular,Typescript,Promise,Angular Promise,我有一个用例,希望执行以下操作: 在indexDb中设置元数据 迭代一组图像 查看indexDb中是否已设置img 如果是,什么也不做,如果不是,下载img 在indexDb中设置下载的img(作为blob) 在结束时引发所有已处理图像事件 ads数据: [{ ETag:"", S3URL:"", duration:30, filename:"", linear-gradient:"", status:"", timerRequired:"yes" }] 我现在的代码是: this.Tvlo

我有一个用例,希望执行以下操作:

  • 在indexDb中设置元数据
  • 迭代一组图像
  • 查看indexDb中是否已设置img
  • 如果是,什么也不做,如果不是,下载img
  • 在indexDb中设置下载的img(作为blob)
  • 在结束时引发所有已处理图像事件
  • ads数据:

    [{
    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()
    块,此时
    LSPromises
    null
    。当然,我知道内部嵌套的承诺还没有得到解决

    决议一:

    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();});
        }
    
    返回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。下载步骤的所有
    都是从内部开始的&在尝试
    解决
    问题时,
    返回promise。将下载图像的所有
    设置为LS。但它不起作用。

    可能还有其他错误,但缺少一个
    返回:

    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
            });
          } 
        });
    
    this.tvLocalFower.setItem('meta',newMeta)。然后(()=>{//步骤1
    对于(让idx在ads中){//步骤2
    LSPromises.push(this.localfough.getItem(ads[idx]['filename'])。然后(blob=>{
    如果(!blob){//步骤3
    return/*添加了return*/imgSrcToBlob(ads[idx]['S3URL'],未定义,'Anonymous',1)。然后((blob)=>{//步骤4
    返回此.localfough.setItem(ads[idx]['filename'],blob);//步骤5
    });
    //LSPromises.push(LSPromise);
    }
    }));
    }  
    //})。然后(()=>{
    if(lsc.length){
    
    return/*我无法测试这一点,但您应该尝试展平嵌套,将
    链接到最外层。您可以使用
    Promise。所有
    甚至更多,以便将
    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
    });
    
    摆脱
    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
      });
    
    });
    

    信息:我意识到localfough setItem api按原样启动。它可以作为一个承诺工作,但这是可选的用法,也就是说,this.localfough.setItem(k,v)将插入一个虚拟回调并以行非承诺方式执行。还有其他问题您将遇到。如果
    imgSrcToBlob
    是真正异步的,并且不能立即解决,则
    idx
    将不会有您在//步骤5中认为的值。是的@jochenbdersdorfer,我很快就意识到了。我们无法确保正确的idx m应用。&需要将BLOB设置为LS的最后步骤需要文件名,该文件名仅来自idx。由于不了解
    ads
    的结构,这可能会更好:
    promises=Object.keys(ads).map(idx=>this.tvLocalFower.getItem(ads[idx]['filename])
    在映射()中缺少一个
    return
    …因此基本上没有承诺传递给
    Promise.all()
    LSPromise
    是一个
    Promise
    ,而不是
    Array
    原始代码中最大的问题是使用了for循环,因此
    idx
    在步骤5中无效。还需要关闭
    for()
    循环。我做了额外的更改。然后错过了一个循环(
    .then(blob=>
    )非常感谢您的好意,先生。您为我节省了周末(可能至少两个工作日)。标记接受。祝您愉快:)这是一个非常有趣的方法。我尝试了Gunter的解决方案&它解决了我的用例,而不需要从头开始进行修改。不过,非常感谢。感谢您给我时间。我有一个问题,为什么我们需要回报承诺。如果setItem('meta')中不需要任何功能,那么()现在?只有当您需要链中的另一个
    then()
    时才是重要的,毕竟您已经解决了这个问题。好的。