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

130

Я написал этот код в lib/helper.js

var myfunction = async function(x,y) {
   ....
   reutrn [variableA, variableB]
}
exports.myfunction = myfunction;

а потом я попытался использовать его в другом файле

 var helper = require('./helper.js');   
 var start = function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

У меня ошибка

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

В чем проблема?

j.doe
источник
1
Что ж, проблема в том, что его awaitможно использовать только внутри asyncфункции. То есть awaitделает функцию асинхронной, поэтому она должна быть объявлена ​​как таковая.
Pointy
Какая текущая ошибка?
acdcjunior
все то же самое, SyntaxError: await допустимо только в асинхронной функции
j.doe
Вам нужно больше рассказать о своем коде.
Ele

Ответы:

162

Ошибка относится не к, myfunctionа к start.

async function start() {
   ....

   const result = await helper.myfunction('test', 'test');
}

// My function
const myfunction = async function(x, y) {
  return [
    x,
    y,
  ];
}

// Start function
const start = async function(a, b) {
  const result = await myfunction('test', 'test');
  
  console.log(result);
}

// Call start
start();



Я использую возможность этого вопроса , чтобы сообщить вам об известных антипаттернах , используя awaitкоторый: return await.


НЕПРАВИЛЬНО

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// useless async here
async function start() {
  // useless await here
  return await myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


ВЕРНЫЙ

async function myfunction() {
  console.log('Inside of myfunction');
}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// Also point that we don't use async keyword on the function because
// we can simply returns the promise returned by myfunction
function start() {
  return myfunction();
}

// Call start
(async() => {
  console.log('before start');

  await start();
  
  console.log('after start');
})();


Также знайте, что есть особый случай, когда return awaitэто правильно и важно: (используя try / catch)

Есть ли проблемы с производительностью при использовании return await?

Грегори НЕЙТ
источник
Но это не работает, я обновил свой код. Я все еще получаю ту же ошибку
j.doe
@ j.doe Я добавил отрывок
Grégory NEUT
2
Спасибо, я нашел свою проблему. Я пытался сделать это внутри обратного вызова - это функция start (). Решение было: const start = async function (a, b) {task.get (options, async function (error, result1) {const result = await myfunction ('test', 'test');
j.doe
Учитывая, что Node является однопоточным. Разве это не уменьшает количество запросов в минуту, а также увеличивает задержку между заполнением запросов.
Rishabh Dhiman
1
Стоит отметить , что в «ПРАВИЛЬНОЙ» , например, не нужно объявлять startкак asyncфункции (хотя некоторые предпочли сделать это в любом случае, для того , чтобы быть более явным)
Гирсам
11

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

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}
Джон Лэнгфорд
источник
2
Это было проблемой для меня. Я заменил функцию карты на цикл for, что было для меня простым решением. Однако это решение может не работать для вас в зависимости от вашего кода.
Thomas
6
К вашему сведению, вы тоже можете это сделатьsomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
птим
1
В awaitвашем коде вводит в заблуждение, потому Array.mapчто не будет обрабатывать функцию как асинхронную функцию. Чтобы быть совершенно ясным, после завершения mapфункции someFunctionвсе будут отложены. Если вы действительно хотите дождаться завершения работы функций, вам нужно написать: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))или await Promise.all(someArray.map(someFunction))).
Грегори НЕЙТ
9

Для использования awaitконтекст его выполнения должен быть asyncв природе

Как уже говорилось, вам нужно прежде всего определить природу вашего executing contextжелания выполнить awaitзадачу.

Просто поставьте asyncперед fnобъявлением, в котором asyncбудет выполняться ваша задача.

var start = async function(a, b) { 
  // Your async task will execute with await
  await foo()
  console.log('I will execute after foo get either resolved/rejected')
}

Объяснение:

В вашем вопросе вы импортируете объект, methodкоторый asynchronousпо своей природе будет выполняться параллельно. Но там, где вы пытаетесь выполнить этот asyncметод, находится внутри другого, execution contextкоторый вам нужно определить asyncдля использования await.

 var helper = require('./helper.js');   
 var start = async function(a,b){
     ....
     const result = await helper.myfunction('test','test');
 }
 exports.start = start;

Интересно, что происходит под капотом

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

Также, если вы знакомы с promises, awaitна самом деле выполняет тот же процесс обещания / решения. Создание цепочки обещаний и выполнение следующей задачи в resolveобратном вызове.

Для получения дополнительной информации вы можете обратиться к MDN DOCS .

Сатьям Патхак
источник
Даже с асинхронным запуском функции запуска я получаю сообщение об ошибке
j.doe
Я не уверен, где вы упускаете и получаете эту ошибку, нет такого сложного объяснения, чтобы устранить эту ошибку.
Satyam Pathak
это правильный ответ и фактически объясняет причину подчеркивания. за проголосовали.
linehrr
3

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

 var start = async function(a, b) {

 }

Для заинтересованных: предложение для верхнего уровня awaitв настоящее время находится на этапе 2: https://github.com/tc39/proposal-top-level-await

user835611
источник
1
К сожалению, это в основном означает, что вам придется сделать ВСЕ свои функции асинхронными во всей базе кода. Потому что, если вы хотите использовать await, вы должны сделать это в асинхронной функции, что означает, что вы должны ожидать ответа этой функции в вызывающей ее функции - опять же, это означает, что ВСЕ ваши функции должны будут стать асинхронными. Для меня это означает, что await async не готов к использованию. Когда вы можете использовать await для вызова асинхронного метода, независимо от того, является ли текущая функция синхронной или асинхронной, тогда он будет готов к работе в прайм-тайм.
Родни П. Барбати,
1
Каждая функция , которая через любой уровень косвенности зависит от результатов внешнего процесса должны, и должны быть определены async- это вся суть в async.
Гершом,
В настоящее время вы можете использовать его в node repl с помощью --experimental-repl-awaitoption.
Лодзь
3

У меня была такая же проблема, и следующий блок кода выдавал такое же сообщение об ошибке:

repositories.forEach( repo => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});

Проблема в том, что метод getCommit () был асинхронным, но я передавал ему репозиторий аргументов, который также был создан с помощью Promise. Итак, мне пришлось добавить к нему слово async вот так: async (repo), и он начал работать:

repositories.forEach( async(repo) => {
        const commits = await getCommits(repo);
        displayCommit(commits);
});
Эмиль
источник
0

async / await - это механизм обработки обещаний, это можно сделать двумя способами

functionWhichReturnsPromise()
            .then(result => {
                console.log(result);
            })
            .cathc(err => {
                console.log(result);

            });

или мы можем использовать await, чтобы дождаться, пока обещание сначала заполнит его, что означает, что оно либо отклонено, либо разрешено.

Теперь, если мы хотим использовать await (ожидание выполнения обещания) внутри функции, обязательно, чтобы функция контейнера была асинхронной функцией, потому что мы ожидаем асинхронного выполнения обещания || имеет смысл правильно ?.

async function getRecipesAw(){
            const IDs = await getIds; // returns promise
            const recipe = await getRecipe(IDs[2]); // returns promise
            return recipe; // returning a promise
        }

        getRecipesAw().then(result=>{
            console.log(result);
        }).catch(error=>{
            console.log(error);
        });
повелитель
источник
-2

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

Но почему? 'await' явно превращает асинхронный вызов в синхронный вызов, и, следовательно, вызывающий не может быть асинхронным (или асинхронным) - по крайней мере, не из-за вызова, выполняемого в 'await'.

