На данной странице попробую коротко рассказать про часто-используемые подходы в современном JS.
Заранее, протестировать можно тут »
var promise = new Promise(function(resolve, reject) {
// Это тело promise-а, в нем можно делать любые операции,
// и когда они завершатся — нужно вызвать одну из функций:
let date = new Date('December 25, 1995 11:00:00');
if (date.getHours() > 10) {
resolve('данный текст будет передан первым аргументом в метод then')
} else {
reject('данный текст будет передан вторым аргументом в метод then');
}
throw new Error("тоже самое что reject, а в качестве результата будет данный объект Error");
});
// как видим then принимая аргументы пробрасывает значения в анонимные функции
promise.then(
// сработает только если в promise-е будет вызвана функция resolve
result => {
alert("resolve: " + result);
},
// сработает только если в promise-е будет вызвана функция reject
error => {
alert("reject: " + error);
}
);После вызова промиса он уже не может «передумать», когда промис переходит в состояние «выполнен» – с результатом (resolve) или ошибкой (reject) – это навсегда.
Можно игнорировать любой вариант работы промиса, например:
promise.then(myResolveFunc); // игнорируем reject
promise.then(null, myRejectFunc); // игнорируем resolve
promise.catch(myRejectFunc); // игнорируем resolve (подобно строчки выше)
promise.then(myResolveFunc).then(null, myRejectFunc).catch(myRejectFunc); // можно совмещатьПромисификация – это когда берут асинхронную функциональность и делают для неё обёртку, возвращающую промис.
Чейнинг – последовательный вызов promise.then(...) .then(...) .then(...).catch(...).catch(...)
Если очередной then вернул какой-то промис Х, то далее по then-цепочке будет передан результат работы промиса Х.
Согласно стандарту, у объекта new Promise(executor) при создании есть четыре внутренних свойства:
PromiseState – состояние, вначале «pending».PromiseResult – результат, при создании значения нет.PromiseFulfillReactions – список функций-обработчиков успешного выполнения.PromiseRejectReactions – список функций-обработчиков ошибки.Для параллельной обработки нескольких промисов используется метод all:
Promise.all([
promise1,
promise2
]).then(results => {
alert(results);
});Если какой-то из промисов завершился с ошибкой, то результатом Promise.all будет эта ошибка. При этом остальные промисы игнорируются.
Если нужно успешно обработать хотя бы один промис, используют метод race:
Promise.race([
promise1,
promise2
]).then(firstSuccesResult => {
alert(firstSuccesResult);
});Ключевое слово async перед объявлением функции:
resolve-ит undefined).await в теле этой функции (при попытке использовать await без async возникнет ошибка).Ключевое слово await перед промисом заставит JavaScript дождаться его выполнения, после чего:
throw.async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("готово!"), 1000)
});
let result = await promise; // JS будет ждать, пока промис не выполнится (1 sec)
alert(result); // "готово!"
}
f();3. await нельзя использовать в обычных функциях
function f() {
let promise = Promise.resolve(1);
let result = await promise; // SyntaxError
}Ошибки не будет, если мы укажем ключевое слово async перед объявлением функции.
4. await нельзя использовать на верхнем уровне вложенности
Программисты, узнав об await, часто пытаются использовать эту возможность на верхнем уровне вложенности (вне тела функции). Но из-за того, что await работает только внутри async–функций, так сделать не получится:
// SyntaxError на верхнем уровне вложенности
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();Можно обернуть этот код в анонимную async–функцию, тогда всё заработает:
(async () => {
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
...
})();но зачем так делать?
5. await работает с «thenable»–объектами
Как и promise.then, await позволяет работать с промис–совместимыми объектами. Идея в том, что если у объекта можно вызвать метод then, этого достаточно, чтобы использовать его с await.
class Thenable {
constructor(num) {
this.num = num;
}
then(resolve, reject) {
alert(resolve);
// выполнить resolve со значением this.num * 2 через 1000мс
setTimeout(() => resolve(this.num * 2), 1000); // (*)
}
};
async function f() {
// код будет ждать 1 секунду,
// после чего значение result станет равным 2
let result = await new Thenable(1);
alert(result);
}
f();Когда await получает объект с .then, не являющийся промисом, JavaScript автоматически запускает этот метод, передавая ему аргументы – встроенные функции resolve и reject. Затем await приостановит дальнейшее выполнение кода, пока любая из этих функций не будет вызвана (в примере это строка (*)). После чего выполнение кода продолжится с результатом resolve или reject соответственно.
Простая реализация через кэлбэк функцию:
export interface MyInterface {
readonly title: string;
readonly url: string;
}
type CallBackFunction = () => string;
export class MyClient {
constructor(
private domain: CallBackFunction,
) {}
public async myFunction(): Promise<MyInterface[]> {
console.log('domain name', this.domain());
...
return new Promise<MyInterface[]>(resolve => {
resolve(myObjects);
});
}
}
// в данный момент значение env.SOME_DOMAIN может не существовать (может переменная еще не объявлена)
const myClient = MyClient(
() => env.SOME_DOMAIN
);
// здесь может быть код, который объявит env.SOME_DOMAIN с нужным значением
// И только при следущем вызове произойдет обращение к выше переданной CallBackFunction, с
// помощью выозова this.domain(), которая вернет значение env.SOME_DOMAIN
myClient.myFunction();This will simulate pressing the Enter key on an element with an ID of myInput.
// create a new keyboard event and set the key to "Enter"
const event = new KeyboardEvent('keydown', {
key: 'Enter',
code: 'Enter',
which: 13,
keyCode: 13,
});
// dispatch the event on some DOM element
document.getElementById('myInput').dispatchEvent(event);
Комментарии