await只能在异步函数中使用。

354

我在lib/helper.js中写下了这段代码:

var myfunction = async function(x,y) {
   ....
   return [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;

我遇到了一个错误:

await is only valid in async function

问题是什么?


9
问题在于 await 只能在 async 函数内部使用。也就是说,await 使函数变成异步函数,因此必须声明为异步函数。 - Pointy
当前错误是什么? - acdcjunior
1
仍然是相同的错误,SyntaxError:await只能在异步函数中使用。 - j.doe
你需要分享更多关于你的代码的上下文信息。 - Ele
我想象一下(很难说,因为您的编辑现在使问题无效了),您所做的只是将问题提升到了更高的级别。如果您正在使用async/await,那么您需要在整个过程中都使用它。您不能从同步方法调用异步方法并期望它能正确运行。 - Liam
2
可能是一个重复问题:如何从异步调用中返回响应? - Liam
14个回答

410
错误并不是指向 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');
})();


CORRECT

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 我添加了一段代码片段。 - Orelsanpls
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函数(尽管有些人仍会选择这样做,以便更加明确)。 - Gershom Maes
@Gershom,你说得完全正确,这是正确的最佳方式,我会指出它。 - Orelsanpls

37

使用await,其执行上下文需要具有async的特性

正如所说,您需要定义您愿意在其中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')
}

解释:

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

想知道底层的运作方式?

await 用于消费返回 promise/future / task 的方法或函数,而 async 则表示该方法或函数可以使用 await

此外,如果您熟悉 promises,那么 await 实际上执行的是 promise/resolve 的相同过程。创建一条 promise 链并在 resolve 回调中执行下一个任务。

如需更多信息,请参阅MDN DOCS


2
即使在 start 函数中使用了 async,我仍然收到错误信息。 - j.doe
我不确定你错在哪里并且出现了这个错误,解决这个错误并没有什么复杂的解释。 - Satyam Pathak
这是一个恰当的回答,实际上解释了其中的原因。我投了赞成票。 - linehrr

17
当我遇到这个错误时,结果发现我的“async”函数内部调用了map函数,因此这个错误信息实际上是指map函数没有被标记为“async”。我通过将“await”调用从map函数中取出并想出其他方法来获得预期行为来解决了这个问题。
var myfunction = async function(x,y) {
    ....
    someArray.map(someVariable => { // <- This was the function giving the error
        return await someFunction(someVariable);
    });
}

4
对我而言,这是一个问题。我用for循环替换了map函数,这对我来说是一个简单的解决方案。然而,这个解决方案可能并不适用于你的代码,具体情况要看你的代码而定。 - Thomas
7
иҜ·жіЁж„ҸпјҢжӮЁиҝҳеҸҜд»ҘдҪҝз”ЁsomeArray.map(async (someVariable) => { return await someFunction(someVariable)})иҝҷз§Қж–№ејҸгҖӮиҜҘиҜӯеҸҘзҡ„дҪңз”ЁжҳҜе°ҶдёҖдёӘж•°з»„дёӯзҡ„жҜҸдёӘе…ғзҙ дј йҖ’з»ҷдёҖдёӘејӮжӯҘеҮҪж•°someFunction()иҝӣиЎҢеӨ„зҗҶпјҢ并иҝ”еӣһеӨ„зҗҶеҗҺзҡ„з»“жһңгҖӮ - ptim
1
你代码中的 await 是误导性的,因为 Array.map 不会将函数处理为异步函数。为了更加清晰明确,在 map 函数完成后,someFunction 将全部处于挂起状态。如果你想要真正等待函数执行完毕,你需要写成:await Promise.all(someArray.map(someVariable => someFunction(someVariable))) 或者 await Promise.all(someArray.map(someFunction))) - Orelsanpls

15

如果您正在编写Chrome扩展程序并且在代码根目录中遇到此错误,可以使用以下“解决方法”进行修复:

async function run() {
    // Your async code here
    const beers = await fetch("https://api.punkapi.com/v2/beers");
}

run();

基本上,您需要将异步代码放入一个async函数中,然后调用该函数而不等待它。


你知道为什么在Chrome中会发生这种情况吗? - user2268997

15

我遇到了同样的问题,以下代码块也出现了相同的错误信息:

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

问题在于方法getCommits()是异步的,但我正在将它传递给由Promise生成的repo参数。因此,我不得不像这样添加async关键字:async(repo),然后它开始工作了:

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

非常感谢!我两个小时后才看到了这个答案 XD - Eder Armando Anillo Lora
请注意,使用 async.forEach() 经常不能很好地配合使用。例如,在你的循环内部第一个 await 后面的代码之后,.forEach() 后面的代码将会运行。并且在此示例中也不能保证 displayCommit() 的调用顺序与元素的循环顺序相同。请参考 Using async/await with a forEach loop - Ivar

8

4

async/await是处理Promise的机制,我们有两种方法可以做到这一点。

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

            });

或者我们可以使用 await 等待 promise 先被履行,这意味着它可能被拒绝或被解决。
现在,如果我们想在函数内使用 await(等待 promise 履行),那么容器函数必须是异步函数,因为我们正在异步等待 promise 被履行 || 听起来合理吧?
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);
        });

是的,它确实如此。为了调用异步函数,您需要在调用者中使用await,并且因为您需要在那里等待,所以该函数也必须是异步的。基本上,如果您想使用async/await,您将不得不在整个应用程序中对所有函数都使用它。 - Rodney P. Barbati

3

当前的async/await实现仅支持在async函数内使用await关键字。更改您的start函数签名,以便您可以在start内部使用await

 var start = async function(a, b) {

 }

对于那些感兴趣的人,顶层await提案目前处于第二阶段:https://github.com/tc39/proposal-top-level-await


3
很不幸,这基本意味着你需要在整个代码库中将所有函数都变成异步的。因为如果你想使用await,你必须在一个异步函数中使用它,这意味着你必须在调用它的函数中等待该函数的响应 - 这又意味着所有的函数都需要变成异步函数。对我来说,这意味着await async还没有准备好投入使用。当你可以使用await调用异步方法,而不管当前函数是同步的还是异步的,那么它就准备好了。 - Rodney P. Barbati
1
每个函数如果通过任何间接依赖于外部进程的结果,必须且应该使用async进行定义 - 这就是async的整个意义所在。 - Gershom Maes
您可通过--experimental-repl-await选项,在Node repl中使用该语法。 - Lodz

2

在这篇好文章中找到了下面的代码:使用Axios在Node中进行HTTP请求

const axios = require('axios')

const getBreeds = async () => {
  try {
    return await axios.get('https://dog.ceo/api/breeds/list/all')
  } catch (error) {
    console.error(error)
  }
}

const countBreeds = async () => {
  const breeds = await getBreeds()

  if (breeds.data.message) {
    console.log(`Got ${Object.entries(breeds.data.message).length} breeds`)
  }
}

countBreeds()

或者使用Promise:

const axios = require('axios')

const getBreeds = () => {
  try {
    return axios.get('https://dog.ceo/api/breeds/list/all')
  } catch (error) {
    console.error(error)
  }
}

const countBreeds = async () => {
  const breeds = getBreeds()
    .then(response => {
      if (response.data.message) {
        console.log(
          `Got ${Object.entries(response.data.message).length} breeds`
        )
      }
    })
    .catch(error => {
      console.log(error)
    })
}

countBreeds()

2
如果您在foreach中调用了异步函数,请将其更新为for loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接