mn_test347
источник
1
Собственно, await не ждет результатов - он сразу возвращает обещание. Это именно то, что я пытался передать. Если await действительно ждал и не возвращал управление вызывающей стороне, то любая функция, содержащая ключевое слово await, буквально не могла быть помечена как асинхронная. Но вместо этого у нас есть любая функция, которая содержит await или вызывает функцию, которая в конечном итоге вызывает функцию, содержащую await, должна быть асинхронной. В принципе, если вы вызываете await хотя бы один раз - все ваши функции должны быть помечены как асинхронные.
Родни П. Барбати,
-5

Да, await / async был отличной концепцией, но реализация полностью нарушена.

По какой-то причине ключевое слово await было реализовано таким образом, что его можно использовать только в рамках асинхронного метода. На самом деле это ошибка, хотя вы не увидите упоминания о ней нигде, кроме как здесь. Исправление этой ошибки заключалось в реализации ключевого слова await таким образом, чтобы его можно было использовать только ДЛЯ ВЫЗОВА асинхронной функции, независимо от того, является ли вызывающая функция синхронной или асинхронной.

Из-за этой ошибки, если вы используете await для вызова реальной асинхронной функции где-то в вашем коде, то ВСЕ ваши функции должны быть помечены как асинхронные, и ВСЕ ваши вызовы функций должны использовать await.

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

Если вы действительно думаете об этом, использование await в функции должно требовать функции, содержащей ключевое слово await, чтобы НЕ БЫТЬ ASYNC - это потому, что ключевое слово await собирается приостановить обработку в функции, в которой найдено ключевое слово await. Если обработка в этой функции приостановлена, то она определенно НЕ асинхронна.

Итак, разработчикам javascript и ECMAScript - исправьте реализацию await / async следующим образом ...

  • await может использоваться только для ВЫЗОВА асинхронных функций.
  • await может появляться в любой функции, синхронной или асинхронной.
  • Измените сообщение об ошибке с «await is valid only in async function» на «await can only be used to call async functions».
Родни П. Барбати
источник
Если хотите, можете назвать это ошибкой, но я не согласен. Не существует такого понятия, как «приостанавливающийся» код - скорее, есть код, который не может завершиться без результатов какого-либо внешнего процесса (обычно io). Такой код следует называть «асинхронным», так как многие внешние процессы должны иметь возможность работать одновременно (несинхронно), в отличие от виртуальной машины javascript, которая является однопоточной. Если у вас есть много функций, которые необходимо реорганизовать, asyncэто отражает тот факт, что многие из ваших функций требуют результатов внешних процессов. На мой взгляд, это совершенно канонично.
Гершом,
Также стоит упомянуть ужасный недостаток ограничения использования awaitтолько с вызовами функций: для одного внешнего процесса только одна точка в коде javascript может быть уведомлена, когда этот процесс завершится. Например, если содержимое файла необходимо для трех независимых целей, каждая цель должна будет выполняться независимо let content = await readTheFile();- это потому, что нельзя ожидать «обещания содержимого файла», а только «действие чтения файла и возобновления после того, как оно было выполнено. читать".
Гершом,
Хорошо, не будем называть это кодом, который приостанавливает работу, или кодом, который не может быть завершен, но как насчет заблокированного ожидания. Вот в чем загвоздка - функция, которая заблокирована в ожидании или не может завершить, - это функция, содержащая ключевое слово await. С ключевым словом await вызывается не асинхронная функция. Следовательно, функция, содержащая ключевое слово await, определенно НЕ должна быть помечена как асинхронная - это блокируется ожидание, что является противоположностью асинхронности.
Родни П. Барбати,
Чтобы сделать это предельно ясным, рассмотрим следующее - await предназначен для упрощения использования асинхронных функций, заставляя их казаться синхронными (т.е. он позволяет мне делать что-то в определенном порядке). Принуждение функции, содержащей await, быть асинхронной - это полное неправильное употребление названия - вы использовали await, чтобы она стала синхронной. Функция, содержащая await, абсолютно, во всех возможных смыслах, НЕ является асинхронной функцией !!!
Родни П. Барбати,
1
@Gershom - звучит разумно. Спасибо!
Родни П. Барбати,