Можно ли использовать async/await практически везде?

В настоящее время я пишу небольшой инструмент NodeJS CLI для личного использования, и я решил попробовать функцию async/await ES7 с Babel.

Это сетевой инструмент, поэтому у меня, очевидно, есть асинхронные сетевые запросы. Я написал простую оболочку для пакета request:

export default function(options) {
    return new Promise(function(resolve, reject) {
        request({...options,
            followAllRedirects: true,
            headers: {
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0"
            }
        }, (error, response, body) => {
            if(error) {
                return reject(error);
            }
            resolve({response: response, body: body});
        });
    });
}

Теперь я могу сделать что-то вроде

async function getGooglePage() {
    try {
        var r = await request({url: "http://google.com"});

        console.log(r.body);
        console.log("This will be printed in the end.")
    } catch(e) {
        console.log(e);
    }
}
getGooglePage();

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


person user0103    schedule 13.02.2016    source источник


Ответы (3)


async/await иногда называют «заразным» или «вирусным» (по крайней мере, так оно и есть в мире C#), потому что для того, чтобы он был эффективным, он должен поддерживаться на всем протяжении цепочки вызовов. Принуждение чего-то асинхронного к синхронному может привести к непредвиденным результатам, поэтому вам следует расширить его от исходного метода до потребителя верхнего уровня, использующего его. Другими словами, если вы создаете или используете тип, который его использует, этот тип также должен его реализовать, и так далее по всей цепочке. Так что да, ожидается, что вы добавите асинхронность к каждой функции, которая сама от нее зависит. Просто обратите внимание, однако, что вы не должны упреждающе добавлять асинхронность к функциям, которые на самом деле не реализуют или не нуждаются в этом.

Просто подумайте: если вы используете async (я имею в виду await что-то), вы async. Не превращайте вызов async во что-то синхронное.

person moribvndvs    schedule 13.02.2016
comment
Я не думаю, что вирусная часть так сильно применима к JavaScript, поскольку кажется, что это больше выбор реализации, реализована ли функция, возвращающая промис, с промисами или как асинхронная функция. В JavaScript также очень мало типов. - person jib; 14.02.2016
comment
@jib Честно говоря, такие вещи, как мир C #, просто возвращают общую задачу, которая в данном случае эффективно используется как обещание, а async/await - это просто синтаксический сахар. Опять же, я думаю, что смешивание этих двух концепций — хороший способ получить желаемые результаты, но я понимаю, что вы имеете в виду в том смысле, что в мире C# вирусная природа усиливается тем фактом, что это требуется компилятору, но такого нет. вещь в JavaScript. - person moribvndvs; 14.02.2016
comment
Я согласен с @jib. В асинхронности нет ничего вирусного. Практически нет разницы между асинхронной функцией и обычной функцией, возвращающей обещание. Асинхронную функцию можно обрабатывать так же, как обещание. - person Maciej Krawczyk; 25.02.2021

Я делаю запросы во многих местах, и мне приходится помечать все эти функции как асинхронные.

Да, если бы весь ваш код был асинхронным, вы бы везде использовали функции async.

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

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

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

async function getXandThenDoY(xargs) {
    let res = await get(xargs);
    …
    return …;
}

вам следует рассмотреть возможность создания двух функций

function doY(res) {
    // synchronous
    …
    return …;
}
function getXandDoY(xargs) {
    // asynchronous
    return get(xargs).then(doY);
}
/* or, if you prefer:
async function getXandDoY(xargs) {
    return doY(await get(xargs));
}
*/
person Bergi    schedule 13.02.2016

У меня был тот же вопрос.

И обнаружил отличный ответ здесь → «Подводный камень 3: весь ваш стек должен быть асинхронным»

Нет, async/await не заразен. (Я тоже некоторое время верил в то же самое)

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

С сайта developer.mozilla.org:

Объявление асинхронной функции определяет асинхронную функцию…

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

Образец кода:

const log = console.log; // just lazy shorthand

// just to delay, as seen in many places
function promiseTimeout(time, value) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() { resolve(value); }, time);
    });
};

// the thing you care about
async function foo() {
    Promise.resolve('here')
    .then((a) => {log('doing stuff '+a); return 'pear'})
    .then(function(v) {
        return promiseTimeout(1000,v)
    });
};

// treat async-function like promise:
foo().then(function(){ log('folling up in main, ')});
// log('bad end');

получает вас:

doing stuff here
following up in main

Включение «плохого конца» проявилось бы слишком рано. Вы можете только ожидать вещи, которые вы используете. (И если вы это сделаете, помните: это просто синтаксический сахар, избавляющий вас от необходимости вставлять ваш последующий код в .then() clasuses... хорошо, но не более того.)

person Frank Nocke    schedule 17.04.2018