Spec-Zone.ru › Q

Q

Методы Promise

Большинство методов обещаний имеют «статические» аналоги в основном объекте Q, которые принимают либо обещание, либо не обещание, и в последнем случае сначала создают выполненное обещание. Например, Q.when(5, onFulfilled) эквивалентно Q(5).then(onFulfilled). Все остальные имеют статические аналоги, которые названы так же, как метод обещания.

Некоторые методы имеют названия, совпадающие с зарезервированными словами JavaScript, например, try, catch, и finally. Это помогает продемонстрировать явное сходство между стандартными синхронными языковыми конструкциями и асинхронными операциями с обещаниями. Однако такое использование слов в качестве имён свойств поддерживается только начиная с версии ECMAScript 5 языка JavaScript, которая не реализована в некоторых старых браузерах, таких как IE8, Safari 5, Android 2.2 или PhantomJS 1.8. Если вы нацеливаетесь на эти браузеры и не используете язык, подобный CoffeeScript, который позаботится об этом за вас, используйте их псевдонимы или экранируйте их, как Q["try"](...) или promise["catch"](...).

Основные методы Promise

promise.then(onFulfilled, onRejected, onProgress)

Метод then из спецификации Promises/A+ с дополнительным обработчиком прогресса.

promise.catch(onRejected)

Псевдоним: promise.fail (для браузеров, не поддерживающих ES5)

Метод-упрощение, эквивалентный promise.then(undefined, onRejected).

promise.progress(onProgress)

Устаревший: promise.observeEstimate или подобный интерфейс должен заменить этот метод в версии 2. Прогресс не работает хорошо. https://github.com/kriskowal/gtor#progress-and-estimated-time-to-completion

Метод-упрощение, эквивалентный promise.then(undefined, undefined, onProgress). Обработчик onProgress получает значения, отправленные этому обещанию либо методом notify соответствующего отложенного объекта, либо из обещания, которым это обещание стало благодаря возвращению из обработчика.

promise.finally(callback)

Псевдоним: promise.fin (для браузеров, не поддерживающих ES5)

Подобно блоку finally, позволяет наблюдать за выполнением или отклонением обещания, но без изменения конечного значения. Это полезно для сбора ресурсов независимо от того, выполнена ли задача, например, для закрытия подключения к базе данных, остановки сервера или удаления ненужного ключа из объекта.

finally возвращает обещание, которое будет выполнено с тем же значением выполнения или причиной отклонения, что и promise. Однако, если callback возвращает обещание, выполнение возвращенного обещания будет отложено до завершения обещания, возвращенного callback. Кроме того, если возвращенное обещание отклоняется, это отклонение будет передано дальше по цепочке вместо предыдущего результата.

promise.done(onFulfilled, onRejected, onProgress)

Подобно then, но с другим поведением относительно необработанных отклонений. Если произойдет необработанное отклонение, либо потому, что promise отклонено и не был предоставлен обработчик onRejected, либо потому, что onFulfilled или onRejected выбросили ошибку или вернули отклоненное обещание, причина возникшего отклонения будет выброшена в качестве исключения в будущий цикл обработки событий.

Этот метод следует использовать для завершения цепочек обещаний, которые не будут переданы дальше. Поскольку исключения, выброшенные в обработчиках then обработчиках, потребляются и преобразуются в отклонения, исключения в конце цепочки легко случайно и незаметно игнорируются. Организуя выброс исключения в будущий цикл обработки событий, чтобы его не перехватывать, вы вызываете событие onerror в браузере window или событие uncaughtException в объекте process Node.js.

Исключения, выброшенные done будут иметь длинные стеки вызовов, если Q.longStackSupport установлено в true. Если Q.onerror установлено, исключения будут доставлены туда вместо выброса в будущий цикл.

Золотое правило использования done против then заключается в том: либо передайте ваше обещание кому-то другому, либо, если цепочка заканчивается на вас, вызовите done для ее завершения. Завершение с catch недостаточно, потому что обработчик catch сам может выбросить ошибку.

