Tengo un módulo con una función asíncrona init() que se invoca varias veces. Sin embargo, solo quiero que el efecto de la función init() se active una vez y cualquier llamada posterior solo debe esperar a que se resuelva esa promesa inicial.
Aquí está mi código actual. El error en este ejemplo es que la segunda vez que se llama a la función init() , se resuelve inmediatamente ya que la etiqueta del script ya existe. Me gustaría esperar la onload de llamada de carga del script creado en la primera invocación de 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();https://codesandbox.io/s/modest-cohen-9k4bf?file=/src/index.js
Puede configurar su función init para que solo haga el trabajo una vez, y en llamadas posteriores devuelva la promesa desde la primera vez:
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; }Aquí hay un ejemplo de trabajo, creo que si lo usa en el contexto de una clase, será un mejor patrón de código.
function init() { return new Promise((resolve) => { console.log("run"); if (!document.getElementById("script")) { 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); } else { resolve(); } }); } var loader = undefined; async function doSomethingNice() { !loader ? (loader = init()) : await loader; console.log("nice"); } async function doSomethingElse() { !loader ? (loader = init()) : await loader; console.log("something else"); } doSomethingNice(); doSomethingElse();Entonces, básicamente, no tenemos ninguna API nativa para verificar el estado de la promesa. Entonces, lo que podemos hacer es tener una variable y verificarla con otra función que devuelva una Promesa.
No pude usar completamente su código de muestra, pero este es un ejemplo de trabajo. Dado que se resuelve una promesa, pasamos a la otra llamada.
let PromiseState = false; const promiseStateTimer = 1000; // this function is responsible to manage the state function checkState() { return new Promise((resolve) => { const checkInterval = setInterval(() => { // console.log(PromiseState); if (!PromiseState) { clearInterval(checkInterval); resolve(PromiseState); } }, promiseStateTimer); }); } function init() { // change state ------------------- ! if (!PromiseState) { PromiseState = !PromiseState; } return new Promise((resolve, reject) => { setTimeout(() => { // revert back the state while resolving -------------------- ! PromiseState = !PromiseState; resolve("Hello"); }, 3000); }); } async function doSomethingNice() { await checkState(); await init(); console.log("something nice"); } async function doSomethingElse() { await checkState(); await init(); console.log("something else"); } doSomethingNice(); doSomethingElse();Según el PromiseStateTimer, el estado de PromiseState se verifica cada segundo y luego se resuelven los valores, pero aún debe agregar algunos parches a su Promesa escuchada para que funcionen.