首页 > 解决方案 > 具有外部解析的 Promise.all 永远不会解析

问题描述

我正在开发一个 SPA(单页应用程序)项目,需要以动态和受控的方式(CSS、HTML 和 JS)加载文件

我创建了下面的结构(在此示例中仅用于 CSS),但尽管文件被注入到页面中,但承诺从未得到解决

该结构的一个特点是每个“promise”创建的“resolve”和“reject”都保存在原始“promise”函数之外执行

这是必要的,因为如果“承诺”成功,则必须移除控制事件,如果发生错误,则必须移除元素

'use strict';

const

  css=
    (
      ()=>
      {
        const
          load=
            url=>
            {
              return new Promise(
                (resolve,reject)=>
                {
                  let
                    link=document.createElement("link");
                  link.setAttribute("href",url);
                  link.setAttribute("rel","stylesheet");
                  link.addEventListener("load",onSuccess);
                  link.addEventListener("error",onError);
                  resolveAhead=resolve;
                  rejectAhead=reject;
                  document.head.appendChild(link);
                }
              );
            },
          onSuccess=
            event=>
            {
              event.target.removeEventListener("load",onSuccess);
              event.target.removeEventListener("error",onError);
              resolveAhead(event);
            },
          onError=
            event=>
            {
              document.head.removeChild(event.target);
              rejectAhead(event);
            };
        let
          resolveAhead,
          rejectAhead;
        return {
          load
        }
      }
    )();

Promise.all(
  [
    css.load("style1.css"),
    css.load("style2.css"),
    css.load("style3.css"),
    css.load("style4.css"),
    css.load("style5.css"),
    css.load("style6.css")
  ]
).then(
  response=>
  {
    console.log(response);
    alert("Well done");
  }
).catch(
  response=>
  {
    console.log(response);
    alert("Houston... we've had a problem here");
  }
);

标签: javascriptpromisepromise.all

解决方案


您的问题是您有两个变量:

let resolveAhead, rejectAhead;

第一次调用.load()时,将它们设置为正在构建的新 Promise 的 resolve 和 reject 函数。但是,下次调用 时.load(),您将再次创建一个新的 Promise,并覆盖这些变量以作为新 Promise 的解析/拒绝。然后只能调用最后构造的 Promise 中的 resolve/reject 函数。

您可以在load()函数内部创建对这些的引用,以便进一步调用load()不会影响已定义的 resolveAhead 和 rejectAhead 函数:

'use strict';
const css = (() => {
  const load = url => {
    let resolveAhead, rejectAhead;
    
    const onSuccess = event => {
      event.target.removeEventListener("load", onSuccess);
      event.target.removeEventListener("error", onError);
      resolveAhead(event);
    };
    const onError = event => {
      document.head.removeChild(event.target);
      rejectAhead(event);
    };
    
    return new Promise(
      (resolve, reject) => {
        let link = document.createElement("link");
        link.setAttribute("href", url);

        link.setAttribute("rel", "stylesheet");
        link.addEventListener("load", onSuccess);
        link.addEventListener("error", onError);
        resolveAhead = resolve;
        rejectAhead = reject;
        document.head.appendChild(link);
      }
    );
  };
  
  return {load};
})();

Promise.all([
 css.load("https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"),
 css.load("https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css"),
]).then(response => {
  console.log(response);
  alert("Well done");
}).catch(response=> {
  console.log(response);
  alert("Houston... we've had a problem here");
});


推荐阅读