Методы Promise для объектов

promise.get(propertyName)

Возвращает обещание для получения указанного свойства объекта. По существу эквивалентно

promise.then(function (o) {
  return o[propertyName];
});

promise.post(methodName, args)

Экспериментальный псевдоним: promise.mapply

Возвращает обещание для результата вызова указанного метода объекта с заданным массивом аргументов. Сам объект this в функции, как и при синхронном вызове метода. По существу эквивалентно

promise.then(function (o) {
  return o[methodName].apply(o, args);
});

promise.invoke(methodName, ...args)

Псевдоним: promise.send

Экспериментальный псевдоним: promise.mcall

Возвращает обещание для результата вызова указанного метода объекта с заданными аргументами. Сам объект this в функции, как и при синхронном вызове метода.

promise.keys()

Возвращает обещание для массива имён свойств объекта. По существу эквивалентно

promise.then(function (o) {
  return Object.keys(o);
});

Методы Promise для функций

promise.fbind(...args) (устарело)

Возвращает новую функцию, которая асинхронно вызывает функцию с заданными аргументами и возвращает обещание. Отметим, что любые синхронные возвращаемые значения или выброшенные исключения соответственно преобразуются в значения выполнения или причины отклонения для возвращаемого обещания этой новой функцией.

Этот метод особенно полезен в своей статической форме для обертывания функций, чтобы гарантировать, что они всегда асинхронны, и что любые выброшенные исключения (умышленные или случайные) должным образом преобразуются в возвращаемое отклоненное обещание. Например:

var getUserData = Q.fbind(function (userName) {
  if (!userName) {
    throw new Error("userName must be truthy!");
  }

  if (localCache.has(userName)) {
    return localCache.get(userName);
  }

  return getUserFromCloud(userName);
});

promise.fapply(args)

Возвращает обещание для результата вызова функции с заданным массивом аргументов. По существу эквивалентно

promise.then(function (f) {
  return f.apply(undefined, args);
});

Обратите внимание, что это приведет к тому же преобразованию возвращаемых значений/выброшенных исключений, что и для fbind.

promise.fcall(...args)

Статический псевдоним: Q.try (только для браузеров ES5)

Возвращает обещание для результата вызова функции с заданными аргументами. Имеет то же преобразование возвращаемых значений/выброшенных исключений, что и описано выше для fbind.

В своей статической форме он имеет псевдоним Q.try, поскольку он имеет семантику, аналогичную блоку try (но обрабатывает как синхронные исключения, так и асинхронные отклонения). Это позволяет писать код, такой как

Q
.try(function () {
  if (!isConnectedToCloud()) {
    throw new Error("The cloud is down!");
  }

  return syncToCloud();
})
.catch(function (error) {
  console.error("Couldn't sync to the cloud", error);
});

Методы Promise для массивов

promise.all()

Возвращает обещание, которое выполняется с массивом, содержащим значения выполнения каждого обещания, или отклоняется с той же причиной отклонения, что и первое отклоненное обещание.

Этот метод часто используется в своей статической форме с массивами обещаний для одновременного выполнения ряда операций и получения уведомления, когда все они завершатся успешно. Например:

Q.all([getFromDisk(), getFromCloud()]).done(function (values) {
  assert(values[0] === values[1]); // values[0] is fromDisk and values[1] is fromCloud
});

promise.allSettled()

Возвращает обещание, которое выполняется с массивом снимков состояния обещаний, но только после того, как все исходные обещания завершатся, т. е. станут выполненными или отклоненными.

Этот метод часто используется в своей статической форме с массивами обещаний для одновременного выполнения ряда операций и получения уведомления о завершении всех них, независимо от успеха или неудачи. Например:

Q.allSettled([saveToDisk(), saveToCloud()]).spread(function (disk, cloud) {
  console.log("saved to disk:", disk.state === "fulfilled");
  console.log("saved to cloud:", cloud.state === "fulfilled");
}).done();

