在 javascript 中异步调用多个承诺的正确方法

Proper way of calling multiple promises asynchronously in javascript

我是 Javascript 的新人,如果我的问题对您来说似乎很蹩脚,请原谅我。我在这里做的是通过 Graph-API 一个接一个地在 Facebook 页面上发布 6 张图像。所以我用 URL 参数调用 POST 函数,然后当我从那个调用中得到 photoID 时,我又调用了一个函数来读取带有 photoID 的照片,然后借助该图像的实际宽度和高度,从该响应的图像对象中获取原始图像。

这是在 Facebook 页面上发布图片的调用:

function postImageOnFacebookPageAndGetPhotoID(url) {
  return new Promise(function(resolve, reject) {
    FB.api(
      '/'+pageID+'/photos',
      'POST',
      {"url":url, "access_token":document.getElementById("pageAccessToken").value},
      function(response) {
        if (!response || response.error) {
          reject(response.error);
        } else {
          resolve(response.id);
        }
      }
    );
  });
}   

这就是我得到 PhotoID:

的方式
postImageOnFacebookPageAndGetPhotoID(wallpaper1125_2436Url).then(
  function(result) {
    if (result) {
      //Get the original image by photoID with the help of width and height
      //Here result is the photoID
      var photoID_1125_2436 = result;
      console.log(photoID_1125_2436);
    }
  }).catch(
    function(error) {
      alert(error);
    }
  )

我的墙纸图片大小是 1125x2436,所以我再次调用从 Facebook 读取图片,使用我图片的实际大小 photoID 像这样:

从facebook获取图片的实际宽高功能:

function getOriginalUploadedImageURL(photoID, imageWidth, imageHeight) {
  return new Promise(function(resolve, reject) {
    FB.api(
      '/'+photoID,
      'GET',
      {"fields":"images"},
      function(response) {
        if (!response || response.error) {
          reject(response.error);
        } else {
          var imageArray = response.images;
          imageArray.forEach((item) => {
            if (item.width == imageWidth && item.height == imageHeight) {
              resolve(item.source);
            }
          });
        }
      }
    );
  });
}

我根据我的第一个承诺 resolve 调用此函数,如下所示:

postImageOnFacebookPageAndGetPhotoID(wallpaper1125_2436Url).then(
  function(result) {
    if (result) {
      //Get the original image by photoID with the help of width and height
      //Here result is the photoID
      var photoID_1125_2436 = result;
      getOriginalUploadedImageURL(photoID_1125_2436, "1125", "2436").then(
        function(result) {
          if (result) {
            //result is the original photo url of the uploaded image
            console.log(result);
          }
        }).
        catch(
          function(error) {
            alert(error);
          }
        )
    }
  }).
  catch(
    function(error) {
      alert(error);
    }
  )

这对一张图片来说效果很好。但是当我用我所有的 6 张图像尝试这种方法时,它在 2 次迭代后停止返回任何 resolvereject,并且整个事情看起来有线:

