Usando las promesas de ES6, ¿cómo creo una promesa sin definir la lógica para resolverla? Aquí hay un ejemplo básico (algo de TypeScript):
var promises = {}; function waitFor(key: string): Promise<any> { if (key in promises) { return promises[key]; } var promise = new Promise(resolve => { // But I don't want to try resolving anything here :( }); promises[key] = promise; return promise; } function resolveWith(key: string, value: any): void { promises[key].resolve(value); // Not valid :( }Se hace fácilmente con otras bibliotecas prometedoras. JQuery por ejemplo:
var deferreds = {}; function waitFor(key: string): Promise<any> { if (key in promises) { return deferreds[key].promise(); } var def = $.Deferred(); deferreds[key] = def; return def.promise(); } function resolveWith(key: string, value: any): void { deferreds[key].resolve(value); }La única forma que veo de hacer esto sería almacenar la función de resolución en algún lugar dentro del ejecutor de la promesa, pero eso parece complicado, y no estoy seguro de que esté definido exactamente cuando se ejecuta esta función. ¿Siempre se ejecuta inmediatamente en la construcción?
Gracias.
¡Buena pregunta!
El resolutor pasado al constructor de la promesa se ejecuta intencionalmente de forma síncrona para admitir este caso de uso:
var deferreds = []; var p = new Promise(function(resolve, reject){ deferreds.push({resolve: resolve, reject: reject}); });Luego, en algún momento posterior en el tiempo:
deferreds[0].resolve("Hello"); // resolve the promise with "Hello"La razón por la que se da el constructor de la promesa es que:
A veces no encaja y por eso el resolver se ejecuta sincrónicamente. Aquí hay lecturas relacionadas sobre el tema .
Quiero agregar mis 2 centavos aquí. Teniendo en cuenta exactamente la pregunta " Crear una promesa es6 sin comenzar a resolverla ", la resolví creando una función contenedora y llamando a la función contenedora en su lugar. Código:
Digamos que tenemos una función f que devuelve una Promesa
/** @return Promise<any> */ function f(args) { return new Promise(....) } // calling f() f('hello', 42).then((response) => { ... }) Ahora, quiero preparar una llamada a f('hello', 42) sin resolverla realmente:
const task = () => f('hello', 42) // not calling it actually // later task().then((response) => { ... })Espero que esto ayude a alguien :)
Haciendo referencia Promise.all() como se preguntó en los comentarios (y respondido por @Joe Frambach), si quiero preparar una llamada a f1('super') & f2('rainbow') , 2 funciones que devuelven promesas
const f1 = args => new Promise( ... ) const f2 = args => new Promise( ... ) const tasks = [ () => f1('super'), () => f2('rainbow') ] // later Promise.all(tasks.map(t => t())) .then(resolvedValues => { ... })¿Qué tal un enfoque más completo?
Podrías escribir un Constructor que devuelva una nueva Promesa decorada con .resolve() y .reject() .
Probablemente elegiría nombrar al constructor Deferred , un término con mucha precedencia en [la historia de] las promesas de JavaScript.
function Deferred(fn) { fn = fn || function(){}; var resolve_, reject_; var promise = new Promise(function(resolve, reject) { resolve_ = resolve; reject_ = reject; fn(resolve, reject); }); promise.resolve = function(val) { (val === undefined) ? resolve_() : resolve_(val); return promise;//for chainability } promise.reject = function(reason) { (reason === undefined) ? reject_() : reject_(reason); return promise;//for chainability } promise.promise = function() { return promise.then(); //to derive an undecorated promise (expensive but simple). } return promise; }Al devolver una promesa decorada en lugar de un objeto simple, todos los métodos/propiedades naturales de la promesa permanecen disponibles además de las decoraciones.
Además, al manejar fn , el patrón revelador permanece disponible, en caso de que necesite/decida usarlo en un diferido.
Ahora, con la utilidad Deferred() en su lugar, su código es prácticamente idéntico al ejemplo de jQuery.
var deferreds = {}; function waitFor(key: string): Promise<any> { if (key in promises) { return deferreds[key].promise(); } var def = Deferred(); deferreds[key] = def; return def.promise(); }