等待仅在异步功能中有效


128

我写了这段代码 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使函数异步,因此必须这样声明。
尖尖的

当前错误是什么?
acdcjunior

仍然相同,SyntaxError:await仅在异步函数中有效
j.doe

您需要共享有关代码的更多上下文。
Ele

Answers:


157

错误不是指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();



我利用这个问题的机会来告诉你关于一种已知的反模式的用法awaitreturn 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)

是否有与“返回等待”有关的性能问题?


但这不起作用,我更新了代码。我仍然遇到相同的错误
j.doe

@ j.doe我添加了一个片段
了GrégoryNEUT

2
谢谢,我发现了我的问题。我试图在回调函数start()函数中执行此操作。解决方案是:const start = async function(a,b){task.get(options,async function(error,result1){{const result = await myfunction('test','test');
j.doe

考虑到Node是单线程的。它不是减少每分钟的请求数,也增加了填充请求之间的延迟。
瑞沙卜·迪曼

1
值得一提的是,在“ CORRECT”示例中,没有必要将其声明start为一个async函数(尽管为了明确起见,无论如何都会选择这样做)
Gershom

11

当我收到此错误时,事实证明我在“异步”函数中调用了map函数,因此此错误消息实际上是指未标记为“异步”的map函数。通过从map函数中取消“ await”调用,并提出了一些其他获得预期行为的方法,我解决了这个问题。

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

2
这是我的问题。我用for循环替换了map函数,这对我来说是一个简单的解决方案。但是,此解决方案可能不适用于您,具体取决于您的代码。
托马斯

5
仅供参考,您也可以做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égoryNEUT

9

要使用await它,它的执行上下文必须是async自然的

就像说的那样,您需要先定义自己executing context愿意去做的事情的性质await

只需放在执行任务asyncfn声明之前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标记为能够使用等待。

另外,如果您熟悉promisesawait实际上会执行相同的Promise / Resolve过程。创建承诺链并在其中执行下一个任务resolve回调中。

有关更多信息,请参阅MDN DOCS


即使启动函数中出现了异步,我
仍然

我不确定您在哪里丢失此错误,没有解决此类错误的复杂解释。
萨蒂扬·帕塔克

这是一个正确的答案,并且实际上解释了下划线的原因。投票。
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


1
不幸的是,这基本上意味着您将必须在整个代码库中使所有函数异步。因为如果要使用await,则必须在异步函数中执行此操作,这意味着您必须在调用该函数的函数中等待该函数的响应-再次,这意味着您所有的函数都需要变为异步状态。对我来说,这意味着尚未准备好使用await异步。当您可以使用await调用异步方法时,无论当前函数是同步还是异步,它都准备就绪。
Rodney P. Barbati

1
通过任何级别的间接依赖于外部过程结果的每个功能都必须并且应该与被定义async-这是整个点async
Gershom

您当前可以在使用--experimental-repl-await选项的节点repl中使用它。
罗兹

3

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

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);
});

0

异步/等待是处理诺言的机制,我们可以通过两种方式来实现它

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”进行的。


1
实际上,await不等待结果-它立即返回一个诺言。这正是我试图传达的。如果await实际上是在等待,并且没有将控制权返回给调用者,那么任何包含await关键字的函数都将无法标记为异步。但除此之外,我们还有任何包含await的函数或调用一个函数,而最终调用包含await的函数必须是异步的。基本上,如果您甚至调用await一次-所有功能都必须标记为异步。
Rodney P. Barbati

-5

是的,await / async是一个很棒的概念,但是实现已完全中断。

无论出于何种原因,已经实现了await关键字,使其只能在async方法中使用。实际上,这是一个错误,尽管您在此处看不到它所指的错误。解决此错误的方法是实现await关键字,以便无论调用函数本身是同步还是异步的,它都只能用于调用异步函数。

由于该错误,如果在代码中的某个位置使用await调用真正的异步函数,则必须将所有函数标记为异步,并且所有函数调用必须使用await。

从本质上讲,这意味着您必须将promise的开销添加到整个应用程序中的所有函数中,其中大多数不是,并且永远不会是异步的。

如果您真的考虑过,在函数中使用await应该要求包含await关键字的函数不要同步-这是因为await关键字将暂停在找到await关键字的函数中的处理。如果该函数中的处理被暂停,那么它肯定不是异步的。

因此,对于javascript和ECMAScript的开发人员-请按以下步骤修复await / async实现...

  • await只能用于CALL异步功能。
  • 等待可以以任何一种功能出现,同步或异步。
  • 将错误消息从“等待仅在异步函数中有效”更改为“等待只能用于调用异步函数”。

如果愿意,可以将其称为错误,但我不同意。没有代码会“暂停”,而是没有一些外部过程(通常是io)的结果才能完成的代码。此类代码应称为“异步”,因为与单线程的javascript VM相比,许多外部进程应该能够同时(非同步)运行。如果您有许多需要重构async的功能,则表明您的许多功能需要外部过程的结果。我认为这完全是规范的。
Gershom

还值得一提的是,限制await只能用于函数调用的可怕缺点:对于单个外部进程,当该进程完成时,只能在JavaScript代码中通知单个点。例如,如果出于3个独立目的需要文件的内容,则每个目的都需要独立执行let content = await readTheFile();-这是因为无法等待“文件内容的承诺”,而仅是“读取文件并在文件恢复后恢复的行为”。读”。
Gershom

好的,我们不要称其为暂停代码或无法完成的代码,而是阻塞等待。麻烦的是-阻塞等待或无法完成的函数是包含await关键字的函数。使用await关键字调用的不是异步函数。因此,绝对不应该将包含await关键字的函数标记为异步-它被阻塞等待,这与异步相反。
Rodney P. Barbati

为了使这一点完全清楚,请考虑以下内容-等待通过使异步函数看起来像是同步的(即,它允许我按特定的顺序执行操作)来简化异步函数的使用。强制包含await的函数异步是完全不正确的-您使用await使其变为同步。在所有可能的方式中,包含等待的函数绝对不是异步函数!!!
Rodney P. Barbati

1
@Gershom-听起来很合理。谢谢!
Rodney P. Barbati
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.