You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1-js/11-async/06-promisify/article.md
+35-21Lines changed: 35 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,20 +1,20 @@
1
-
# Promisification
1
+
# Promisificación
2
2
3
-
Promisification (Promisificación) -- es una palabra larga para una simple transformación. Es una conversión: de una función que acepta un callback a una función que retorna una promesa.
3
+
"Promisificación" es una simple transformación. Es la conversión de una función que acepta un callback a una función que devuelve una promesa.
4
4
5
-
En otras palabras, creamos una función de envoltura que realiza lo mismo, llamando a la original internamente, pero retornando una promesa.
5
+
A menudo estas transformaciones son necesarias en la vida real ya que muchas funciones y librerías están basadas en callbacks, pero las promesas son más convenientes así que tiene sentido promisificarlas.
6
6
7
-
Estas transformaciones son usualmente necesarias en la vida real, ya que muchas funciones y librerías están basadas en callbacks. Pero las promesas son mas convenientes, así que tiene sentido promisificar.
7
+
Veamos un ejemplo.
8
8
9
-
Por ejemplo, tenemos `loadScript(src, callback)` del capítulo<info:callbacks>.
9
+
Aquí tenemos `loadScript(src, callback)` del artículo<info:callbacks>.
10
10
11
11
```js run
12
12
functionloadScript(src, callback) {
13
13
let script =document.createElement('script');
14
14
script.src= src;
15
15
16
16
script.onload= () =>callback(null, script);
17
-
script.onerror= () =>callback(newError(`Error de carga de script para ${src}`));
17
+
script.onerror= () =>callback(newError(`Error de carga de script ${src}`));
18
18
19
19
document.head.append(script);
20
20
}
@@ -23,9 +23,15 @@ function loadScript(src, callback) {
Vamos a promisificarla. La función nueva `loadScriptPromise(src)` va a hacer lo mismo, pero solo acepta `src` (sin callback) y retorna una promesa.
26
+
La función carga un script con el `src` dado, y llama a `callback(err)` en caso de error o `callback(null, script)` en caso de carga exitosa. Esto está ampliamente acordado en el uso de callbacks, lo hemos visto antes.
27
27
28
-
Aquí:
28
+
Vamos a promisificarla.
29
+
30
+
Haremos una función nueva `loadScriptPromise(src)` que va a hacer lo mismo (carga el script), pero devuelve una promesa en vez de usar callbacks.
31
+
32
+
Es decir: pasamos solamente `src` (sin `callback`) y obtenemos una promesa de vuelta, que resuelve con `script` cuando la carga fue exitosa y rechaza con error en caso contrario.
33
+
34
+
Aquí está:
29
35
```js
30
36
letloadScriptPromise=function(src) {
31
37
returnnewPromise((resolve, reject) => {
@@ -40,21 +46,19 @@ let loadScriptPromise = function(src) {
40
46
// loadScriptPromise('path/script.js').then(...)
41
47
```
42
48
43
-
Ahora `loadScriptPromise` se ajusta bien a nuestro código basado en promesas.
49
+
Como podemos ver, la nueva función es un "wrapper" (una función contenedora) que envuelve la función `loadScript` original. La llama proveyendo su propio callback y la traduce a una promesa `resolve/reject`.
44
50
45
-
Como podemos ver, le delega todo el trabajo a la función `loadScript` original, proveyendo su propio callback que es traducido a promise `resolve/reject`.
51
+
Ahora `loadScriptPromise` se adapta bien a un código basado en promesas. Si nos gustan más las promesas que los callbacks (y pronto veremos más motivos para ello), la usaremos en su lugar.
46
52
47
-
Como vamos a tener que promisificar muchas funciones, tiene sentido usar un ayudante.
53
+
En la práctica podemos necesitar promisificar más de una función, así que tiene sentido usar un ayudante.
48
54
49
-
Esto es en realidad muy simple -- La función `promisify(f)` debajo toma una función `f` que sera promisificada y retorna una función de envoltura (wrapper function).
50
-
51
-
Esa envoltura realiza lo mismo que el código de arriba: retorna una promesa y pasa el llamado a la `f` original, rastreando el resultado en un callback personalizado.
55
+
Lo llamamos `promisify(f)`: esta acepta la función a promisificar `f` y devuelve una función contenedora (wrapper).
52
56
53
57
```js
54
58
functionpromisify(f) {
55
-
returnfunction (...args) { //retorna una función de envoltura
59
+
returnfunction (...args) { //devuelve una función contenedora (*)
56
60
returnnewPromise((resolve, reject) => {
57
-
functioncallback(err, result) { // nuestro callback personalizado para f
61
+
functioncallback(err, result) { // nuestro callback personalizado para f (**)
58
62
if (err) {
59
63
reject(err);
60
64
} else {
@@ -74,11 +78,18 @@ let loadScriptPromise = promisify(loadScript);
74
78
loadScriptPromise(...).then(...);
75
79
```
76
80
77
-
Aquí asumimos que la función original espera un callback con dos argumentos `(err, result)`. Eso es lo que usualmente encontramos. Entonces nuestro callback personalizado está exactamente en el formato correcto, y `promisify` funciona muy bien para tal caso.
81
+
El código puede verse complicado, pero es esencialmente lo mismo que escribimos arriba al promisificar la función `loadScript`.
82
+
83
+
Una llamada a `promisify(f)` devuelve una función contenedora que envuelve a `f``(*)`. Este contenedor devuelve una promesa y redirige el llamado a la `f` original, siguiendo el resultado en el callback personalizado `(**)`.
84
+
85
+
Aquí `promisify` asume que la función original espera un callback con dos argumentos `(err, result)`. Eso es lo que usualmente encontramos. Entonces nuestro callback personalizado está exactamente en el formato correcto, y `promisify` funciona muy bien para tal caso.
78
86
79
87
¿Y si la `f` original espera un callback con más argumentos `callback(err, res1, res2)`?
80
88
81
-
Aquí hay una modificación de `promisify` que retorna un array de los múltiples resultados del callback:
89
+
Podemos mejorar el ayudante. Hagamos una versión de `promisify` más avanzada.
90
+
91
+
- Cuando la llamamos como `promisify(f)`, debe funcionar igual que en la versión previa.
92
+
- Cuando la llamamos como `promisify(f, true)`, debe devolver una promesa que resuelve con el array de resultados del callback. Esto es para callbacks con muchos argumentos.
82
93
83
94
```js
84
95
// promisify(f, true) para conseguir array de resultados
@@ -89,7 +100,7 @@ function promisify(f, manyArgs = false) {
89
100
if (err) {
90
101
reject(err);
91
102
} else {
92
-
//Retornar todos los resultados del callback si manyArgs es especificado
103
+
//Devolver todos los resultados del callback si "manyArgs" es especificado
93
104
*!*resolve(manyArgs ? results : results[0]);*/!*
94
105
}
95
106
}
@@ -105,12 +116,15 @@ function promisify(f, manyArgs = false) {
105
116
f =promisify(f, true);
106
117
f(...).then(arrayOfResults=>..., err=>...);
107
118
```
108
-
En algunos casos, puede que `err` esté ausente: `callback(result)`, o que haya algo que no es habitual en el formato del callback, por lo que tendremos que promisificar tales funciones manualmente.
119
+
120
+
Como puedes ver es esencialmente lo mismo de antes, pero `resolve` es llamado con solo uno o con todos los argumentos dependiendo del valor de `manyArgs`.
121
+
122
+
Para formatos más exóticos de callback, como aquellos sin `err` en absoluto: `callback(result)`, podemos promisificarlos manualmente sin usar el ayudante.
109
123
110
124
También hay módulos con funciones de promisificación un poco más flexibles, ej. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). En Node.js, hay una función integrada `util.promisify` para ello.
111
125
112
126
```smart
113
-
La promisificación es un excelente enfoque, especialmente cuando usas `async/await` (revisa el siguiente capítulo), pero no es totalmente un substituto para los callbacks.
127
+
La promisificación es un excelente enfoque, especialmente cuando usas `async/await` (revisa el siguiente artículo), pero no es un substituto completo para los callbacks.
114
128
115
129
Recuerda, una promesa puede tener sólo un resultado, pero un callback puede ser técnicamente llamado muchas veces.
0 commit comments