Quiero trabajar con promesas pero tengo una API de devolución de llamada en un formato como:
1. Carga DOM u otro evento único:
window.onload; // set to callback
...
window.onload = function() {
};
2. Devolución de llamada simple:
function request(onChangeHandler) {
...
}
request(function() {
// change happened
...
});
3. Devolución de llamada de estilo de nodo ("nodoback"):
function getStuff(dat, callback) {
...
}
getStuff("dataParam", function(err, data) {
...
})
4. Una biblioteca completa con devoluciones de llamada de estilo de nodo:
API;
API.one(function(err, data) {
API.two(function(err, data2) {
API.three(function(err, data3) {
...
});
});
});
new Promise
complemento supone una sobrecarga significativa? Quiero envolver todas mis funciones síncronas Noje.js en una Promesa para eliminar todo el código síncrono de mi aplicación Node, pero ¿es esta la mejor práctica? En otras palabras, una función que acepta un argumento estático (por ejemplo, una cadena) y devuelve un resultado calculado, ¿debería envolverlo en una promesa? ... Leí en alguna parte que no deberías tener ningún código síncrono en Nodejs.Respuestas:
Las promesas tienen estado, comienzan como pendientes y pueden conformarse con:
Las funciones de promesa de devolución nunca deberían arrojarse , sino que deberían devolver rechazos. Lanzar desde una función de devolución de promesa lo obligará a usar a
} catch {
y a.catch
. Las personas que usan API prometidas no esperan promesas. Si no está seguro de cómo funcionan las API asíncronas en JS, consulte primero esta respuesta .1. Carga DOM u otro evento único:
Por lo tanto, crear promesas generalmente significa especificar cuándo se liquidan, es decir, cuándo pasan a la fase cumplida o rechazada para indicar que los datos están disponibles (y se puede acceder a ellos
.then
).Con implementaciones de promesas modernas que admiten el
Promise
constructor como las promesas nativas de ES6:Luego usaría la promesa resultante de la siguiente manera:
Con bibliotecas que admiten diferido (usemos $ q para este ejemplo aquí, pero también usaremos jQuery más adelante):
O con un jQuery como API, enganchando un evento que ocurre una vez:
2. Devolución de llamada simple:
Estas API son bastante comunes ya que bueno ... las devoluciones de llamada son comunes en JS. Veamos el caso común de tener
onSuccess
yonFail
:Con implementaciones de promesas modernas que admiten el
Promise
constructor como las promesas nativas de ES6:Con bibliotecas que admiten diferido (usemos jQuery para este ejemplo aquí, pero también hemos usado $ q arriba):
jQuery también ofrece un
$.Deferred(fn)
formulario, que tiene la ventaja de permitirnos escribir una expresión que emule muy de cerca elnew Promise(fn)
formulario, de la siguiente manera:Nota: Aquí explotamos el hecho de que los métodos
resolve
y los diferidos de jQueryreject
son "desmontables"; es decir. están vinculados a la instancia de jQuery.Deferred (). No todas las bibliotecas ofrecen esta función.3. Devolución de llamada de estilo de nodo ("nodoback"):
Las devoluciones de llamada de estilo de nodo (devoluciones de nodo) tienen un formato particular donde las devoluciones de llamada son siempre el último argumento y su primer parámetro es un error. Primero promisifiquemos uno manualmente:
A:
Con los diferidos puede hacer lo siguiente (usemos Q para este ejemplo, aunque Q ahora admite la nueva sintaxis que debería preferir ):
En general, no debe prometer demasiado las cosas manualmente, la mayoría de las bibliotecas de promesas que se diseñaron teniendo en cuenta el Nodo, así como las promesas nativas en el Nodo 8+, tienen un método incorporado para promulgar las devoluciones de nodo. Por ejemplo
4. Una biblioteca completa con devoluciones de llamada de estilo de nodo:
No hay una regla de oro aquí, los prometes uno por uno. Sin embargo, algunas implementaciones prometedoras le permiten hacer esto de forma masiva, por ejemplo, en Bluebird, convertir una API de retorno de nodo en una API de promesa es tan simple como:
O con promesas nativas en Node :
Notas:
.then
controlador no necesita prometer cosas. Devolver una promesa de un.then
manejador se resolverá o rechazará con el valor de esa promesa. Lanzar desde un.then
controlador también es una buena práctica y rechazará la promesa: esta es la famosa promesa de seguridad de lanzamiento.onload
caso real , debe usar enaddEventListener
lugar deonX
.fuente
resolve()
, yreject()
están escritas para ser reutilizable, aventuro que mi edición sugerida es relevante, ya que ofrece un ejemplo de la forma de jQuery$.Deferred(fn)
, que es también insuficiente. Si solo se incluye un ejemplo de jQuery, sugiero que debería ser de esta forma en lugar devar d = $.Deferred();
etc., ya que se debería alentar a las personas a usar la forma que a menudo se descuida$.Deferred(fn)
, además, en una respuesta como esta, pone a jQuery más a la par con libs que usan el patrón Revealing Constructor .$.Deferred(fn)
, si editas eso en lugar del ejemplo existente en los próximos 15 minutos, estoy seguro de que puedo tratar de aprobarlo a tiempo :)util.promisify
que Node.js se agregará a su núcleo a partir de RC 8.0.0. Su funcionamiento no es muy diferente al de BluebirdPromise.promisify
, pero tiene la ventaja de no requerir dependencias adicionales, en caso de que solo quiera Promise nativo. He escrito una publicación de blog sobre util.promisify para cualquiera que quiera leer más sobre el tema.Hoy, puedo usar
Promise
enNode.js
un método sencillo Javascript.Un ejemplo simple y básico para
Promise
(con forma de KISS ):Código de API asíncrono Javascript simple :
Promise
Código API asíncrono Javascript:(Recomiendo visitar esta hermosa fuente )
También
Promise
se puede usar juntoasync\await
conES7
para hacer que el flujo del programa espere unfullfiled
resultado como el siguiente:Otro uso con el mismo código usando el
.then()
métodoPromise
también se puede usar en cualquier plataforma basada en Node.js comoreact-native
.Bonificación : un método híbrido
(se supone que el método de devolución de llamada tiene dos parámetros como error y resultado)
El método anterior puede responder al resultado de la devolución de llamada antigua y los usos de Promesa.
Espero que esto ayude.
fuente
Antes de convertir una función como promesa en Node.JS
Después de convertirlo
En caso de que necesite manejar solicitudes múltiples
fuente
No creo que la
window.onload
sugerencia de @Benjamin funcione todo el tiempo, ya que no detecta si se llama después de la carga. He sido mordido por eso muchas veces. Aquí hay una versión que siempre debería funcionar:fuente
setTimeout(resolve, 0)
(osetImmediate
, si está disponible) para asegurarse de que se llame de forma asincrónica?resolve
sincrónicamente está bien. El marco garantiza que losthen
controladores de Promise se invoquen de forma asíncrona , independientemente de siresolve
se llama de forma sincrónica.Node.js 8.0.0 incluye una nueva
util.promisify()
API que permite que las API de estilo de devolución de llamada estándar de Node.js se envuelvan en una función que devuelve una Promesa. Un ejemplo de uso deutil.promisify()
se muestra a continuación.Ver Soporte mejorado para promesas
fuente
En la versión candidata para Node.js 8.0.0, hay una nueva utilidad,
util.promisify
(he escrito sobre util.promisify ), que encapsula la capacidad de promisificar cualquier función.No es muy diferente de los enfoques sugeridos en las otras respuestas, pero tiene la ventaja de ser un método central y no requiere dependencias adicionales.
Entonces tienes un
readFile
método que devuelve un nativoPromise
.fuente
util.promisify
dos veces (en 2014, cuando se escribió esta pregunta, y hace unos meses, lo que presioné como miembro principal de Node y es la versión actual que tenemos en Node). Como todavía no está disponible públicamente, aún no lo agregué a esta respuesta. Sin embargo, agradeceríamos profundamente los comentarios sobre el uso y conocer cuáles son algunas de las dificultades para tener mejores documentos para el lanzamiento :)util.promisify
en su publicación de blog :)util.promisify.custom
símbolo es posible anular el resultado de util.promisify? Para ser honesto, esta fue una falta intencional, porque todavía no puedo encontrar un caso de uso útil. ¿Quizás me puedan dar algunas entradas?fs.exists
tenga en cuenta API como API o API que no siguen la convención de Nodo: un bluebirdPromise.promisify
podría equivocarse, pero lasutil.promisify
hace bien.Puede usar las promesas nativas de JavaScript con Node JS.
Enlace del código My Cloud 9: https://ide.c9.io/adx2803/native-promises-in-node
fuente
Con el viejo y simple javaScript de vainilla, aquí hay una solución para promisificar una devolución de llamada api.
fuente
La biblioteca Q de kriskowal incluye funciones de devolución de llamada a promesa. Un método como este:
se puede convertir con Q.ninvoke
fuente
Q.denodeify
. ¿Necesitamos enfatizar los ayudantes de la biblioteca?Cuando tiene algunas funciones que toman una devolución de llamada y desea que devuelvan una promesa, puede usar esta función para realizar la conversión.
fuente
En el nodo v7.6 + que ha incorporado promesas y asíncrono:
Cómo utilizar:
fuente
En Node.js 8 puede promisificar métodos de objeto sobre la marcha utilizando este módulo npm:
https://www.npmjs.com/package/doasync
Utiliza util.promisify y Proxies para que sus objetos permanezcan sin cambios. La memorización también se realiza con el uso de WeakMaps). Aquí hay unos ejemplos:
Con objetos:
Con funciones:
Incluso puede usar nativo
call
yapply
vincular un contexto:fuente
Puede usar Promise nativo en ES6, por ejemplo, lidiar con setTimeout:
En este ejemplo, la Promesa no tiene motivos para fallar, por
reject()
lo que nunca se llama.fuente
La función de estilo de devolución de llamada siempre es así (casi todas las funciones en node.js son este estilo):
Este estilo tiene la misma característica:
la última función pasa la función de devolución de llamada.
la función de devolución de llamada siempre acepta el objeto de error como primer argumento.
Entonces, podría escribir una función para convertir una función con este estilo como este:
Para ser más conciso, el ejemplo anterior utilizó ramda.js. Ramda.js es una excelente biblioteca para programación funcional. En el código anterior, utilizamos su aplicación (como javascript
function.prototype.apply
) y anexar (como javascriptfunction.prototype.push
). Entonces, podríamos convertir una función de estilo de devolución de llamada a una función de estilo prometedora ahora:La función toPromise y checkErr es propia de la biblioteca berserk , es una bifurcación de biblioteca de programación funcional de ramda.js (creada por mí).
Espero que esta respuesta te sea útil.
fuente
Puedes hacer algo como esto
Entonces úsalo
fuente
es6-promisify
convierte funciones basadas en devolución de llamada en funciones basadas en Promesa.Ref: https://www.npmjs.com/package/es6-promisify
fuente
Mi versión promisificada de una
callback
función es laP
función:La
P
función requiere que la firma de devolución de llamada debe sercallback(error,result)
.fuente
util.promisify(fn)
(err, value) => ...
o usted debe definir una personalizada (consulte Funciones personalizadas personalizadas). Gracias buena catcha.var P = function (fn, ...args) { return new Promise((resolve, reject) => fn.call(this, ...args, (error, result) => error ? reject(error) : resolve(result))); };
haría lo mismo que el tuyo y es mucho más simple.A continuación se muestra la implementación de cómo una función (API de devolución de llamada) se puede convertir en una promesa.
fuente
Es como 5 años tarde, pero quería publicar aquí mi versión promesify que toma funciones de API de devoluciones de llamada y las convierte en promesas
Eche un vistazo a esta versión muy simple aquí: https://gist.github.com/jdtorregrosas/aeee96dd07558a5d18db1ff02f31e21a
fuente