Снимки состояния будут иметь тот же формат, что и те, которые получены через promise.inspect, т. е. либо { state: "fulfilled", value: v } или { state: "rejected", reason: r }.

promise.spread(onFulfilled, onRejected)

Подобно then, но «распределяет» массив в многоаргументный обработчик выполнения. Если любое из обещаний в массиве отклонено, вместо этого вызывает onRejected с причиной отклонения первого отклоненного обещания.

Это особенно полезно в сочетании с all, например:

Q.all([getFromDisk(), getFromCloud()]).spread(function (diskVal, cloudVal) {
  assert(diskVal === cloudVal);
}).done();

Вспомогательные методы

promise.thenResolve(value)

Нет статического аналога

Метод-упрощение, эквивалентный promise.then(function () { return value; }).

promise.thenReject(reason)

Нет статического аналога

Метод-упрощение, эквивалентный promise.then(function () { throw reason; }).

promise.tap(onFulfilled)

Введено в версии 1.1.0 (ноябрь 2014 г.)

Прикрепляет обработчик, который будет наблюдать за значением обещания, когда оно выполнится, возвращая обещание для того же значения, возможно, отложенное, но не замещаемое обещанием, возвращенным обработчиком onFulfilled.

Q("Hello, World!")
.delay(1000)
.tap(console.log)
.then(function (message) {
  expect(message).toBe("Hello, World!");
})

promise.timeout(ms, message)

Возвращает обещание, которое будет иметь тот же результат, что и promise, за исключением того, что если promise не выполнится или не отклонится до истечения ms миллисекунд, возвращаемое обещание будет отклонено с Error сообщением message. Если message не предоставлено, сообщение будет "Timed out after " + ms + " ms".

promise.timeout(10000).then(
  function (result) {
  // will be called if the promise resolves normally
  console.log(result);
  },
  function (err) {
  // will be called if the promise is rejected, or the 10 second timeout occurs
  console.log(err);
  }
);

promise.delay(ms)

Возвращает обещание, которое будет иметь тот же результат, что и promise, но выполнится только после того, как пройдёт не менее ms миллисекунд. Если promise отклонено, возвращаемое обещание будет отклонено немедленно.

Q.delay(ms)

Если статическая версия Q.delay получает только один аргумент, она возвращает обещание, которое будет выполнено со значением undefined после того, как пройдёт не менее ms миллисекунд. (Если вызывается с двумя аргументами, используется обычное преобразование статического аналога, т. е. Q.delay(value, ms) эквивалентно Q(value).delay(ms).)

Это удобный способ вставить задержку в цепочку обещаний или даже просто получить более удобочитаемый синтаксис для setTimeout:

Q.delay(150).then(doSomething);

Методы проверки состояния

promise.isFulfilled()

Возвращает, находится ли данное обещание в состоянии выполнения. При использовании статической версии на не-обещаниях результат всегда true.

promise.isRejected()

Возвращает значение, указывающее, находится ли заданная promise в состоянии отклонения. При использовании статической версии на не-promise, результат всегда false.

promise.isPending()

Возвращает значение, указывающее, находится ли заданная promise в состоянии ожидания. При использовании статической версии на не-promise, результат всегда false.

promise.inspect()

Возвращает объект "снимок состояния", который будет иметь одну из трех форм:

  • { state: "pending" }
  • { state: "fulfilled", value: <fulfllment value> }
  • { state: "rejected", reason: <rejection reason> }

Создание Promise

Q.defer()

Возвращает объект "отложенный" с:

  • свойством promise
  • методом resolve(value)
  • методом reject(reason)
  • методом notify(value)
  • методом makeNodeResolver()

Методы resolve и reject управляют состоянием свойства promise, которое вы можете передавать другим, сохраняя за собой право изменять его состояние. Метод notify предназначен для уведомлений о прогрессе, а метод makeNodeResolver предназначен для взаимодействия с Node.js (см. ниже).

