Подтвердить что ты не робот

Создание обещания (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);
}

Единственный способ, с помощью которого я могу это сделать, - сохранить функцию разрешения где-то внутри исполнителя обещаний, но это кажется беспорядочным, и я не уверен, что он определен, когда именно эта функция запускается - всегда ли она выполняется немедленно по строительству?

Спасибо.

4b9b3361

Ответ 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();
}