wait є дійсним лише у функції async


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;

Я отримав помилку

"Очікувати дійсно лише в функції асинхронізації"

У чому питання?


1
Ну, проблема полягає в тому, що awaitйого можна використовувати лише всередині asyncфункції. Тобто awaitробить функцію асинхронною, тому її треба оголосити як таку.
Pointy

Яка поточна помилка?
acdcjunior

як і раніше, SyntaxError: wait є дійсним лише у функції async
j.doe

Вам потрібно поділитися більше контексту про свій код.
Еле

Відповіді:


160

Помилка не посилається, 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правильний і важливий випадок : (використовуючи спробувати / ловити)

Чи є проблеми з функціонуванням із „поверненням чекаємо”?


Але це не працює, я оновив код. Я все одно отримую ту саму помилку
j.doe

@ j.doe Я додав фрагмент
Grégory NEUT

2
Дякую, я знайшов свою проблему. Я намагався зробити це всередині зворотного дзвінка - це функція start (). Рішенням було: const start = функція асинхронізації (a, b) {task.get (параметри, функція асинхронізації (помилка, результат1) {const result = очікувати моєї функції ('test', 'test');
j.doe

Враховуючи, що Вузол - це одна нитка. Чи не зменшує це запит на хвилину, а також збільшує затримку між запитами на повне заповнення.
Рішабх Дхіман

1
Варто зазначити , що в «ПРАВИЛЬНОЇ» , наприклад, не потрібно оголошувати startяк asyncфункції (хоча деякі вважали за краще зробити це в будь-якому випадку, для того , щоб бути більш явним)
Ґершом

11

Коли я отримав цю помилку, виявилося, що я зателефонував до функції карти всередині моєї функції "асинхронізація", тому це повідомлення про помилку насправді посилалось на те, що функція карти не позначається як "асинхронізація". Я вирішив цю проблему, взявши виклик "очікування" з функції карти і придумав інший спосіб отримати очікувану поведінку.

var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}

2
Це було для мене проблемою. Я замінив функцію map на цикл for, що було для мене легким рішенням. Однак це рішення може не працювати для вас залежно від вашого коду.
Томас

6
FYI ви також можете зробитиsomeArray.map(async (someVariable) => { return await someFunction(someVariable)})
ptim

1
Код awaitу вашому коді вводить в оману, тому що Array.mapне буде обробляти функцію як асинхронну функцію. Щоб бути абсолютно зрозумілим, після завершення mapфункції someFunctionвсе буде в очікуванні. Якщо ви хочете по-справжньому чекати завершення функцій, вам слід написати: await Promise.all(someArray.map(someVariable => someFunction(someVariable)))або await Promise.all(someArray.map(someFunction))).
Grégory NEUT

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

Я не впевнений, де ви пропущені та отримуєте цю помилку, немає такого складного пояснення, щоб вирішити цю помилку.
Сатьям Патхак

це правильна відповідь і фактично пояснив підкреслену причину. нагору проголосували.
linehrr

3

Поточна реалізація async/ awaitпідтримує лише awaitключове слово всередині asyncфункцій. Змініть startпідпис функції, щоб ви могли використовувати awaitвсередині start.

 var start = async function(a, b) {

 }

Для тих, хто цікавиться, пропозиція про найвищий рівень awaitнаразі знаходиться на етапі 2: https://github.com/tc39/proposed-top-level-await


1
На жаль, це в основному означає, що вам доведеться зробити ВСІ свої функції асинхронізуючими по всій базі коду. Оскільки, якщо ви хочете використовувати функцію await, ви повинні виконати це у функції асинхронізації, а це означає, що ви повинні дочекатися відповіді цієї функції у виклику функції - знову ж таки, це означає, що ВСІ ваші функції повинні стати асинхронністю. Для мене це означає, що чекати async не готово до використання. Коли ви можете використовувати функцію очікування для виклику методу асинхронізації, незалежно від того, чи є поточна функція синхронною чи асинхронною, вона буде готова до прайм-тайму.
Родні П. Барбаті

1
Кожна функція , яка через будь-який рівень непрямого залежить від результатів зовнішнього процесу повинні, і повинні бути визначені async- це вся суть в async.
Гершом

Наразі ви можете використовувати його у вузлі repl за допомогою --experimental-repl-awaitпараметра.
Лодзь

3

У мене була та сама проблема, і наступний блок коду давав те саме повідомлення про помилку:

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

Проблема полягає в тому, що метод getCommits () був асинхронним, але я передавав йому аргумент repo, який також вироблявся Обіцянням. Отже, мені довелося додати слово 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 (очікування обіцянки виконати) всередині функції, це обов'язково , що функція контейнера повинна бути функція асинхронної , тому що ми чекаємо обіцянки здійсненого асинхронно || має сенс правильно ?.

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

"Очікувати дійсно лише в функції асинхронізації"

Але чому? "очікувати" явно перетворює виклик асинхронізації у синхронний дзвінок, і тому абонент не може бути асинхронним (або асинхронним) - принаймні, не через те, що дзвінок здійснювався під час "очікування".


1
Власне, очікування не чекає результатів - це негайно повертає обіцянку. Це саме те, що я намагався передати. Якщо ж очікувач дійсно чекав і не повертав керуючий користувачеві, то будь-яка функція, яка містила ключове слово очікування, буквально не змогла б бути позначена асинхронізацією. Але замість цього у нас є будь-яка функція, яка містить функцію очікування або виклику, яка в кінцевому підсумку викликає функцію, що містить функцію очікування, повинна бути асинхронізованою. В основному, якщо дзвінок чекає навіть одного разу - всі ваші функції повинні бути позначені асинхронізуванням.
Родні П. Барбаті

-5

Так, wait / async була чудовою концепцією, але реалізація повністю зламана.

З будь-якої причини ключове слово, яке очікує, було реалізовано таким чином, що його можна використовувати лише в методі асинхронізації. Насправді це помилка, хоча ви не побачите її як таку, де тільки тут. Виправлення цієї помилки полягало б у тому, щоб реалізувати ключове слово очікування таким чином, що воно може використовуватися лише для виклику функції асинхронізації, незалежно від того, сама функція виклику є синхронною чи асинхронною.

Через цю помилку, якщо ви використовуєте функцію очікування для виклику справжньої асинхронної функції десь у вашому коді, то ВСІ ваші функції повинні бути позначені як асинхронні, і ВСІ ваші виклики функцій повинні використовувати функцію очікування.

Це по суті означає, що ви повинні додати накладні обіцянки для всіх функцій у всій своїй програмі, більшість з яких не є і ніколи не буде асинхронною.

Якщо ви насправді думаєте про це, використовуючи функцію await у функції, потрібно вимагати функції, що містить ключове слово очікування, щоб НЕ БУДЬ АСИНАК - це тому, що ключове слово очікує на призупинення обробки в функції, де знайдено ключове слово очікування. Якщо обробка в цій функції призупинена, вона, безумовно, НЕ асинхронна.

Отже, для розробників javascript та ECMAScript - будь ласка, виправте реалізацію очікування / асинхронізацію наступним чином ...

  • wait може використовуватись лише для функцій асинхронізації CALL.
  • чекання може з'являтися в будь-якому виді функції, синхронному або асинхронному.
  • Змініть повідомлення про помилку з "await є дійсним лише у функції async" на "await можна використовувати лише для виклику функцій асинхронізації".

Ви можете назвати це помилкою, якщо хочете, але я не згоден. Не існує такого коду, який "призупиняється" - скоріше, є код, який не може завершитися без результатів якогось зовнішнього процесу (як правило, io). Такий код слід називати "асинхронним", оскільки багато зовнішніх процесів мають бути спроможними запускатись одночасно (несинхронно), на відміну від VM javascript, який є однопоточним. Якщо у вас є багато функцій, які потрібно відновити, asyncце відображає той факт, що для багатьох ваших функцій потрібні результати зовнішніх процесів. На мою думку, це абсолютно канонічно.
Гершом

Варто також зазначити жахливий недолік обмеження користування awaitлише функціональними викликами: для одного зовнішнього процесу лише один пункт у коді JavaScript може бути повідомлений, коли цей процес завершиться. Наприклад, якщо вміст файлу потрібен для 3-х незалежних цілей, кожна мета повинна робити самостійно let content = await readTheFile();- це тому, що "обіцянки вмісту файлу" не можна чекати, лише "акт зчитування файлу та відновлення, як тільки це було читати ".
Гершом

Гаразд, не будемо називати це кодом, який призупиняється, або кодом, який неможливо виконати, а як щодо заблокованого очікування. Ось руб - функція, яка заблокована в очікуванні або яка не може виконати, - це функція, що містить ключове слово очікування. Це не асинхронна функція, яку викликають за допомогою ключового слова очікування. Отже, функцію, що містить ключове слово очікування, обов'язково НЕ слід позначати як асинхронність - вона заблокована в очікуванні, що є протилежною асинхронній.
Родні П. Барбаті

Щоб зробити це абсолютно зрозумілим, врахуйте наступне - очікування призначене для спрощення використання асинхронних функцій, роблячи їх схожими на синхронні (тобто це дозволяє мені робити речі в певному порядку). Примушення функції, що містить функцію очікування бути асинхронізацією, є повною помилкою - ви використовували функцію await, щоб вона стала синхронною. Функція, що містить функцію очікування, абсолютно, у будь-який можливий спосіб, НЕ функція асинхронізації !!!
Родні П. Барбаті

1
@ Гершом - це звучить розумно. Дякую!
Родні П. Барбаті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.