w3schools promises nodejs google from ejemplo javascript promise es6-promise

nodejs - promises javascript w3schools



¿Cómo implementar promesas canceladas y ordenadas? (5)

He reunido un ejemplo para demostrar a lo que me refiero:

function onInput(ev) { let term = ev.target.value; console.log(`searching for "${term}"`); getSearchResults(term).then(results => { console.log(`results for "${term}"`,results); }); } function getSearchResults(term) { return new Promise((resolve,reject) => { let timeout = getRandomIntInclusive(100,2000); setTimeout(() => { resolve([term.toLowerCase(), term.toUpperCase()]); }, timeout); }); } function getRandomIntInclusive(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; }

<input onInput="onInput(event)">

Escriba en el cuadro de "búsqueda" y mire la consola. ¡Los resultados de búsqueda vuelven fuera de servicio!

¿Cómo podemos cancelar cualquier promesa pendiente cuando hay una nueva entrada y garantizar que los resultados vuelvan a estar en orden?


En lugar de usar rebote, o tiempos de espera, establezco una pequeña cantidad de estado afuera en el interior (sugerencia de Jaromanda X) de esta función que usa una función referenciada. De esta forma, puedes cambiar la referencia de la función a algo así como un noop . La promesa aún se resuelve, pero no tomará ninguna medida. Sin embargo, el último no habrá cambiado su función de referencia:

var onInput = function() { let logger = function(term, results) { console.log(`results for "${term}"`, results); }; let noop = Function.prototype; let lastInstance = null; function ActionManager(action) { this.action = action; } return function onInput(ev) { let term = ev.target.value; console.log(`searching for "${term}"`); if (lastInstance) { lastInstance.action = noop; } let inst = new ActionManager(logger.bind(null, term)); lastInstance = inst; getSearchResults(term).then(response => inst.action(response)); } }(); /**************************************** * The rest of the JavaScript is included only for simulation purposes ****************************************/ function getSearchResults(term) { return new Promise((resolve, reject) => { let timeout = getRandomIntInclusive(100, 2000); setTimeout(() => { resolve([term.toLowerCase(), term.toUpperCase()]); }, timeout); }); } function getRandomIntInclusive(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; }

<input onInput="onInput(event)">


No debe usar setTimeout ''s en las promesas de la forma en que lo está haciendo, porque desde el .then está devolviendo la devolución de llamada desde .setTimeout() que no funcionaría y estropearía el orden. Para hacer que las promesas vayan en orden, debes hacer una función como la que se muestra a continuación:

function wait(n){ return new Promise(function(resolve){ setTimeout(resolve, n) }); }

y sustituya setTimeout() con esa función como se muestra a continuación:

wait(getRandomIntInclusive(100,2000)).then(function(){ // code });


Puede usar el paquete async : un conjunto de utilidades para mantener el código asíncrono. Se desarrolló por primera vez para node.js pero también se puede usar en frontend.
Necesita una función de series , guarda un orden de promesas. Aquí hay un breve ejemplo en coffeescript:

async.series([ -> ### do some stuff ### Q ''one'' -> ### do some more stuff ... ### Q ''two'' ]).then (results) -> ### results is now equal to [''one'', ''two''] ### doStuff() .done() ### an example using an object instead of an array ### async.series({ one: -> Q.delay(200).thenResolve(1) two: -> Q.delay(100).thenResolve(2) }).then (results) -> ### results is now equal to: {one: 1, two: 2} ### doStuff() .done()

Ver caolan.github.io/async/


Una solución factible es incluir una latestTimestamp y simplemente ignorar cualquier respuesta que venga con una marca de tiempo temprana (y por lo tanto, obsoleta).

let latestTimestamp = 0; function onInput(ev) { let term = ev.target.value; console.log(`searching for "${term}"`); latestTimestamp = Date.now(); getSearchResults(term, latestTimestamp).then(results => { if (results[2] !== latestTimestamp) { console.log("Ignoring old answer"); } else { console.log(`results for "${term}"`, results); } }); } function getSearchResults(term, latestTimestamp) { return new Promise((resolve, reject) => { let timeout = getRandomIntInclusive(100, 2000); setTimeout(() => { resolve([term.toLowerCase(), term.toUpperCase(), latestTimestamp]); }, timeout); }); } function getRandomIntInclusive(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; }

<input onInput="onInput(event)">


Puede usar Promise.race para cancelar el efecto de una cadena anterior:

let cancel = () => {}; function onInput(ev) { let term = ev.target.value; console.log(`searching for "${term}"`); cancel(); let p = new Promise(resolve => cancel = resolve); Promise.race([p, getSearchResults(term)]).then(results => { if (results) { console.log(`results for "${term}"`,results); } }); } function getSearchResults(term) { return new Promise(resolve => { let timeout = 100 + Math.floor(Math.random() * 1900); setTimeout(() => resolve([term.toLowerCase(), term.toUpperCase()]), timeout); }); }

<input onInput="onInput(event)">

Aquí lo hacemos inyectando un resultado undefined y probando para ello.