postImageOnFacebookPageAndGetPhotoID(wallpaper1125_2436Url).then(
      function(result) {
        if (result) {
          //Get the original image by photoID with the help of width and height
          //Here result is the photoID
          var photoID_1125_2436 = result;
          console.log("Get photoID_1125_2436"+result);
          getOriginalUploadedImageURL(photoID_1125_2436, "1125", "2436").then(
            function(result) {
              if (result) {
                //result is the original photo url of the uploaded image
                wallpaper1125_2436Url = result;
                console.log("Get wallpaper1125_2436Url"+result);
                //Post the wallpaper1242_2208Url in facebook page
                postImageOnFacebookPageAndGetPhotoID(wallpaper1242_2208Url).then(
                  function(result) {
                    if (result) {
                      //Get the original image by photoID with the help of width and height
                      //Here result is the photoID
                      var photoID_1242_2208 = result;
                      console.log("Get photoID_1242_2208"+result);
                      getOriginalUploadedImageURL(photoID_1242_2208, "1242", "2208").then(
                        function(result) {
                          if (result) {
                            //result is the original photo url of the uploaded image
                            wallpaper1242_2208Url = result;
                            console.log("Get wallpaper1242_2208Url"+result);
                            //Post the wallpaper1242_2688Url in facebook page
                            postImageOnFacebookPageAndGetPhotoID(wallpaper1242_2688Url).then(
                              function(result) {
                                if (result) {
                                  //Get the original image by photoID with the help of width and height
                                  //Here result is the photoID
                                  var photoID_1242_2688 = result;
                                  console.log("Get photoID_1242_2688"+result);
                                  getOriginalUploadedImageURL(photoID_1242_2688, "1242", "2688").then(
                                    function(result) {
                                      if (result) {
                                        //result is the original photo url of the uploaded image
                                        wallpaper1242_2688Url = result;
                                        console.log("Get wallpaper1242_2688Url"+result);
                                        //Post the wallpaper828_1792Url in facebook page
                                        postImageOnFacebookPageAndGetPhotoID(wallpaper828_1792Url).then(
                                          function(result) {
                                            if (result) {
                                              //Get the original image by photoID with the help of width and height
                                              //Here result is the photoID
                                              var photoID_828_1792 = result;
                                              console.log("Get photoID_828_1792"+result);
                                              getOriginalUploadedImageURL(photoID_828_1792, "828", "1792").then(
                                                function(result) {
                                                  if (result) {
                                                    //result is the original photo url of the uploaded image
                                                    wallpaper828_1792Url = result;
                                                    console.log("Get wallpaper828_1792Url"+result);
                                                    //Post the wallpaper750_1334Url in facebook page
                                                    postImageOnFacebookPageAndGetPhotoID(wallpaper750_1334Url).then(
                                                      function(result) {
                                                        if (result) {
                                                          //Get the original image by photoID with the help of width and height
                                                          //Here result is the photoID
                                                          var photoID_750_1334 = result;
                                                          console.log("Get photoID_750_1334"+result);
                                                          getOriginalUploadedImageURL(photoID_750_1334, "750", "1334").then(
                                                            function(result) {
                                                              if (result) {
                                                                //result is the original photo url of the uploaded image
                                                                wallpaper750_1334Url = result;
                                                                console.log("Get wallpaper750_1334Url"+result);
                                                                //Post the wallpaper640_1136Url in facebook page
                                                                postImageOnFacebookPageAndGetPhotoID(wallpaper640_1136Url).then(
                                                                  function(result) {
                                                                    if (result) {
                                                                      //Get the original image by photoID with the help of width and height
                                                                      //Here result is the photoID
                                                                      var photoID_640_1136 = result;
                                                                      console.log("Get photoID_640_1136"+result);
                                                                      getOriginalUploadedImageURL(photoID_640_1136, "640", "1136").then(
                                                                        function(result) {
                                                                          if (result) {
                                                                            //result is the original photo url of the uploaded image
                                                                            wallpaper640_1136Url = result;
                                                                            console.log("Get wallpaper640_1136Url"+result);
                                                                            //Here I need to get all of my 6 image url for desired image with and height
                                                                            console.log("Get wallpaper640_1136Url"+wallpaper1125_2436Url);
                                                                            console.log("Get wallpaper640_1136Url"+wallpaper1242_2208Url);
                                                                            console.log("Get wallpaper640_1136Url"+wallpaper1242_2688Url);
                                                                            console.log("Get wallpaper640_1136Url"+wallpaper828_1792Url);
                                                                            console.log("Get wallpaper640_1136Url"+wallpaper750_1334Url);
                                                                            console.log("Get wallpaper640_1136Url"+wallpaper640_1136Url);
                                                                          }
                                                                        }).catch(
                                                                          function(error) {
                                                                            document.getElementById("loaderId").style.visibility = 'hidden';
                                                                            alert(error);
                                                                          }
                                                                        )
                                                                    }
                                                                  }).catch(
                                                                    function(error) {
                                                                      document.getElementById("loaderId").style.visibility = 'hidden';
                                                                      alert(error);
                                                                    }
                                                                  )
                                                              }
                                                            }).catch(
                                                              function(error) {
                                                                document.getElementById("loaderId").style.visibility = 'hidden';
                                                                alert(error);
                                                              }
                                                            )
                                                        }
                                                      }).catch(
                                                        function(error) {
                                                          document.getElementById("loaderId").style.visibility = 'hidden';
                                                          alert(error);
                                                        }
                                                      )
                                                  }
                                                }).catch(
                                                  function(error) {
                                                    document.getElementById("loaderId").style.visibility = 'hidden';
                                                    alert(error);
                                                  }
                                                )
                                            }
                                          }).catch(
                                            function(error) {
                                              document.getElementById("loaderId").style.visibility = 'hidden';
                                              alert(error);
                                            }
                                          )
                                      }
                                    }).catch(
                                      function(error) {
                                        document.getElementById("loaderId").style.visibility = 'hidden';
                                        alert(error);
                                      }
                                    )
                                }
                              }).catch(
                                function(error) {
                                  document.getElementById("loaderId").style.visibility = 'hidden';
                                  alert(error);
                                }
                              )
                          }
                        }).catch(
                          function(error) {
                            document.getElementById("loaderId").style.visibility = 'hidden';
                            alert(error);
                          }
                        )
                    }
                  }).catch(
                    function(error) {
                      document.getElementById("loaderId").style.visibility = 'hidden';
                      alert(error);
                    }
                  )
              }
            }).catch(
              function(error) {
                document.getElementById("loaderId").style.visibility = 'hidden';
                alert(error);
              }
            )
        }
      }).catch(
        function(error) {
          document.getElementById("loaderId").style.visibility = 'hidden';
          alert(error);
        }
      )

