1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
---
title: Promise.prototype.then()
slug: Web/JavaScript/Referencia/Objetos_globales/Promise/then
tags:
- ECMAScript 2015
- JavaScript
- Method
- Promise
- Prototype
translation_of: Web/JavaScript/Reference/Global_Objects/Promise/then
---
<div>{{JSRef}}</div>
<p>El método <code><strong>then()</strong></code> retorna una {{domxref("Promesa")}}. Recibe dos argumentos: funciones callback para los casos de éxito y fallo de <code><a href="/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise">Promise</a></code>.</p>
<p>Nota: Si ambos argumentos son omitidos, o se proveen métodos que no sean funciones, se creará una nueva <code>Promesa</code> sin handlers adicionales, que simplemente adoptan el estado final de la <code>Promesa</code> que entonces es llamado. Si el primer argumento es omitido o se provee una no-función, el nuevo <code>Promise</code> que es creado simplemente adopta el estado cumplido del <code>Promise</code> que entonces es llamado (si se convierte en fulfilled). Si el segundo argument es omitido o se provee una no-función, el nuevo <code>Promise</code> que es creado simplemente adopta el estado de rechazo del <code>Promesa</code> que entonces es llamado (si se convierte en rechazado).</p>
<h2 id="Sintaxis">Sintaxis</h2>
<pre class="syntaxbox notranslate"><var>p.then(alCumplir[, enRechazo])</var>;
p.then(function(value) {
// cumplimiento
}, function(reason) {
// rechazo
});
</pre>
<h3 id="Parámetros">Parámetros</h3>
<p>Retorna un <code>Promise</code> el cual es determinado por las funciones input:</p>
<ul>
<li>Si <font face="consolas, Liberation Mono, courier, monospace">alCumplir</font> o <code>enRechazo</code> arroja un error, o retorna un <code><a href="/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise">Promise</a></code> rechazado, <code>then</code> retorna un <code>Promise</code> rechazado.</li>
<li>Si <font face="consolas, Liberation Mono, courier, monospace">alCumplir</font> o <code>enRechazo</code> retorna un <code>Promise</code> que resuelve, o retorna cualquier otro valor, <code>then</code> retorna un <code>Promise </code>resuelto.</li>
</ul>
<dl>
<dt><font face="consolas, Liberation Mono, courier, monospace">alCumplir </font>{{optional_inline}}</dt>
<dd>Una <a href="es/docs/Web/JavaScript/Referencia/Objetos_globales/Function">Función</a> es llamada si la <code>Promesa</code> se cumple. Esta función tiene un argumento, el <code>valor de</code> cumplimiento. Si no es una función, se reemplaza internamente con una función de "Identidad" (devuelve el argumento recibido).</dd>
<dt><code>enRechazo</code> {{optional_inline}}</dt>
<dd>Una <a href="es/docs/Web/JavaScript/Referencia/Objetos_globales/Function">Función</a> es llamada si la <code>Promesa </code>es rechazada. Esta función tiene un argumento, la <code>razón</code> de rechazo. Si no es una función, se reemplaza internamente con una función "Lanzador" (lanza un error que recibió como argumento).</dd>
</dl>
<h3 id="Valor_de_retorno">Valor de retorno</h3>
<p>Un <code><a href="/es/docs/Web/JavaScript/Referencia/Objetos_globales/Promise">Promise</a></code> en estado <strong>pendiente.</strong> La función de control (<code>alCumplir o enRechazo)</code> es llamada de forma <strong>asíncrona</strong> (tan pronto como el stack se vacíe). Después de la invocación de la función de control pueden darse diferentes casos:</p>
<ul>
<li>Si se recibe un valor, la Promesa devuelta por el método <code>then</code> queda resuelta adoptando el valor de retorno.</li>
<li>Si se produce un error, la Promesa devuelta por el método <code>then</code> es rechazada, adoptando el error como su valor.</li>
<li>Si se devuelve una Promesa ya resuelta, la Promesa devuelta por el método <code>then</code> queda resuelta adoptando el valor de la promesa anterior.</li>
<li>Si se devuelve una Promesa con un objeto <strong>pendiente</strong> de resolver, la resolución o rechazo devueltos por <code>then</code> quedará a esperas de que la Promesa establecida para la función de control quede resuelta. Además, el valor de la Promesa en estado pendiente será el mismo que el valor devuelto por el controlador.</li>
</ul>
<p>Veamos un ejemplo para demostrar la asincronía del método <code>then</code>.</p>
<pre class="notranslate"><code>// al usar una promesa revuelta, el bloque 'then' se lanzará automáticamente,
// pero sus funciones controladoras se lanzarán asíncronamente,
// como demuestran los console.logs
var promResuelta = Promise.resolve(33);
var thenProm = promResuelta.then(función(valor){
console.log("ésto será invocado cuando acabe el stack principal. El valor recibido y devuelto es: " + valor);
return valor;
});
// imprimimos al momento el valor de thenProm()
console.log(thenProm);
// usando setTimeout podemos posponer la ejecución de una función al momento en el que el stack quede vacío.
setTimeout(función(){
console.log(thenProm);
});
// logs, en orden:
// Promise {[[EstadoPromise¡]]: "pendiente", [[ValorPromise]]: undefined}
// "ésto será invocado cuando acabe el stack principal. El valor recibido y devuelto es: "33"
// Promise {[[EstadoPromise]]: "resuelta", [[ValorPromise]]: 33}</code></pre>
<h2 id="Descripción">Descripción</h2>
<p>Ya que los métodos <code>then</code> y {{jsxref("Promise.prototype.catch()")}} devuelven promesas, pueden ser encadenados — una operación llamada <em>composición</em>.</p>
<h2 id="Ejemplos">Ejemplos</h2>
<h3 id="Usando_el_metodo_then">Usando el metodo <code>then</code></h3>
<pre class="brush: js notranslate">var p1 = new Promise(function(resolve, reject) {
resolve('Success!');
// or
// reject ("Error!");
});
p1.then(function(value) {
console.log(value); // Success!
}, function(reason) {
console.log(reason); // Error!
});
</pre>
<h3 id="Encadenamiento">Encadenamiento</h3>
<p>El método <code>then</code> devuelve una <code>Promise</code> que permite encadenar métodos.</p>
<p>Puedes pasar una lambda a <code>then</code> y si devuelve una promesa, una <code>Promise</code> equivalente será expuesta al <code>then</code> subsecuente en la cadena de métodos. El fragmento incluido debajo simula un código asíncrono mediante la función <code>setTimeout</code>. </p>
<pre class="brush: js notranslate">Promise.resolve('foo')
// 1. Recibe "foo", concatena "bar" con él, y resuelve la cadena con el siguiente 'then'
.then(función(hilo) {
return new Promise(function(resolve, reject) {
setTimeout(función() {
hilo += 'bar';
resolve(hilo);
}, 1);
});
})
// 2. recibe "foobar", registra una función de llamada para opear sobre ese hilo
// e imprimirlo en la consola, pero no antes de devolver el hilo sin modificar
// en la resolución del siguiente 'then'
.then(función(hilo) {
setTimeout(función() {
hilo += 'baz';
console.log(hilo);
}, 1)
return hilo;
})
// 3. imprime mensajes útiles sobre cómo funcionará el código en esta sección
// antes de que el hilo se procese por el código de prueba
// antes del bloque 'then'.
.then(función(hilo) {
console.log("Último Then: oops... no me he molestado en instanciar y devolver " +
"una promesa en el then anterior, así que la secuencia puede ser un poco " +
"sorprendente");
// Observemos que `string` no incluye el trozo 'baz' en éste punto. Ésto ocurre
// porque lo hemos contruido para que ocurra asíncronamente con una función setTimeout
console.log(hilo);
});</pre>
<p>Cuando un valor sencillamente se devuelve desde un lambda <code>then</code> , devolverá un <code>Promise.resolve(<valor devuelto por el controlador que haya sido invocado>)</code>.</p>
<pre class="brush: js notranslate">var p2 = nueva Promise(function(resolver, rechazar) {
resolver(1);
});
p2.then(función(valor) {
console.log(valor); // 1
return valor + 1;
}).then(function(value) {
console.log(valor + '- Este uso síncrono es prácticamente inútil'); // 2- Este uso síncrono es prácticamente inútil
});
p2.then(función(valor) {
console.log(valor); // 1
});
</pre>
<p>Una llamada a <code>then</code> devolverá una promesa rechazada si la función lanza un error o devuelve una Promise rechazada.</p>
<pre class="brush: js notranslate">Promise.resolve()
.then( () => {
// Hace que .then() devuelva una promera rechazada
throw new Error('Oh no!');
})
.then( () => {
console.log( 'No invocada.' );
}, error => {
console.error( 'Función de rechazo llamada: ', error );
});</pre>
<p>En cualquier otro caso, una Promise en resolución será devuelta. El el siguiente ejemplo, el primer <code>then()</code> devolverá un <code>42</code> dentro de una Promise en resolución, aunque la Promise de la cadena fue rechazada.</p>
<pre class="brush: js notranslate">Promise.reject()
.then( () => 99, () => 42 ) // enRechazo devuelve 42, que está dentro de una Promise en resolución
.then( respuesta => console.log( 'Resuelta con ' + respuesta ) ); // Resuelta con 42</pre>
<p>En la práctica, suele ser preferible capturar promesas rechazadas en lugar de utilizar la sintaxis de dos casos de <code>then,</code> como demostramos abajo.</p>
<pre class="brush: js notranslate">Promise.resolve()
.then( () => {
// Hace que .then() devuelva una promesa rechazada
throw new Error('Oh no!');
})
.catch( error => {
console.error( 'función enRechazo invocada: ', error );
})
.then( () => {
console.log( "Siempre soy invocada, incluso si la promesa del then previo es rechazada" );
});</pre>
<p><br>
También puedes usar encadenamiento para implementar una función con una API basada en promesas, sobre una función del mismo tipo.</p>
<pre class="brush: js notranslate">function traer_datos_actuales() {
// La función <a href="/en-US/docs/Web/API/GlobalFetch/fetch">fetch</a>() de la API devuelve una Promesa. Esta función
// expone una API similar, pero el valor de cumplimiento
// de la Promesa de esta función tiene más tareas
// implementadas sobre ella.
return fetch('datos_actuales.json').then((response) => {
if (response.headers.get('content-type') != 'application/json') {
throw new TypeError();
}
var j = response.json();
// podríamos hacer algo con j
return j; // valor de cumplimiento asignado al usuario de
// fetch_datos_actuales().then()
});
}
</pre>
<p>Si <code>alCumplir</code> devuelve una promesa, el valor de retorno de <code>then</code> será resuelto o rechazado por la promesa.</p>
<pre class="brush: js notranslate">function resolverDespues(resolver, reject) {
setTimeout(función () {
resolver(10);
}, 1000);
}
function rechazarDespues(resolver, reject) {
setTimeout(function () {
resolver(new Error('Error'));
}, 1000);
}
var p1 = Promise.resolve('foo');
var p2 = p1.then(función() {
// Devuelve la promesa aquí, que será resuelta igualada a 10 tras 1 segundo
return new Promise(resolverDespues);
});
p2.then(función(v) {
console.log('resuelta', v); // "resuelta", 10
}, función(e) {
// no invocada
console.log('rechazada', e);
});
var p3 = p1.then(funcion() {
// Devuelve la promesa aquí, que será rechazada con 'Error' despues de 1 segundo
return new Promise(rechazarDespues);
});
p3.then(funcion(v) {
// no invocada
console.log('resuelta', v);
}, funcion(e) {
console.log('rechazada', e); // "rechazada", 'Error'
});
</pre>
<h3 id="window.setImmediate_estilo_polyfill_basado_en_promesas"><a href="https://wiki.developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate" title="This method is used to break up long running operations and run a callback function immediately after the browser has completed other operations such as events and display updates."><code>window.setImmediate</code></a> estilo polyfill basado en promesas</h3>
<p>Usar un método {{jsxref("Function.prototype.bind()")}}<code>Reflect.apply</code> ({{jsxref("Reflect.apply()")}}) para crear un (non-cancellable) setImmediate-style function.</p>
<pre class="notranslate">const nextTick = (() => {
const noop = () => {}; // literally
const nextTickPromise = () => Promise.resolve().then(noop);
const rfab = Reflect.apply.bind; // (thisArg, fn, thisArg, [...args])
const nextTick = (fn, ...args) => (
fn !== undefined
? Promise.resolve(args).then(rfab(null, fn, null))
: nextTickPromise(),
undefined
);
nextTick.ntp = nextTickPromise;
return nextTick;
})();</pre>
<h2 id="Especificaciones">Especificaciones</h2>
<table class="standard-table">
<tbody>
<tr>
<th scope="col">Especificación</th>
<th scope="col">Estado</th>
<th scope="col">Comentario</th>
</tr>
<tr>
<td>{{SpecName('ES2015', '#sec-promise.prototype.then', 'Promise.prototype.then')}}</td>
<td>{{Spec2('ES2015')}}</td>
<td>Definición inicial en el estándar ECMA.</td>
</tr>
<tr>
<td>{{SpecName('ESDraft', '#sec-promise.prototype.then', 'Promise.prototype.then')}}</td>
<td>{{Spec2('ESDraft')}}</td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="Compatibilidad_en_navegador">Compatibilidad en navegador</h2>
<p class="hidden">Para contribuir a la compatibilidad de estos datos, realiza una pull request sobre éste archivo: <a href="https://github.com/mdn/browser-compat-data/blob/master/javascript/promise.json">https://github.com/mdn/browser-compat-data/blob/master/javascript/promise.json</a>.</p>
<p>{{Compat("javascript/promise","Promise.prototype.then")}}</p>
<h2 id="Ver_también">Ver también</h2>
<ul>
<li>{{jsxref("Promise")}}</li>
<li>{{jsxref("Promise.prototype.catch()")}}</li>
</ul>
|