Tengo una promesa de JavaScript pura (implementación integrada o relleno de polietileno):
var promise = new Promise(function (resolve, reject) { /* ... */ });
De la especificación , una Promesa puede ser uno de:
- 'resuelto' y 'resuelto'
- 'resuelto' y 'rechazado'
- 'pendiente'
Tengo un caso de uso en el que deseo interrogar a Promise sincrónicamente y determinar:
¿Está resuelta la promesa?
Si es así, ¿se resuelve la promesa?
Sé que puedo usar #then()
para programar el trabajo que se realizará de forma asíncrona después de que Promise cambie de estado. NO estoy preguntando cómo hacer esto.
Esta pregunta es específicamente sobre la interrogación sincrónica del estado de una promesa . ¿Cómo puedo conseguir esto?
javascript
promise
es6-promise
broma
fuente
fuente
var promiseStatus = NEW_PRIVATE("Promise#status");
,PromiseSet
función enSET_PRIVATE(promise, promiseStatus, status);
console.log(Promise.new((resolve, reject) => {})
=>Promise { <pending> }
Respuestas:
No existe tal API de inspección síncrona para las promesas nativas de JavaScript. Es imposible hacer esto con las promesas nativas. La especificación no especifica dicho método.
Las bibliotecas Userland pueden hacer esto, y si está apuntando a un motor específico (como v8) y tiene acceso al código de la plataforma (es decir, puede escribir código en el núcleo ), entonces puede usar herramientas específicas (como símbolos privados) para lograr esto . Sin embargo, eso es súper específico y no en el país de los usuarios.
fuente
.any
y cometido un error porque Mark insistió. Por un lado,Promise.race([])
es una promesa pendiente para siempre (y no un error), generalmente desea la primera promesa exitosa y no solo la primera promesa. De todos modos, eso no es realmente relevante para la pregunta formulada: OP preguntó sobre la inspección sincrónica y no sobre.race
sus muchas deficiencias.MakeQueryablePromise(Promise.resolve(3)).isResolved
es falsa, pero la promesa se resuelve de manera bastante obvia. Sin mencionar que la respuesta también está usando el término "resuelto" y "cumplido" incorrectamente. Para hacer esa respuesta, simplemente puede agregar un.then
controlador usted mismo, que omite por completo el punto de inspección sincrónica.promise-status-async hace el truco. Es asíncrono pero no sirve
then
para esperar la promesa de ser resuelta.fuente
No, no hay API de sincronización, pero aquí está mi versión de la asíncrona
promiseState
(con ayuda de @Matthijs):fuente
Promise.race([ Promise.resolve(p).then(() => "fulfilled", () => "rejected"), Promise.resolve().then(() => "pending") ]);
aunque esto me parece más seguro:const t = {}; return Promise.race([p,t]).then(v => v === t ? "pending" : "fulfilled", () => "rejected")
y evita crear promesas adicionales que persisten mientras el p original esté pendiente.Puedes hacer una carrera con Promise.resolve
No es sincrónico pero sucede ahora
Un pequeño script para probar y comprender su significado de forma asincrónica
resultados con retraso (0) (comentar el tiempo de retraso)
y los resultados de esta prueba con firefox (Chrome mantiene el orden)
promiseState make .race y .then: Level 2
fuente
'a value that p should not return'
usar un SímboloSymbol
sería un valor único, por lo tanto, nunca tendría que adivinar qué "valor [...] p no debería devolver". Sin embargo, una referencia a un objeto específico funcionaría igual de bien.Puede usar un truco (feo) en Node.js hasta que se ofrezca un método nativo:
fuente
Promise.prototype.isPending = function(){ return util.inspect(this).indexOf("<pending>")>-1; }
process.binding('util').getPromiseDetails
Promise.resolve('<pending>')
.en el nodo, digamos interno no documentado
process.binding('util').getPromiseDetails(promise)
fuente
Actualizado: 2019
Bluebird.js ofrece esto: http://bluebirdjs.com/docs/api/isfulfilled.html
Si prefiere crear su propio contenedor, aquí hay un buen blog al respecto.
Debido a que JavaScript es de subproceso único, es difícil encontrar un caso de uso lo suficientemente común como para justificar poner esto en la especificación. El mejor lugar para saber si se resuelve una promesa es en .then (). Probar si se cumple una Promesa crearía un bucle de sondeo que probablemente sea la dirección incorrecta.
async / await es una buena construcción si desea razonar el código asincrónico sincrónicamente.
Otra llamada útil es Promise.all ()
Cuando busqué por primera vez esta respuesta, ese es el caso de uso que estaba buscando.
fuente
Puedes envolver tus promesas de esta manera
fuente
.then
siempre ejecuta OP asíncronamente, quien quiera inspeccionar una promesa en el mismo turno no obtendrá el resultado correcto aquí. Nota OP preguntó específicamente sobre la inspección sincrónica y mencionó que ya saben acerca de la inspección asincrónica.De hecho, es bastante molesto que falte esta funcionalidad básica. Si está utilizando node.js, sé dos soluciones alternativas, ninguna de las cuales es muy bonita. Ambos fragmentos a continuación implementan la misma API:
No parece haber ninguna forma de distinguir los dos últimos estados de promesa utilizando cualquiera de los trucos.
1. Use la API de depuración V8
Este es el mismo truco que
util.inspect
usa.2. Ejecute sincrónicamente microtasks
Esto evita la API de depuración, pero tiene una semántica aterradora al hacer que todas las microtasks y las
process.nextTick
devoluciones de llamada pendientes se ejecuten sincrónicamente. También tiene el efecto secundario de evitar que se active el error de "rechazo de promesa no manejada" para la promesa inspeccionada.fuente
process._tickCallback
(o incluso% RunMicrotick): romperá aleatoriamente las cosas en su código. Intenté desesperadamente que funcionara (para temporizadores falsos en funciones asíncronas, principalmente) y nunca fue lo suficientemente estable desde el lado del Nodo. Dejé de trabajar en ello. La API de espejo de depuración V8 es completamente apropiada aquí.DeprecationWarning: DebugContext has been deprecated and will be removed in a future version.
:( Parece que V8 lo eliminóprocess.binding('util').getPromiseDetails( promise )
devoluciones[ 0, ]
por pendientes,[ 1, value ]
por cumplidas y[ 2, value ]
por rechazadas.Advertencia: este método utiliza elementos internos de Node.js no documentados y se puede cambiar sin previo aviso.
En Node puede determinar sincrónicamente el estado de una promesa utilizando
process.binding('util').getPromiseDetails(/* promise */);
.Esto devolverá:
[0, ]
por pendiente,[1, /* value */]
por cumplido, o[2, /* value */]
por rechazado.Envolviendo esto en una función auxiliar:
fuente
jest
(que es el único lugar en el que estoy interesado, de verdad). La función existe, pero siempre parece regresarundefined
. ¿Cómo averiguo lo que está mal?mocha
;jest
aunque nunca lo probé . ¿Quizás comience una nueva pregunta que vincule aquí e incluya su versión Node.js y sujest
versión?Promise
que solo estaba usando para probar cosas que deberían estar sucediendo mientrasPromise
está pendiente, pero pensé que mientras lo que escribí funciona, entonces no hay necesidad de probar eso Además de lo que se basa en ello.lo que puede hacer es usar una variable para almacenar el estado, establecer manualmente el estado en esa variable y verificar esa variable.
Por supuesto, esto significa que debe tener acceso al código original de la promesa. Si no lo hace, entonces puede hacer:
Mi solución es más codificación, pero creo que probablemente no tenga que hacer esto para cada promesa que use.
fuente
A partir de la versión 8 de Node.js, ahora puede usar el paquete de inspección inteligente para inspeccionar sincrónicamente las promesas nativas (sin ningún truco peligroso).
fuente
Puede agregar un método a Promise.prototype. Se parece a esto:
Editado: la primera solución no funciona correctamente, como la mayoría de las respuestas aquí. Devuelve "pendiente" hasta que se invoca la función asincrónica ".then", lo que no ocurre de inmediato. (Lo mismo se trata de soluciones que usan Promise.race). Mi segunda solución resuelve este problema.
Puedes usarlo en cualquier Promesa. Por ejemplo:
Segunda (y correcta) solución:
Y úsalo:
Aviso : en esta solución no tiene que usar el operador "nuevo".
fuente
Aquí hay una versión es6 más desarrollada de QueryablePromise, que permite encadenar y capturar después de la primera resolución e inmediatamente resolver o rechazar para mantener la API coherente con la Promesa nativa.
fuente
await
uso para la respuesta de @ jib , con prototipos idiomáticos.tenga en cuenta que esta función asíncrona se ejecuta "casi" inmediatamente como una función sincronizada (o en realidad puede ser instantáneamente).
fuente
2019:
La forma simple de hacer eso, como sé
thenable
, es un envoltorio súper delgado para promesa o cualquier trabajo asíncrono.fuente
Puede crear su propia subclase, por ejemplo
QueryablePromise
, heredando de laPromise
clase disponible de forma nativa , cuyas instancias tendrían unastatus
propiedad disponible que puede usar para consultar el estado de los objetos de promesa de forma sincrónica . Una implementación de la misma se puede ver a continuación o consulte esto para una mejor explicación.fuente
fetch
, me devolverá una promesa nativa. ¿Cómo ayudaría tu clase con eso?const queryableFetch = new QueryablePromise((resolve, reject) => {fetch(/.../).then((data) => resolve(data)) })
:? O, ¿hay algún problema con eso? : /, err => reject(err)
como un segundo argumentothen
o no propagará los errores correctamente (entre las razones por las que se considera el antipatrón del constructor de promesas ). Sin embargo, no es realmente sincrónico (por ejemplo, no detectará una promesa ya resuelta), pero tal vez sea útil en los casos en que no controle a la persona que llama y la respuesta sea necesaria de inmediato.Hay otra forma elegante y hacky de verificar si una promesa aún está pendiente simplemente convirtiendo todo el objeto en una cadena y verificándolo con la ayuda de una inspección como esta:
util.inspect(myPromise).includes("pending")
.Probado en Node.js 8,9,10,11,12,13
Aquí hay un ejemplo completo
Resultado:
fuente
Si usa ES7 experimental, puede usar async para ajustar fácilmente la promesa que desea escuchar.
fuente
He escrito un pequeño paquete npm, promise-value, que proporciona un contenedor de promesas con una
resolved
bandera:https://www.npmjs.com/package/promise-value
También le da acceso sincrónico al valor prometido (o error). Esto no altera el objeto Promise en sí mismo, siguiendo el ajuste en lugar de extender el patrón.
fuente
Esta es una pregunta anterior, pero estaba tratando de hacer algo similar. Necesito mantener a n trabajadores trabajando. Están estructurados en una promesa. Necesito escanear y ver si están resueltos, rechazados o aún pendientes. Si se resuelve, necesito el valor, si se rechaza hacer algo para corregir el problema o pendiente. Si se resuelve o rechaza, necesito comenzar otra tarea para continuar. No puedo encontrar una manera de hacerlo con Promise.all o Promise.race, ya que sigo trabajando las promesas en una matriz y no puedo encontrar la manera de eliminarlas. Entonces creo un trabajador que hace el truco
Necesito una función de generador de promesas que devuelva una promesa que se resuelva o rechace según sea necesario. Es invocado por una función que configura el marco para saber qué está haciendo la promesa.
En el siguiente código, el generador simplemente devuelve una promesa basada en setTimeout.
Aquí está
doWork devuelve un objeto que contiene la promesa y su estado y valor devuelto.
El siguiente código ejecuta un ciclo que prueba el estado y crea nuevos trabajadores para mantenerlo en 3 trabajadores en ejecución.
Probado en node.js
Por cierto, no tanto en esta respuesta, sino en otros sobre temas similares, ODIO cuando alguien dice "no entiendes" o "no funciona así". Por lo general, supongo que el interlocutor sabe lo que quiere. Sugerir una mejor manera es genial. Una explicación paciente de cómo funcionan las promesas también sería buena.
fuente
Encontré que esta solución es simple y me permite continuar usando promesas nativas, pero agregar comprobaciones síncronas útiles. Tampoco tuve que sacar toda una biblioteca de promesas.
PRUEBA: esto solo funciona si hay algún tipo de interrupción en el hilo de ejecución actual para permitir que las promesas se ejecuten ANTES de verificar las construcciones síncronas. Eso hace que esto tenga una utilidad más limitada de lo que inicialmente pensé, aunque sigue siendo útil para mi caso de uso (gracias Benjamin Gruenbaum por señalar esto)
Desde https://ourcodeworld.com/articles/read/317/how-to-check-if-a-javascript-promise-has-been-fulfilled-rejected-or-resolved que basaron su respuesta en ¿Hay alguna manera de saber si una promesa de ES6 se cumple / rechaza / resuelve?
fuente
MakeQueryablePromise(Promise.resolve(3)).isResolved
es falso, pero la promesa está obviamente resuelta. Sin mencionar que la respuesta también está usando el término "resuelto" y "cumplido" incorrectamente. Para hacer esa respuesta, simplemente puede agregar un.then
controlador usted mismo, que omite por completo el punto de inspección sincrónica.let wrappedPromise = MakeQueryablePromise(Promise.resolve(3)); setTimeout(function() {console.log(wrappedPromise.isFulfilled())}, 1);
Que mientras lo hagas, esto funciona bien. Pero tienes que entender ese hecho para que esto sea útil. Actualizaré la descripción con esa advertencia. También estoy de acuerdo en que el nombre de la función podría ser mejor / más idiomático.then
cumplir la promesa original y lograr lo mismo, ya que de todos modos es asíncrono. Hay una manera conprocess.binding('util').getPromiseDetails
que parece funcionar, pero está utilizando una API privada