那么我怎样才能正确地做到这一点呢?再次抱歉,代码太多。
非常感谢。

有两个答案,但它们都利用了这样一个事实,即您可以 而不是 嵌套 这些处理程序。而不是:

doThis()
.then(function(thisResult) {
    doThat()
    .then(function(thatResult) {
        doTheOther()
        .then(function(theOtherResult) {
            // ...
        });
    })
    .catch(/*...*/);
})
.catch(/*...*/);

这样做:

doThis()
.then(function(thisResult) {
    return doThat();
})
.then(function(thatResult) {
    return doTheOther();
})
.then(function(theOtherResult) {
    // ...
})
.catch(/*...*/);

出现“两个答案”是因为:

1。第一个答案使用原始代码中的离散变量:

// *** Declare them here
let photoID_1125_2436, wallpaper1125_2436Url/*, ...*/;
// *** Fill them in with the promise fulfillment handlers
postImageOnFacebookPageAndGetPhotoID(wallpaper1125_2436Url)
.then(function(result) {
    if (!result) {
        return result;
    }
    //Get the original image by photoID with the help of width and height
    //Here result is the photoID
    photoID_1125_2436 = result;
    console.log("Get photoID_1125_2436"+result);
    return getOriginalUploadedImageURL(photoID_1125_2436, "1125", "2436");
 })
.then(function(result) {
    if (!result) {
        return result;
    }
    //result is the original photo url of the uploaded image
    wallpaper1125_2436Url = result;
    console.log("Get wallpaper1125_2436Url"+result);
    //Post the wallpaper1242_2208Url in facebook page
    return postImageOnFacebookPageAndGetPhotoID(wallpaper1242_2208Url);
})
.then(function(result) {
    // ...and so on...
})
.then(function(result) {
    if (!result) {
        return result;
    }
    wallpaper640_1136Url = result;
    console.log("Get wallpaper640_1136Url"+result);
    // *** Use them all here
    console.log("Get wallpaper640_1136Url"+wallpaper1125_2436Url);
    console.log("Get wallpaper640_1136Url"+wallpaper1242_2208Url);
    console.log("Get wallpaper640_1136Url"+wallpaper1242_2688Url);
    console.log("Get wallpaper640_1136Url"+wallpaper828_1792Url);
    console.log("Get wallpaper640_1136Url"+wallpaper750_1334Url);
    console.log("Get wallpaper640_1136Url"+wallpaper640_1136Url);
})
.catch(function(error) {
    document.getElementById("loaderId").style.visibility = 'hidden';
    alert(error);
});

2。第二个使用循环而不是重复相同的函数

const wallpaperUrls = [
    {width: "1125", height: "2436", url: /*...*/,}
    {width: "1242", height: "2208", url: /*...*/,}
    {width: "1242", height: "2688", url: /*...*/,}
    {width: "828",  height: "1792", url: /*...*/,}
    {width: "750",  height: "1334", url: /*...*/,}
    {width: "640",  height: "1136", url: /*...*/,}
];
const results = {};
const promise = Promise.resolve();
for (const {width, height, url} of wallpaperUrls) {
    promise = promise.then(() => {
        return postImageOnFacebookPageAndGetPhotoID(url)
        .then(result => {
            return result && getOriginalUploadedImageURL(result, width, height);
            // *** ^^^^^^^^^^−−−− It seems odd to me that the promise could be fullfilled but
            //                    not provide a valid result; hopefully you don't need this
        })
        .then(imageUrl => {
            if (imageUrl) { // *** It seems odd to me that the promise could be fullfilled but
                            //    not provide a valid result; hopefully you don't need this
                results[`${width}_${height}`] = imageUrl;
            }
        })
    });
}
promise
.then(() => {
    // ...use `results` here, it's keyed by width_height
})
.catch(error => {
    document.getElementById("loaderId").style.visibility = 'hidden';
    alert(error);
}) ;