Во всех случаях, когда promise разрешен (т.е. выполнен или отклонен), разрешение является постоянным и не может быть сброшено. Попытка вызвать resolve, reject, или notify в случае, если promise уже разрешен, приведет к неоперации.

Отложенные объекты полезны, потому что они отделяют часть promise от части решающего. Таким образом:

  • Вы можете передать promise любому количеству потребителей, и все они будут наблюдать за разрешением независимо. Поскольку возможность наблюдать за promise отделена от возможности разрешения promise, ни один из получателей promise не имеет возможности "обмануть" других получателей ложной информацией (или, в самом деле, каким-либо образом повлиять на них).

  • Вы можете передать решающее любому количеству производителей, и тот, кто первым разрешит promise, выиграет. Кроме того, ни один из производителей не сможет увидеть, что они проиграли, если вы не дадите им и часть promise.

deferred.resolve(value)

Вызов resolve с ожидающей promise вызывает promise ожидать переданную promise, становясь выполненным с ее значением выполнения или отклоненным с причиной ее отклонения (или оставаясь ожидающим вечно, если переданная promise).

Вызов resolve с отклоненной promise вызывает promise быть отклоненным с причиной отклонения переданной promise.

Вызов resolve с выполненной promise вызывает promise быть выполненным со значением выполнения переданной promise.

Вызов resolve с не-promise значением вызывает promise быть выполненным с этим значением.

deferred.reject(reason)

Вызов reject с причиной вызывает promise быть отклоненным с этой причиной.

deferred.notify(value)

Вызов notify со значением вызывает promise быть уведомленным о прогрессе со значением. То есть, любые обработчики onProgress регистрации с promise или производные от promise promise будут вызваны со значением прогресса.

Q объект

Q(value)

Если value является Q promise, возвращает promise.

Если value является promise из другой библиотеки, она преобразуется в Q promise (если это возможно).

Если value не является promise, возвращает promise, которая выполнена со значением value.

Q.reject(reason)

Возвращает promise, которая отклонена со значением reason.

Q.Promise(resolver)

Синхронно вызывает resolver(resolve, reject, notify) и возвращает promise, состояние которой контролируется функциями, переданными resolver. Это альтернативный API для создания promise, обладающий той же мощью, что и концепция deferred, но без введения другого концептуального сущности.

Если resolver вызывает исключение, возвращаемая promise будет отклонена с этим исключением как причиной отклонения.

примечание: В последней версии github этот метод называется Q.Promise, но если вы используете версию npm пакета 0.9.7 или ниже, метод называется Q.promise (строчная vs прописная буква p).

Взаимодействие с Node.js обратными вызовами

Q предоставляет ряд функций для взаимодействия с Node.js стильными (err, result) обратными вызовами API.

Некоторые из них обычно используются в своей статической форме, и поэтому они перечислены здесь как таковые. Тем не менее, они также существуют на каждом Q promise, на случай, если у вас есть promise для функции Node.js-стиля или для объекта с методами Node.js-стиля.

Обратите внимание, что если Node.js-стильный API вызывает обратный вызов с более чем одним параметром, не являющимся ошибкой (например, child_process.execFile), Q упаковывает эти параметры в массив в качестве значения выполнения promise при выполнении преобразования.

Q.nfbind(nodeFunc, ...args)

Псевдоним: Q.denodeify

Создает функцию, возвращающую promise, из функции Node.js-стиля, необязательно привязывая ее к заданным аргументам с вариациями. Пример:

var readFile = Q.nfbind(FS.readFile);

readFile("foo.txt", "utf-8").done(function (text) {

});

Обратите внимание, что если у вас есть метод, использующий шаблон обратного вызова Node.js, а не просто функцию, вам нужно будет привязать его значение this перед передачей его nfbind, как показано ниже:

var Kitty = mongoose.model("Kitty");
var findKitties = Q.nfbind(Kitty.find.bind(Kitty));

