Создание обещания (ES6) без его разрешения
Используя ES6 promises, как мне создать обещание без определения логики его решения? Вот базовый пример (некоторые 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 :(
}
Это легко сделать с другими библиотеками обещаний. Например, 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();
}
function resolveWith(key: string, value: any): void {
deferreds[key].resolve(value);
}
Единственный способ, с помощью которого я могу это сделать, - сохранить функцию разрешения где-то внутри исполнителя обещаний, но это кажется беспорядочным, и я не уверен, что он определен, когда именно эта функция запускается - всегда ли она выполняется немедленно по строительству?
Спасибо.
Ответы
Ответ 1
Хороший вопрос!
Преобразователь, переданный конструктору обещаний, намеренно работает синхронно, чтобы поддерживать этот прецедент:
var deferreds = [];
var p = new Promise(function(resolve, reject){
deferreds.push({resolve: resolve, reject: reject});
});
Затем, в некоторый более поздний момент времени:
deferreds[0].resolve("Hello"); // resolve the promise with "Hello"
Причина, по которой дается конструктор обещаний, заключается в следующем:
- Обычно (но не всегда) логика разрешения привязана к созданию.
- Конструктор обещаний является безопасным и преобразует исключения в отклонения.
Иногда это не подходит, и для этого он работает синхронно. Вот связанное чтение по теме.
Ответ 2
Я хочу добавить свои 2 цента здесь. Учитывая именно вопрос " Создание обещания es6 без его разрешения ", я решил создать функцию-оболочку и вместо этого вызвать функцию-оболочку. Код:
Пусть говорят, что у нас есть функция f
которая возвращает Promise
/** @return Promise<any> */
function f(args) {
return new Promise(....)
}
// calling f()
f('hello', 42).then((response) => { ... })
Теперь я хочу подготовить звонок к f('hello', 42)
не решив его:
const task = () => f('hello', 42) // not calling it actually
// later
task().then((response) => { ... })
Надеюсь, это поможет кому-то :)
Promise.all()
как указано в комментариях (и ответил @Joe Frambach), если я хочу подготовить вызов к f1('super')
& f2('rainbow')
- 2 функции, которые возвращают обещания -
function f1(args) {
return new Promise( ... )
}
function f2(args) {
return new Promise( ... )
}
const tasks = [
() => f1('super'),
() => f2('rainbow')
]
// later
Promise.all(tasks)
.then(() => { ... })
Ответ 3
Как насчет более комплексного подхода?
Вы можете написать конструктор, который возвращает новое обещание, украшенное методами .resolve()
и .reject()
.
Вероятно, вы захотите назвать конструктор Deferred
- термин с большим преимуществом в [истории] javascript promises.
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;
}
Возвращая украшенный промси, а не простой объект, все обещающие естественные методы/свойства остаются доступными в дополнение к украшениям.
Кроме того, при обработке fn
шаблон обнаружения остается доступным, если вам нужно/выбрать его использовать в режиме отложенного.
DEMO
Теперь с помощью утилиты Deferred()
ваш код практически идентичен примеру 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();
}