4

Из прочитанного про async/await, я понял что эта конструкция должна упростить код, избавить разработчиков от лишних коллбэков. Я запустил такой пример:

var request = require('request');
var async = require('asyncawait/async');
var await = require('asyncawait/await');

function getQuote() {
  var quote;

  return new Promise(function(resolve, reject) {
    request('http://ron-swanson-quotes.herokuapp.com/v2/quotes', function(error, response, body) {
      quote = body;
      resolve(quote);
    });
  });
}

var main = async (()=>{
  var quote = await(getQuote());
  console.log(quote);
});


main();

console.log('Ron once said,');

В консоли вижу следующее:

Ron once said,
["Great job, everyone..."]

Это говорит о том, что main() срабатывает после console.log('Ron once said,').

Но в чем суть тогда, если один-черт нужно передавать коллбэк в main() чтобы сначала получить результат запроса, а потом что-то с ним делать?

Как добиться того, чтобы в данном примере сначала сработал main() а потом console.log()?

Qwertiy
  • 123,725
sanu
  • 2,575
  • например добавить await при вызове main – Grundy May 31 '16 at 10:16
  • ну так вы await не делаете для main() – Vladimir Gamalyan May 31 '16 at 10:17
  • Я не совсем уверен, но это какой-то неправильный костыльный async/await, по-моему лучше дождаться нормальной поддержки браузерами – andreymal May 31 '16 at 10:33
  • 2
    @andreymal, почему неправильный? И при чём тут браузеры? – Qwertiy May 31 '16 at 11:03
  • @Qwertiy потому что вместо нормальных async/await я вижу тут полифилл-костыль на этих самых несчастных коллбэках (async/await здесь - функции, а не операторы). Окей, браузеры ни при чём, нода в вопросе не упоминается, а теги я не глянул) Но это ничего не меняет - нативной поддержки async/await в ноде всё равно нет. – andreymal May 31 '16 at 11:39
  • @Qwertiy кстати, по той же причине, что "async/await здесь - функции, а не операторы", ваш ответ не работает и, формально, неверен :) – andreymal May 31 '16 at 11:40
  • @andreymal поддержки браузерами, насмешил =) открой вики https://ru.wikipedia.org/wiki/Node.js – Serge Esmanovich May 31 '16 at 11:45
  • @SergeEsmanovich см. мой второй коммент – andreymal May 31 '16 at 11:46
  • Тут есть пример https://jsfiddle.net/bx5c7xqe/1/ – Serge Esmanovich May 31 '16 at 11:49
  • @andreymal, тега изначально не было. Но node.js'ный код http-запроса узнаётся замечательно. Скобки в ответ добавил. – Qwertiy May 31 '16 at 12:07
  • @SergeEsmanovich, там babel. – Qwertiy May 31 '16 at 12:07
  • @Qwertiy, babel -- временное решение, пока не будет поддержки ES7. – Dmitriy Simushev May 31 '16 at 15:07

2 Answers2

10

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

До определения async/await подобно поведение достигалось использованием генераторов в комплекте с библиотеками, вроде co. Я уже детально расписывал этот подход в одном из своих ответов.


Теперь несколько слов о вашем конкретном примере. Основная цель, насколько я могу видеть, в псевдо-синхронном выполнении связки:

main();
console.log('Ron once said,');

Казалось бы, функция main определена как асинхронная и этот блок должен выполняться последовательно. Однако вы упускаете один очень важный момент: определение функции асинхронной не делает ее вызов псевдо-синхронным автоматически. Вам нужно в явном виде дождаться результата выполнения main.

Для этого нужно просто обернуть весь ваш код в IIFE-выражение, использующее асинхронную функцию и дождаться результата выполнения main:

let getData = () => {
    return new Promise(function(resolve, reject) {
        setTimeout(() => {
            resolve('Great job, everyone...');
        }, 500);
    });
};

(async () => {
    let main = async ()=> {
        console.log(await getData());
    };

    await main();
    console.log('Ron once said,');
})();

Этот пример выведет:

Great job, everyone...
Ron once said,

А вот и работающий пример на JSFiddle.

Замечание:

Код выше я написал на чистом JS, без использования библиотеки-полифила asyncawait. Если вы хотите использовать эту библиотеку, то вместо ключевых слов async/await вам нужно в явном виде вызывать функции этой библиотеки.

В качестве альтернативы, я бы предложил использовать Babel, превращающий ES 6/7 код в то, что уже сегодня можно запустить в большинстве браузеров.

Dmitriy Simushev
  • 17,999
  • 5
  • 49
  • 85
0
main();

Если надо ждать, то это надо указать:

await (main());
Qwertiy
  • 123,725
  • Таким образом я получаю ошибку await main(); SyntaxError: Unexpected identifier. для этого нужно как-то запустить ноду в режиме компилирования через babel? – sanu May 31 '16 at 11:07
  • @sanu0074, если посмотрите в вашем случае await похоже функция, по этому должно быть как-то так await( main()); – Grundy May 31 '16 at 11:09
  • @sanu0074, добавил скобки. – Qwertiy May 31 '16 at 12:08
  • @Qwertiy, это так же вызывает ошибку: Error: await functions, yield functions, and value-returning suspendable functions may only be called from inside a suspendable function. – sanu May 31 '16 at 12:12
  • 1
    @Qwertiy, ключевое слово await можно использовать только в функции, помеченной как async. – Dmitriy Simushev May 31 '16 at 14:34
  • @DmitriySimushev, ну значит не выйдет. Можно было бы всё обернуть в функцию, но ожидания всё равно не оправдаются, как только кто-то сделает require этого модуля... – Qwertiy May 31 '16 at 14:40
  • require не должен приводить к выполнению чего бы то ни было на прямую. А возвращать асинхронные функции можно. – Dmitriy Simushev May 31 '16 at 15:02
  • @DmitriySimushev, но ведь в данной реализации код вызывается непосредственно. – Qwertiy May 31 '16 at 15:17
  • @Qwertiy, но ведь в данной реализации ничего не сказано про require этого кода. – Dmitriy Simushev May 31 '16 at 15:19