Лучшей стратегией для методов было бы использовать Q.nbind, как показано ниже.

Q.nbind(nodeMethod, thisArg, ...args)

Создает функцию, возвращающую promise, из метода Node.js-стиля, необязательно привязывая ее к заданным аргументам с вариациями. Пример:

var Kitty = mongoose.model("Kitty");
var findKitties = Q.nbind(Kitty.find, Kitty);

findKitties({ cute: true }).done(function (theKitties) {

});

Q.nfapply(nodeFunc, args)

Вызывает функцию Node.js-стиля с заданным массивом аргументов, возвращая promise, который выполнен, если функция Node.js вызывает обратный вызов с результатом, или отклонен, если она вызывает обратный вызов с ошибкой (или вызывает ее синхронно). Пример:

Q.nfapply(FS.readFile, ["foo.txt", "utf-8"]).done(function (text) {
});

Обратите внимание, что этот пример работает только потому, что FS.readFile является функцией, экспортированной из модуля, а не методом объекта. Для методов, например, redisClient.get, вы должны привязать метод к экземпляру перед передачей его Q.nfapply (или, как правило, в качестве аргумента любого вызова функции):

Q.nfapply(redisClient.get.bind(redisClient), ["user:1:id"]).done(function (user) {
});

Лучшей стратегией для методов было бы использовать Q.npost, как показано ниже.

Q.nfcall(func, ...args)

Вызывает функцию Node.js-стиля с заданными аргументами с вариациями, возвращая promise, который выполнен, если функция Node.js вызывает обратный вызов с результатом, или отклонен, если она вызывает обратный вызов с ошибкой (или вызывает ее синхронно). Пример:

Q.nfcall(FS.readFile, "foo.txt", "utf-8").done(function (text) {
});

То же предупреждение о функциях и методах применимо к nfcall так же, как и к nfapply. В этом случае лучшей стратегией было бы использование Q.ninvoke.

Q.npost(object, methodName, args)

Устаревший псевдоним: Q.nmapply

Вызывает метод Node.js-стиля с заданным массивом аргументов, возвращая promise, который выполнен, если метод вызывает обратный вызов с результатом, или отклонен, если он вызывает обратный вызов с ошибкой (или вызывает ее синхронно). Пример:

Q.npost(redisClient, "get", ["user:1:id"]).done(function (user) {
});

Q.ninvoke(object, methodName, ...args)

Псевдоним: Q.nsend

Устаревший псевдоним: Q.nmcall

Вызывает метод Node.js-стиля с заданными аргументами с вариациями, возвращая promise, который выполнен, если метод вызывает обратный вызов с результатом, или отклонен, если он вызывает обратный вызов с ошибкой (или вызывает ее синхронно). Пример:

Q.ninvoke(redisClient, "get", "user:1:id").done(function (user) {
});

promise.nodeify(callback)

Если callback является функцией, предполагает, что это обратный вызов Node.js-стиля, и вызывает его как callback(rejectionReason) в случае/при promise отклоняется, или как callback(null, fulfillmentValue) в случае/при promise выполняется. Если callback не является функцией, просто возвращает promise.

Этот метод полезен для создания двойных API promise/callback, т.е. API, которые возвращают promise, но также принимают обратные вызовы Node.js-стиля. Например:

function createUser(userName, userData, callback) {
  return database.ensureUserNameNotTaken(userName)
  .then(function () {
    return database.saveUserData(userName, userData);
  })
  .nodeify(callback);
}

deferred.makeNodeResolver()

Возвращает функцию, подходящую для передачи в Node.js API. То есть, она имеет подпись (err, result) и отклонит deferred.promise со значением err если err дано, или выполнит его со значением result если оно дано.

Генераторы

Эта функциональность экспериментальная.

Q.async(generatorFunction)

Это экспериментальный инструмент для преобразования генераторной функции в функцию deferred. Это имеет потенциал для уменьшения вложенных обратных вызовов в движках, которые поддерживают yield. См. пример генераторов для получения дополнительной информации.

