Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

244
Views
Use Promesa para esperar hasta que se cumpla la condición de sondeo

Necesito crear una promesa de JavaScript que no se resolverá hasta que se cumpla una condición específica. Digamos que tengo una biblioteca de terceros y necesito esperar hasta que exista una determinada condición de datos dentro de esa biblioteca.

El escenario que me interesa es uno en el que no hay forma de saber cuándo se cumple esta condición más que mediante un simple sondeo.

Puedo crear una promesa que espera, y este código funciona, pero ¿hay un enfoque mejor o más conciso para este problema?

 function ensureFooIsSet() { return new Promise(function (resolve, reject) { waitForFoo(resolve); }); } function waitForFoo(resolve) { if (!lib.foo) { setTimeout(waitForFoo.bind(this, resolve), 30); } else { resolve(); } }

Uso:

 ensureFooIsSet().then(function(){ ... });

Normalmente implementaría un tiempo máximo de sondeo, pero no quería que eso empañara el problema aquí.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Una pequeña variación sería usar un IIFE con nombre para que su código sea un poco más conciso y evite contaminar el alcance externo:

 function ensureFooIsSet() { return new Promise(function (resolve, reject) { (function waitForFoo(){ if (lib.foo) return resolve(); setTimeout(waitForFoo, 30); })(); }); }
over 4 years ago · Santiago Trujillo Report

0

Aquí hay una función waitFor que uso bastante. Le pasa una función, y verifica y espera hasta que la función devuelva un valor verdadero, o hasta que se agote el tiempo de espera.

  • Esta es una versión simple que ilustra lo que hace la función, pero es posible que desee usar la versión completa, agregada más adelante en la respuesta
 let sleep = ms => new Promise(r => setTimeout(r, ms)); let waitFor = async function waitFor(f){ while(!f()) await sleep(1000); return f(); };

Ejemplos de usos:

  • esperar a que exista un elemento, luego asignarlo a una variable
 let bed = await waitFor(() => document.getElementById('bedId')) if(!bed) doSomeErrorHandling();
  • esperar a que una variable sea veraz
 await waitFor(() => el.loaded)
  • esperar a que alguna prueba sea cierta
 await waitFor(() => video.currentTime > 21)
  • agregue un tiempo de espera específico para dejar de esperar
 await waitFor(() => video.currentTime > 21, 60*1000)
  • pásalo alguna otra función de prueba
 if(await waitFor(someTest)) console.log('test passed') else console.log("test didn't pass after 20 seconds")

Versión completa:

Esta versión se ocupa de más casos que la versión simple, nulo, indefinido, matriz vacía, etc., tiene un tiempo de espera, se puede pasar una frecuencia como argumento y registra en la consola lo que está haciendo con algunos colores agradables.

 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms));} /** * Waits for the test function to return a truthy value * example usage: * wait for an element to exist, then save it to a variable * let el = await waitFor(() => document.querySelector('#el_id'))) * timeout_ms and frequency are optional parameters */ async function waitFor(test, timeout_ms = 20 * 1000, frequency = 200) { if (typeof (test) != "function") throw new Error("test should be a function in waitFor(test, [timeout_ms], [frequency])") if (typeof (timeout_ms) != "number") throw new Error("timeout argument should be a number in waitFor(test, [timeout_ms], [frequency])"); if (typeof (frequency) != "number") throw new Error("frequency argument should be a number in waitFor(test, [timeout_ms], [frequency])"); let logPassed = () => console.log('Passed: ', test); let logTimedout = () => console.log('%c' + 'Timeout : ' + test, 'color:#cc2900'); let last = Date.now(); let logWaiting = () => { if(Date.now() - last > 1000) { last = Date.now(); console.log('%c' + 'waiting for: ' + test, 'color:#809fff'); } } let endTime = Date.now() + timeout_ms; let isNotTruthy = (val) => val === undefined || val === false || val === null || val.length === 0; // for non arrays, length is undefined, so != 0 let result = test(); while (isNotTruthy(result)) { if (Date.now() > endTime) { logTimedout(); return false; } logWaiting(); await sleep(frequency); result = test(); } logPassed(); return result; }
over 4 years ago · Santiago Trujillo Report

0

¿Hay un enfoque más conciso para este problema?

Bueno, con esa función waitForFoo no necesitas una función anónima en tu constructor:

 function ensureFooIsSet() { return new Promise(waitForFoo); }

Para evitar contaminar el alcance, recomendaría envolver ambos en un IIFE o mover la función waitForFoo dentro del alcance de ensureFooIsSet :

 function ensureFooIsSet(timeout) { var start = Date.now(); return new Promise(waitForFoo); function waitForFoo(resolve, reject) { if (window.lib && window.lib.foo) resolve(window.lib.foo); else if (timeout && (Date.now() - start) >= timeout) reject(new Error("timeout")); else setTimeout(waitForFoo.bind(this, resolve, reject), 30); } }

Alternativamente, para evitar el enlace que se necesita para pasar la resolve y el reject , puede moverlo dentro de la devolución de llamada del constructor Promise como sugirió @DenysSéguret.

¿Hay un mejor enfoque?

Como comentó @BenjaminGruenbaum, puede ver que se asigne la propiedad .foo , por ejemplo, usando un setter:

 function waitFor(obj, prop, timeout, expected) { if (!obj) return Promise.reject(new TypeError("waitFor expects an object")); if (!expected) expected = Boolean; var value = obj[prop]; if (expected(value)) return Promise.resolve(value); return new Promise(function(resolve, reject) { if (timeout) timeout = setTimeout(function() { Object.defineProperty(obj, prop, {value: value, writable:true}); reject(new Error("waitFor timed out")); }, timeout); Object.defineProperty(obj, prop, { enumerable: true, configurable: true, get: function() { return value; }, set: function(v) { if (expected(v)) { if (timeout) cancelTimeout(timeout); Object.defineProperty(obj, prop, {value: v, writable:true}); resolve(v); } else { value = v; } } }); }); // could be shortened a bit using "native" .finally and .timeout Promise methods }

Puede usarlo como waitFor(lib, "foo", 5000) .

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!