-
Notifications
You must be signed in to change notification settings - Fork 16
async await
Иногда нужно синхронизировать несколько асинхронных операций
В ES7 это достигается легко с помощью асинхронной функции
Для объявления асинхронной функции используется ключевое слово async ( перед function )
в теле асинхронной функции перед каждым выражением, возвращающим промис, ставится ключевое слово await
Результатом будет объект класса AsyncFunction
async function test () {}
console.dir ( test )▼ async ƒ test()
arguments: (...)
caller: (...)
length: 0
name: "test"
▼ __proto__: AsyncFunction
arguments: (...)
caller: (...)
► constructor: ƒ AsyncFunction()
Symbol(Symbol.toStringTag): "AsyncFunction"
▼ __proto__: ƒ ()
► apply: ƒ apply()
arguments: (...)
► bind: ƒ bind()
► call: ƒ call()
caller: (...)
► constructor: ƒ Function()
length: 0
name: ""
► toString: ƒ toString()
► Symbol(Symbol.hasInstance): ƒ [Symbol.hasInstance]()
► get arguments: ƒ ()
► set arguments: ƒ ()
► get caller: ƒ ()
► set caller: ƒ ()
► __proto__: ObjectПопытка отратиться к объекту AsyncFunction вызовет исключение:
test instanceof AsyncFunctionпоэтому получить ссылку на нее можно, например, так:
var AsyncFunctionConstructor = test.__proto__.constructorили:
var AsyncFunction = ( async function () {} ).__proto__.constructorТеперь исключения не будет:
test instanceof AsyncFunction // trueПоэтому нельзя конструктор объявить как асинхронную функцию - конструктор должен возвращать экземпляр объекта, а не обещание
Асинхронная функция является промисом, который обещает, что все асинхронные операции внутри него будут выполнены в строго заданном порядке, но когда это произойдет - неизвестно, поскольку каждая из операций будет выполнятся неизвестно сколько времени
В принципе, того же эффекта можно достичь с помощью цепочки промисов
Однако асинхронная функция делает код линейным и прозрачным
Внутри асинхронной функции синхронизируются вызовы коллбэков промисов
Ключевое слово await выполняет ту же роль, что и метод then() каждого промиса
Различие в том, что метод then() промиса запускает свой коллбэк асинхронно,
а ключевое слово await запускает функцию обратного вызова в нужное время
Итак, асинхронная функция является "оберткой" для нескольких асинхронных операций, которые строго упорядочиваются, т.е. их коллбэки вызываются в заданной последовательности
await можно использовать только внутри асинхронных функций
В противном случае будет сгенерировано исключение
⛔️ Uncaught SyntaxError: await is only valid in async function☕ 1️⃣
function common ( message ) {
return new Promise (
( resolve, reject ) => {
setTimeout (
() => resolve ( message ),
Math.random() * 8000
)
}
)
}
function first () {
return common ( "first" )
}
function second () {
return common ( "second" )
}
function third () {
return common ( "third" )
}Задача - синхронизировать вызов коллбэков так,
чтобы первым в консоль было выведено "first", затем "second", а затем "third"
Аасинхронный код выводит их в случайном порядке:
first().then( res => console.log ( res) )
second().then( res => console.log ( res) )
third().then( res => console.log ( res) )first().then(
res => {
console.log ( res )
second().then(
res => {
console.log ( res )
third().then(
res => console.log ( res )
)
}
)
}
)let test = async () => {
console.log ( await first() )
console.log ( await second() )
console.log ( await third() )
}
test()Как видно из примера, код асинхронной функции проще, чем цепочка промисов
☕ 2️⃣
async function getUsersData ( userName ) {
let readJSON = url => fetch ( url )
.then ( response => response.json() )
let userData = await readJSON (
`https://api.github.com/users/${userName}`
)
document.body.appendChild (
document.createElement ( "img" )
).src = userData.avatar_url
let userRepos = await readJSON ( userData.repos_url )
return readJSON ( userRepos[0].events_url )
}
getUsersData( 'josh' )
.then ( events => console.log ( events ) )☕ 3️⃣
Синхронизация асинхронных процессов приводит к увеличению времени выполнения
Предположим, есть две функции, возвращающие промис:
var getNames = () =>
new Promise ( ( resolve, reject ) =>
setTimeout (
() => resolve ( "Names" ),
1000
)
)
var getPosts = () =>
new Promise ( ( resolve, reject ) =>
setTimeout (
() => resolve ( "Posts" ),
1000
)
)Каждый вызов длится 1 секунду
Если мы будем использовать асинхронную функцию для последовательного вызова getNames и getPosts, то суммарная продолжительность выполнения этих двух асинхронных операций составит не менее 2 сек
async function getData () {
console.time ( 'time' )
var posts = await getPosts ()
var names = await getNames ()
console.timeEnd ( 'time' )
console.info ( `\n${ names } | ${ posts }\n\n` )
}
getData ()Names | Posts
time: 2002.258056640625msЧто плохо?
То, что несвязанные между собой асинхронные процессы выстраиваются в очередь
Посмотрим на альтернативный вариант
function getData () {
console.time ( 'time' )
Promise.all ([
getNames (),
getPosts ()
])
.then (
result => {
console.info ( `\n${ result[0] } | ${ result[1] }\n\n` )
console.timeEnd ( 'time' )
}
)
}Names | Posts
time: 1001.474365234375ms☕ 4️⃣
<body>
<label for="user">Name of github user:</label>
<input id="user"/>
</body>function getData ( typ ) {
return new Promise ( function ( resolve, reject ) {
setTimeout ( () => {
console.log ( 'Promise resolved: ', typ )
resolve ( typ )
}, 1000 )
})
}
function getAllData () {
console.time ( "Total" )
let promises = Array.from ( arguments )
.map ( x => getData ( x ) )
Promise.all ( promises )
.then ( response => {
console.timeEnd ( "Total" )
console.log ( "response: ", response )
})
}
getAllData ( "figures", "colors", "diameters" )Функция getData () возвращает промис
Промис будет разрешен через 1 сек
Функция getAllData () формирует массив промисов promises и запускает сразу все асинхронные процессы с помощью метода Promise.all ()
Что происходит в этом случае:
Мы не выстраиваем очередь, а запускаем сразу все асинхронные процессы параллельно
Общая продолжительность операции не будет суммой продолжительности всех асинхронных процессов
В нашем примере вместо 3 секунд, которые мы получили бы в случае последовательной обработки запросов ( как в примере 1 ) мы получили общую продолжительность 1 сек
Используем fetch для получения данных трех типов: JSON, text, img
| ☕ 5️⃣ |
|---|
© Irina H.Fylyppova 2018
Использование данных материалов или любой их части коммерческими школами ( курсами ) является нарушением авторских прав
| 1 | 2 | 3 | 4 | 5 |
| 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 |
| ⏬ |
|---|
- Блок-схема алгоритма
- Developer Tools
- Chrome DevTools
- Переменные
- Оператор typeof
- Структуры данных
- Операторы присваивания
- Логические выражения
- Условные операторы
- Инкремент
- Свойство length
- Оператор цикла for
- UTF-8
Homework
- Приведение типов
- NaN | null | Infinity
- BigInt (ES10)
- Функции
- Методы
- Методы строк
- Методы массивов
- Date ()
Самостоятельная работа
Практика (XSS)
Homework
- Циклы while и do...while
- Циклы for...of и for...in
- Параметры по умолчанию
- Объект function
Практика
Homework
- Нативные и host-объекты
- Литерал объекта
- Унаследованные свойства
- Конструктор
- Модель наследования
- Публичные и приватные свойства
- Оператор in
1
Homework
- Итерирующие методы массивов
- Тестирование производительности
- SHA
Homework
- Размеры и прокрутка элемента
- Event Loop
- async | await
- API
- REST | HATEOAS
- status codes
JSON placeholder-
JSON server
fake chat
Homework
- strict mode
- Вычисляемые имена свойств
- Краткий синтаксис методов
- Краткий литерал объекта
- Классы
Homework
- :not(:defined)
- Shadow DOM
- Custom elements
- Lifecycle hooks
- whenDefined
- <template>
- slot
1
2
3
Homework
- npm
- webpack
Упражнение 1- ES6 модули
Упражнение 2- --mode | --watch
Упражнение 3
Упражнение 4
Упражнение 5
Упражнение 6
Упражнение 7
Упражнение 8
Homework
| ⏫ |
|---|

Дополнительно
Справочная инфо
Git Bush
TCP/IP
Коды символов