在异步事件发生时改变 Promise.all() 中 Promise 的 Promise 状态

Change the Promise state of a Promise in Promise.all() when an asynchronous event occurs

我正在使用 google 地图 Api。我有两个异步事件,库 API 调用和页面用户的位置请求。在 geolocate() functiongetCurrentPosition 中,我检索用户的坐标,此函数 return 如果一切正常,则处于已解决状态的承诺,将位置设置为 value。为了加载 API 库,我使用 JSONP 并在 loadGoogleAPI() 中动态添加了一个脚本,当库准备就绪时,将调用回调函数 googleAPILoaded。当上述 2 个异步事件发生并且我在 useGoogleMapsApi() function (await Promise.all) 中使用并行执行模式时,我必须继续 'asynchronous execution'。 我的问题是,当我调用 Promise.all 时,googleAPIStatusPromise.all 绑定到其初始值 new Promise(()=>{}) 挂起的 Promise。当加载带有 JSONP 的库时,我将变量的值 googleAPIStatus=Promise.resolve() 更改为已解决的 Promise,但 Promise.all 仍然与初始未决 Promise 值相关。 这是代码。我该如何解决?

 let googleAPIStatus = new Promise(()=>{});

  function googleAPILoaded(){
   console.log('loaded');
   googleAPIStatus = Promise.resolve(); 
}

  function useGoogleMapsApi(){
  loadGoogleAPI();//JSONP with a dynamic script
  let [_,posizione]= await Promise.all([googleAPIStatus , geolocate()]); //parallel execution pattern
  //Here if resolved either the Promises
  }

  function loadGoogleAPI(){
      let isLibraryLoaded = document.querySelector("script[src='google-api']"); 
      if(!(typeof google === 'object' && typeof google.maps === 'object')){
         //Add dynamic script that load the library
         let script = document.createElement('script');
         script.type='text/javascript';
         script.src = 'https://maps.googleapis.com/maps/api/js?key=HEREMYKEY&libraries=places&callback=googleAPILoaded';
         script.id  = 'google-api';
         if(!isLibraryLoaded)
            document.body.appendChild(script);
         else
            isLibraryLoaded.parentNode.replaceChild(script,isLibraryLoaded);
      }
  }

您可以公开 googleAPIStatus Promise 的设置,以便您可以在 googleAPILoaded 回调中设置它的状态。

let resolve, reject;
let googleAPIStatus = new Promise((_resolve, _reject) => {
  resolve = _resolve;
  reject = _reject;
});

function googleAPILoaded() {
  console.log('loaded');
  resolve()
}

setTimeout(googleAPILoaded, 100);

googleAPIStatus.then(() => console.log("resolved"))

另一个答案建议公开解析器函数,即“延迟模式”,这是一种由于封装性差而应尽可能避免的反模式。

而是考虑:“如果每个 API 都支持承诺,我将如何编写?”

然后通过包装您在 Promise 构造函数 (which is their primary purpose) 中遇到的每个遗留非承诺 API 来创建该现实,或者更好的是,寻找更新的 APIs。

对于您的情况,已经存在一种更简单的等待脚本加载的方法:

async function loadGoogleAPI() {
  if (typeof google === 'object' && typeof google.maps === 'object') {
    return;
  }
  //Add dynamic script that load the library
  const script = document.body.appendChild(document.createElement('script'));
  script.type = 'text/javascript';
  script.src = 'https://maps.googleapis.com/maps/api/js?key=HEREMYKEY&libraries=places';
  script.id = 'google-api';
  await new Promise(resolve => script.onload = resolve);
}
  
(async () => {
  try {
    await loadGoogleAPI();    
    console.log(typeof google.maps);
  } catch(e) {
    console.log(e);
  }
})();