多个监听者实现同一个承诺

nom*_*oda 4 javascript

我有一个带有异步函数的模块,init()该函数被多次调用。但是,我只希望函数的效果init()触发一次,任何后续调用都应该等待最初的承诺解决。

这是我当前的代码。此示例中的错误是,第二次init()调用该函数时,由于脚本标记已经存在,因此会立即解决该问题。我想等待onload第一次调用时创建的脚本的回调init()。

let scriptExists = false;

// This function should only be called once
// Returns a mock script that calls onload after 1000ms
function addScript() {
  const mockScript = {
    onload: () => {}
  };
  setTimeout(() => mockScript.onload(), 1000);
  return mockScript;
}

// Add script and wait for it to load
function init() {
  return new Promise((resolve) => {
    if (!scriptExists) {
      const script = addScript();
      scriptExists = true;
      script.onload = resolve;
    } else {
      // TODO: This should only resolve if the script has loaded
      resolve();
    }
  });
}

// Wait for the script to load, then add message
async function doSomethingNice() {
  await init();
  console.log("nocie");
}

// Wait for the script to load, then add message
async function doSomethingElse() {
  await init();
  console.log("something else");
}

doSomethingNice();
doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

https://codesandbox.io/s/modest-cohen-9k4bf?file=/src/index.js

Nic*_*wer 5

您可以设置您的init函数,使其只执行一次工作,并在后续调用中返回第一次的承诺:

let promise;
function init() {
  if (!promise) {
    promise = new Promise((resolve) => {
      const script = document.createElement('script');
      script.id = SCRIPT_ID;
      script.onload = resolve;
      script.type = 'text/javascript';
      script.src = 'https://www.example.com/';
      document.head.appendChild(script);
    });
  }
  return promise;
}
Run Code Online (Sandbox Code Playgroud)