Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 异步函数在Nodejs中的行为不符合预期_Javascript_Node.js_Async Await_Es6 Promise - Fatal编程技术网

Javascript 异步函数在Nodejs中的行为不符合预期

Javascript 异步函数在Nodejs中的行为不符合预期,javascript,node.js,async-await,es6-promise,Javascript,Node.js,Async Await,Es6 Promise,我有一个简单的代码: (async ()=>{ const five = await printHello() console.log(`five: ${five}`); })() async function printHello(){ console.log('Hello World') return 5; } console.log("App started"); 我的期望是,它应该打印: App started Hello World

我有一个简单的代码:

(async ()=>{
    const five = await printHello()
    console.log(`five: ${five}`);
})()

async function printHello(){
    console.log('Hello World')
    return 5;
}

console.log("App started");
我的期望是,它应该打印:

App started    
Hello World
five: 5
因为执行的匿名函数被标记为异步

但是,即使经过多次试验,它也会打印:

Hello World
App started
five: 5

有人能解释一下为什么会这样吗?

首先,你可以调用
printHello()

然后调用
console.log('helloworld')
哪个日志

然后
返回5它解决了承诺

然后您
const five=wait…
等待上面返回的承诺。这是一个微任务,因此它排队,异步函数进入睡眠状态

IIFE完成运行,因此外部功能继续执行
console.log(“应用程序启动”)应用程序启动的日志

然后外部函数完成,因此微任务被从队列中拉出,异步函数被唤醒

来自promise的解析值被赋值并
console.log(`five:${five}`)记录它


有关详细信息,请参阅。

async
函数返回承诺,但
async
函数中的同步代码立即执行(即同步执行)。
await
语句暂停代码执行,直到给出给它的承诺得到解决或拒绝


我总是比较
async
函数行为和
Promise
的行为<代码>执行器
函数立即被调用,即同步调用。

您的代码没有执行任何异步操作。
printHello
方法同步执行。 在函数前面加上
async
,只需确保它返回一个承诺即可。您可以用callback替换它,它将以相同的方式工作,因为callback将立即返回,而无需等待事件循环的下一个滴答声

因此,如果您希望代码按照您希望的方式运行,那么您必须使用setTimeout或setImmediate调用来包装代码

async function printHello() {
      setImmediate(() => {
        console.log('Hello World');
        return 5;
      });
  }

您的代码不是异步的。这就是问题所在。您需要返回一个始终异步的承诺

const users = [
  {
    id: 0,
    name: 'foo',
  },
  {
    id: 1,
    name: 'bar',
  }
];

function getUserById(id) {
  return new Promise((resolve, reject) => {
    setTimeout(function() {
      resolve(users.filter(user => user.id === id)[0]);
    }, 1000);
  });
}

async function getUser(id) {
  let name;

  await getUserById(id).then(function(user) {
    name = user ? user.name : null;
  });

  console.log(name);
}

getUser(0);
console.log('console');

所有人都给出了很多有用的答案,但我需要为此写一个答案,以帮助那些有着与我类似想法的人:仅仅将函数标记为异步[或将其包装为承诺]不会使CPU密集型代码在nodejs中以异步方式运行

在遇到这个问题之前,我的理解是,我们可以将异步放在函数之前,并将所有繁重的任务放在函数上。Aysnc将介绍如何在完成[返回]后让nodejs事件循环知道。我过去认为它通过繁殖线程在引擎盖下完成所有事情

但这种理解是错误的。节点是单线程的,如果您要编写代码的话。永远不要把任何繁重的任务放在nodej身上

考虑一下这个express应用程序:

const express = require('express')

const app = express()

app.use('/name/:name',(req,res)=>{
    if(req.params['name']==='John'){
        res.end(timeConsumingFunct(2000).toString())
    }else{
        res.end(timeConsumingFunct(10000).toString())
    }
})


function timeConsumingFunct(ms) {//simulating CPU intensive work
    var start = Date.now(),
        now = start;
    while (now - start < ms) {
      now = Date.now();
    }
    return ms/1000;
}

app.listen(3000,()=>{
    console.log('Server started at : http://localhost:3000')
})
const express=require('express'))
const app=express()
应用程序使用('/name/:name',(请求,请求)=>{
如果(请求参数['name']='John'){
res.end(timeConsumingFunct(2000).toString())
}否则{
res.end(timeConsumingFunct(10000).toString())
}
})
函数timeConsumingFunct(ms){//模拟CPU密集型工作
var start=Date.now(),
现在=开始;
同时(现在-开始<毫秒){
now=Date.now();
}
返回ms/1000;
}
app.listen(3000,()=>{
console.log('服务器启动于:http://localhost:3000')
})
现在,如果您访问:
http://localhost:3000/name/Tom
首先,然后
http://localhost:3000/name/John
在您的浏览器中,John先生至少需要等待12秒。 这是因为节点js是单线程的,无论您使用async还是承诺包装
timeConsumingFunct
,它都会挂起整个流

唯一真正的异步方法是使用子进程或WorkAPI,或者用C++编写。


作为JS编写的任何东西都是同步的,它会挂断所有请求,在您认为可以在nodejs中进行任何操作之前,请先了解这一点。

这可能是因为代码是自上而下执行的,因此在“应用程序启动”之前会显示“Hello World”消息。@Edric是的,但当您将其标记为async时,调用转到下一行,在事件循环的下一个刻度上执行async funct。那么立即执行的匿名异步函数呢?它应该创建微任务并排队等待下一个滴答声。”“应用程序已启动”表示当前勾号。纯形式的Promise会这样做,但
async
函数会暂停所有操作。所以最后一行等待IIFE完成。@user3769778-调用异步函数不会创建微任务。如果我在printHello中有一个非常大的计算,我希望它不会挂断我的事件循环,那么我有什么选项可以使它异步?我认为将任何函数标记为async都将使其异步,传递将转到下一行。将其包装在setImmediate或process.nextTick中将使其显示为异步,并且不会立即阻止执行。但是在子进程中执行它将是一个更好的主意(),虽然代码没有做任何异步的事情,但它仍然是异步的,因为承诺(也是从异步函数返回的承诺)保证了异步解析。你是对的,不过转移到另一个流程似乎是正确的方法。