< strong>ES2016 (обычно именуемый ES7 или ECMAScript 7) — это следующая эволюция стандарта ECMA-262 (обычно называемого JavaScript), и он все еще находится на ранней стадии.
Асинхронные функции — это новая функция JavaScript, предложенная как часть стандарта ES2016 и пока не поддерживаемая ни одним браузером. Они построены на основе обещаний.
См. ниже введение в эту новую функцию из различных авторитетных источников.
Примечание :
Несмотря на то, что асинхронные функции обычно обозначаются как ES7 asynch functions
(например, чтобы отличить их от async.js или асинхронный JavaScript в целом), Аксель Раушмайер< /a> рекомендует не называть их так, однако как функция будет включена в следующий стандарт только после того, как его предложение достигнет стадии 4.
Асинхронные функции сейчас только на третьем этапе. Фактически, ES2016, скорее всего, не будет содержать асинхронных функций (поскольку < a href="https://stackoverflow.com/users/218196/felix-kling">Феликс Клинг указал в комментариях ниже).
Из предложения этапа 3:
Введение
Введение промисов и генераторов в ECMAScript дает возможность значительно улучшить модель на уровне языка для написания асинхронного кода в ECMAScript.
Аналогичное предложение было сделано для отложенных функций во время обсуждения ES6. Предложение здесь поддерживает те же варианты использования, используя аналогичный или тот же синтаксис, но напрямую опираясь на структуры потока управления, параллельные структурам генераторов, и используя промисы для возвращаемого типа вместо определения пользовательских механизмов.
Разработка этого предложения происходит по адресу https://github.com/tc39/ecmascript-asyncawait< /сильный>а>. Пожалуйста, регистрируйте проблемы там. Нетривиальные вклады ограничены членами TC39, но запросы на вытягивание для незначительных проблем приветствуются и поощряются!
Статус этого предложения
Это предложение было принято на этапе 3 ("Кандидат") процесса спецификации в сентябре 2015 года. Чемпион намерен принять это предложение на этапе 4 («Завершено») к концу ноября.
Примеры
Возьмем следующий пример, сначала написанный с использованием промисов. Этот код связывает набор анимаций с элементом, останавливаясь при возникновении исключения в анимации и возвращая значение, созданное окончательной успешно выполненной анимацией.
function chainAnimationsPromise(elem, animations) {
let ret = null;
let p = currentPromise;
for(const anim of animations) {
p = p.then(function(val) {
ret = val;
return anim(elem);
})
}
return p.catch(function(e) {
/* ignore and keep going */
}).then(function() {
return ret;
});
}
Уже с промисами код значительно улучшился по сравнению с прямым стилем обратного вызова, где такого рода зацикливание и обработка исключений сложны.
Task.js и подобные библиотеки предлагают способ использования генераторов для дальнейшего упрощения поддержки кода. Такое же значение:
function chainAnimationsGenerator(elem, animations) {
return spawn(function*() {
let ret = null;
try {
for(const anim of animations) {
ret = yield anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
});
}
Это заметное улучшение. Все шаблонные обещания, выходящие за пределы семантического содержания кода, удаляются, а тело внутренней функции представляет собой намерение пользователя. Тем не менее, есть внешний слой шаблона, чтобы обернуть код в дополнительную функцию генератора и передать его в библиотеку для преобразования в промис. Этот уровень необходимо повторять в каждой функции, использующей этот механизм для создания обещания. Это настолько распространено в типичном асинхронном коде Javascript, что имеет смысл избавиться от необходимости в оставшемся шаблоне.
С асинхронными функциями весь оставшийся шаблон удаляется, оставляя в тексте программы только семантически значимый код:
async function chainAnimationsAsync(elem, animations) {
let ret = null;
try {
for(const anim of animations) {
ret = await anim(elem);
}
} catch(e) { /* ignore and keep going */ }
return ret;
}
Из статьи Джейка Арчибальда асинхронные функции ES7 :
Асинхронно с промисами
В статье HTML5Rocks о обещаниях , в последнем примере показано, как загрузить некоторые данные JSON для истории, затем использовать их для получения дополнительных данных JSON для глав, а затем отобразить главы по порядку, как только они будут получены.
Код выглядит следующим образом:
function loadStory() {
return getJSON('story.json').then(function(story) {
addHtmlToPage(story.heading);
return story.chapterURLs.map(getJSON)
.reduce(function(chain, chapterPromise) {
return chain.then(function() {
return chapterPromise;
}).then(function(chapter) {
addHtmlToPage(chapter.html);
});
}, Promise.resolve());
}).then(function() {
addTextToPage("All done");
}).catch(function(err) {
addTextToPage("Argh, broken: " + err.message);
}).then(function() {
document.querySelector('.spinner').style.display = 'none';
});
}
Не плохо, но…
На этот раз с асинхронными функциями ES7…
async function loadStory() {
try {
let story = await getJSON('story.json');
addHtmlToPage(story.heading);
for (let chapter of story.chapterURLs.map(getJSON)) {
addHtmlToPage((await chapter).html);
}
addTextToPage("All done");
} catch (err) {
addTextToPage("Argh, broken: " + err.message);
}
document.querySelector('.spinner').style.display = 'none';
}
С помощью асинхронных функций (полное предложение) вы можете await
на обещать. Это останавливает функцию неблокирующим образом, ждет разрешения обещания и возвращает значение. Если обещание отклонено, оно выдает значение отклонения, поэтому вы можете справиться с этим, используя catch
.
Изменить: изначально я использовал await
в функции стрелки, очевидно, это не так разрешено, поэтому я заменил его циклом for
. Доменик рассказал мне, почему await
нельзя использовать в стрелочные функции.
loadStory
возвращает обещание, поэтому вы можете использовать его в других асинхронных функциях.
(async function() {
await loadStory();
console.log("Yey, story successfully loaded!");
}());
Из статьи KoaJS Эволюция асинхронного JavaScript :
Генераторы / выход
Генераторы JavaScript — относительно новая концепция, они были представлены в ES6 (также известном как ES2015).
Было бы неплохо, если бы при выполнении функции можно было приостановить ее в любой момент, вычислить что-то еще, сделать что-то еще, а затем вернуться к ней, даже с некоторым значением, и продолжить?
Это именно то, что функции генератора делают для вас. Когда мы вызываем функцию генератора, она не запускается, нам придется перебирать ее вручную.
function* foo () {
var index = 0;
while (index < 2) {
yield index++;
}
}
var bar = foo();
console.log(bar.next()); // { value: 0, done: false }
console.log(bar.next()); // { value: 1, done: false }
console.log(bar.next()); // { value: undefined, done: true }
Если вы хотите легко использовать генераторы для написания асинхронного JavaScript, вам понадобится co< /а> тоже.
Co — это средство управления потоком управления на основе генератора для Node.js и браузера, использующее промисы и позволяющее красиво писать неблокирующий код.
С co
наши предыдущие примеры могут выглядеть примерно так:
co(function* (){
yield Something.save();
}).then(function() {
// success
})
.catch(function(err) {
//error handling
});
Вы можете спросить: а как насчет операций, выполняемых параллельно? Ответ проще, чем вы думаете (на самом деле это просто Promise.all
):
yield [Something.save(), Otherthing.save()];
Асинхронный / ожидающий
Асинхронные функции были представлены в ES7 и в настоящее время доступны только с использованием транспилятора, такого как babel. (отказ от ответственности: сейчас мы говорим о ключевом слове async, а не о пакете async)
Короче говоря, с ключевым словом async
мы можем делать то же, что и с комбинацией co
и генераторов, кроме взлома.
Под капотом функции async
используют промисы — вот почему асинхронная функция вернется с ошибкой Promise
.
person
John Slegers
schedule
23.02.2016
async
/await
. Заблуждающийся, может быть, ужасный, нет. - person Frédéric Hamidi   schedule 23.02.2016async
/await
не отказывается от обещаний. Оно охватывает их. Это делает код обещаний со сложным потоком управления намного проще для чтения и записи. - person Bergi   schedule 23.02.2016await
для написания кода, как будто он не был асинхронным, построчно. Это упрощает написание, но во многих случаях труднее читать, так как большинство людей привыкли к асинхронным функциям, имеющим обратный вызов, возможность использования и т. д., а теперь вдруг это не так. - person adeneo   schedule 23.02.2016async
функции по-прежнему доступны, каждая из них возвращает обещание! Их можно полностью прозрачно заменить обычными функциями, возвращающими промисы, подобно тому, как функции-генераторы можно заменять функциями, возвращающими итераторы (единственное отличие —.toString()
). - person Bergi   schedule 23.02.2016