Q.spawn(generatorFunction)

Это немедленно выполняет генераторную функцию и перенаправляет любые необработанные ошибки в Q.onerror. Необработанная ошибка считается произошедшей, если функция возвращает отклоненную promise. Обратите внимание, что это автоматически происходит, если генераторная функция вызывает исключение, например, путем yield на promise, которая отклоняется без окружающего этот код try/catch.

Q.spawn(function* () {
  // If `createUser` returns a rejected promise, the rejection reason will
  // reach `Q.onerror`.
  var user = yield createUser();
  showUserInUI(user);
});

Обработка и отслеживание ошибок

Q.onerror

Устанавливаемое свойство, которое перехватывает любые необработанные ошибки, которые в противном случае будут выброшены в следующем тике цикла событий, обычно в результате done. Может быть полезно для получения полного стека отслеживания ошибок в браузерах, что обычно невозможно с window.onerror.

Q.getUnhandledReasons()

Получает массив причин, принадлежащих отклоненным promise, которые в настоящее время не обработаны, т.е. для них не вызваны обработчики обратных вызовов onRejected, они не были подключены к цепочке и т. д. Как правило, они представляют потенциально "потерянные" ошибки, поэтому этот массив должен быть пустым, за исключением, возможно, тех случаев, когда вы передаете отклоненную promise асинхронно, чтобы кто-то мог обработать отклонение позже.

Q.stopUnhandledRejectionTracking()

Отключает отслеживание необработанных отклонений, что обеспечивает небольшое повышение эффективности, если вы не считаете эту информацию о дебаге полезной. Это также предотвращает вывод Q любых причин необработанных отклонений при выходе процесса в Node.js.

Q.resetUnhandledRejections()

Сбрасывает внутренний отслеживающий механизм Q для необработанных отклонений, но сохраняет отслеживание необработанных отклонений включенным. Этот метод в основном предназначен для тестирования и диагностики, когда у вас накопилось несколько необработанных отклонений, но вы хотите начать с чистого листа.

Другое

Q.isPromise(value)

Возвращает значение, указывает ли данное значение на обещание Q.

Q.isPromiseAlike(value)

Возвращает значение, указывает ли данное значение на обещание (т.е. это объект с then функцией).

Q.promised(func)

Создает новую версию func, которая принимает любое сочетание обещаний и значений, не являющихся обещаниями, преобразуя их в значения выполнения перед вызовом исходной func. Возвращаемая версия также всегда возвращает обещание: если func выполняет return или throw, то Q.promised(func) вернёт выполненное или отклоненное обещание соответственно.

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

Q.longStackSupport

Настраиваемое свойство, которое позволяет включить поддержку длинных стеков вызовов. При включении «скачки стека» будут отслеживаться в асинхронных операциях с обещаниями, поэтому, если исключение без обработки бросает done или свойство stack причины отклонения проверяется в обработчике отклонения, генерируется длинный стек вызовов.

API пользовательского обмена сообщениями (расширенный)

Конструктор обещания Q устанавливает базовый API для выполнения операций над объектами: «get», «put», «del», «post», «apply» и «keys». Этот набор «операторов» можно расширить, создавая обещания, которые реагируют на сообщения с другими именами операторов, и отправляя соответствующие сообщения этим обещаниям.

promise.dispatch(operator, args)

Отправляет произвольное сообщение обещанию с указанным массивом аргументов.

Следует соблюдать осторожность, чтобы не создавать рисков нарушения потока выполнения и проблем безопасности при пересылке сообщений обещаниям. Функции выше, особенно then, тщательно разработаны для предотвращения сбоя инвариантов, например, не применять обратные вызовы несколько раз или в одном цикле обработки событий.

© 2009–2017 Kristopher Michael Kowal
Licensed under the MIT License.
https://github.com/kriskowal/q/wiki/API-Reference

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API