请注意,这 系列 一个接一个地执行所有操作,就像您的原始示例一样。但是您可以并行执行它们:

const wallpaperUrls = [
    {width: "1125", height: "2436", url: /*...*/,}
    {width: "1242", height: "2208", url: /*...*/,}
    {width: "1242", height: "2688", url: /*...*/,}
    {width: "828",  height: "1792", url: /*...*/,}
    {width: "750",  height: "1334", url: /*...*/,}
    {width: "640",  height: "1136", url: /*...*/,}
];
const results = {};
Promise.all(wallpaperUrls.map(({width, height, url}) => {
    return postImageOnFacebookPageAndGetPhotoID(url)
    .then(result => {
        return result && getOriginalUploadedImageURL(result, width, height);
        // *** ^^^^^^^^^^−−−− It seems odd to me that the promise could be fullfilled but
        //                    not provide a valid result; hopefully you don't need this
    })
    .then(imageUrl => {
        if (imageUrl) { // *** It seems odd to me that the promise could be fullfilled but
                        //    not provide a valid result; hopefully you don't need this
            results[`${width}_${height}`] = imageUrl;
        }
    })
});
.then(() => {
    // ...use `results` here, it's keyed by width_height
})
.catch(error => {
    document.getElementById("loaderId").style.visibility = 'hidden';
    alert(error);
});

我坚持使用上面的 .then.catch 等,因为您的代码没有使用 async/await。但是,如果您使用 async/await,代码将更容易编写和阅读,您可以在许多本地环境中执行此操作(如果您转译,则几乎可以在任何环境中执行)。


请注意:以上内容可能存在细微错误。我没有 运行 甚至 syntax-check 代码。你肯定需要在这里和那里进行一些调整。 :-)

我认为你可以使用 Promise.all(promises 数组)[Promise.all](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all.

postImageOnFacebookPageAndGetPhotoID(wallpaper1125_2436Url).then(
  function(result) {
    if (result) {
      //Get the original image by photoID with the help of width and height
      //Here result is the photoID
      var photoID_1125_2436 = result;
      return getOriginalUploadedImageURL(photoID_1125_2436, "1125", "2436").then(
        function(result) {
          if (result) {
            //result is the original photo url of the uploaded image
            console.log(result);
            return result
          }
        }).
        catch(
          function(error) {
            alert(error);
          }
        )
    }
  }).
  catch(
    function(error) {
      alert(error);
    }
  )

// Then use Promise.all for all the 6 images

Promise.all([
  postImageOnFacebookPageAndGetPhotoID(url 1), 
  postImageOnFacebookPageAndGetPhotoID(url 2) 
  ... 
  upto 6 images
])
  .then((results) => console.log(results))

此处的结果将是一个数组,其中包含每个单独调用的结果,其顺序与传递给 Promise.all()

的顺序相同

然后你可以在Promise.all的末尾附加一个catch。

只是抽象你的功能

function yourfunction(arg){
  return new Promise((resolve,reject)=>{
    if(Math.random() > 0.9){
      console.log(arg,'failed');
      reject();
    }else{
      console.log(arg,'ok');
      resolve();
    }
  });
}

// run all
function allok(){
  let arr = [];
  for(let i = 0;i<6;i++){
    arr.push(yourfunction(i));
  }
  return Promise.all(arr).then(()=>{
    console.log('all ok');
    return true;
  }).catch(()=>{
    console.log('some func failed');
    return Promise.resolve(false);
  });
}


async function oneByone(){
  try{
    for(let i = 0;i<6;i++){
      await yourfunction(i);
    }
  }catch(e){
    console.log('some func failed');
    return false;
  }
  console.log('all ok');
  return true;
}

如果你想调用所有函数并检查它们是否都可以调用allok();

或者你想一个接一个地调用函数直到有些失败,调用oneByone();