Promise.all 外部解决永远解决不了

Promise.all with external resolve never resolves

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

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

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

这是必要的,因为如果“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");
  }
);

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

let resolveAhead, rejectAhead;

第一次调用 .load() 时,您将这些设置为您正在构建的新 Promise 的解析和拒绝函数。但是,下次调用 .load() 时,您将再次创建一个新的 Promise,并将这些变量覆盖为新 Promise 的 resolve/reject。然后只能调用最后构造的 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");
});