首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么异步函数超过同步函数?

为什么异步函数超过同步函数?
EN

Stack Overflow用户
提问于 2018-09-11 04:34:30
回答 3查看 1.5K关注 0票数 3

我是NodeJS新手,我发现使用异步函数有点困难。我想找出这里的好处。下面是我对异步函数的理解。

,请您验证我在下面的每一项理解?

  1. 当独立操作(来自主程序流)被执行时,异步函数可以很好地使用。当主程序非常需要来自异步函数的数据/响应或各种独立的异步函数互连时,使用异步函数是不理想的。
  2. 在主程序流中依赖异步函数的输出结果是不好的。因为异步总是在主流之后执行。因此,如果需要在主流中执行某些函数,最好将其定义为同步的,而不是异步的。
  3. 调用独立异步函数时,通常使用承诺或回调调用后续操作(异步函数)。
  4. 我仍然可以在异步函数中调用同步函数。但是,如果我从同步函数调用异步函数,程序可能无法按预期工作,因为异步函数将只在最后执行?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-09-11 05:33:04

好吧,让我们一片一片地研究。作为一个基础,请记住Node.js是一个单线程进程,如果它需要执行blocking processes,例如读取文件(创建一个事件指针、读取文件句柄、设置文件路径、设置打开模式等)。最好使用异步函数,它在同一页的单独线程或线程的/池上执行。

1)当独立操作(来自主程序流)被执行时,异步函数可以很好地使用。当主程序非常需要来自异步函数的数据/响应或各种独立的异步函数互连时,使用异步函数是不理想的。

首先,我们不会将程序文件称为main program,因为在Node.js世界中没有子程序(我是而不是,谈论模块等)。

现在,当您说在迫切需要输出时不应该使用任何异步函数时,实际上是正确的。让我们以下面的例子为例:

代码语言:javascript
运行
复制
...
const data = readFile( 'fileName', ( data, output ) => {
    ...
} );
console.log( data ); // this might be null or undefined

在上述情况下,我们将不使用异步函数(在传统意义上)。然而,在ES6和更高版本中,我们得到了可爱的async/await范例:

代码语言:javascript
运行
复制
const data = await readFile( 'filename' );

await使调用伪同步:它的行为类似于一个async函数,但是会有一个暂停的线程等待输出。所以,在这里,你是绝对正确的!让我们继续吧。

2)在主程序流中依赖异步函数输出的结果是不好的。因为异步总是在主流之后执行。因此,如果需要在主流中执行某些函数,最好将其定义为同步的,而不是异步的。

在这里,您说async在主流之后运行。现在,认为是不正确的。让我画一个线程评估和执行的简单图片:

比方说,有两个sync函数A()B(),它们对应的线程是th__Ath__B,它们将如下所示:

代码语言:javascript
运行
复制
th__a ---> th__b

如果它们是按A()顺序发射的,那么B()。它等待第一个同步(或阻塞)进程的计算,然后执行第二个进程。很明显,这并不是在整个执行结束之后。

但是,如果它们现在是异步函数,它们将并行执行。假设A()是一个同步函数,而B()是一个异步函数,具有与上面相同的线程名,执行如下所示:

代码语言:javascript
运行
复制
th__a     ----
- - th__b   ->

其中-代表时钟周期,->代表执行的结束。我们可以看到,A()被触发,然后,在一个新线程上,B()被触发。

我想这是有道理的。现在,再次返回,如果您需要立即使用它们,同时作为异步调用,则使用await

3)调用独立异步函数时,通常使用许诺或回调调用后续操作(异步函数)。

绝对一点儿没错。

比如说,我们定义了一个函数sayHello()

代码语言:javascript
运行
复制
const sayHello = () => {
    const P = Q.defer();

    // P.resolve(data);

    // or if there is an exception 
    // P.reject(error);

    return p.promise;
 };

其中Q是优秀的承诺库。我们可以称之为:

代码语言:javascript
运行
复制
sayHello.then( ( data ) => {
    console.log( data ); // P.resolve(..) is working here since the promise was successful.
} ).catch( ( err ) => {
    console.log( err ); // P.reject(..) is working here since there was a problem.
} );

或者您也可以像fs.readFile(...)那样使用回调

代码语言:javascript
运行
复制
fs.readFile( 'fileName', ( e, data ) => {
    if( e ) { return console.log( e ); } // error was handled
    // perform subsequent functions here with data
} );

4)我仍然可以在异步函数中调用同步函数,但是如果从同步函数/操作调用异步函数,程序可能无法按预期工作,因为异步函数将只在最后执行?

不怎么有意思。请参阅第(2)点。是关于线的。不是静态过程。您可以很好地调用异步函数中的同步函数,它将完美地工作。

当您读取文件时,假设您希望通过\n或新行拆分数据:

代码语言:javascript
运行
复制
...
if( e ) { return console.log( e ); }
const dataLines = e.split( '\n' ); // this will work brilliantly 
...

我希望这一切都清楚了!

票数 5
EN

Stack Overflow用户

发布于 2018-09-11 04:55:37

您似乎还没有研究过javascript事件循环。这里是一篇很好的文章,您可以阅读。通常在javascript异步函数中,用于避免进程的IO (输入/输出)延迟,比如浏览器上的HTTP调用、NodeJS上的文件读取,而不是执行延迟或并行执行,因为javascript进程是单线程的。如果您想学习更多关于非阻塞IO的知识,这里是我写过的一篇关于它是如何工作的文章,它似乎回答了您所有的问题。

在编写异步方法时,正如您前面提到的,很难跟踪每个回调,然后再执行一个回调,然后一次又一次地执行,这在javascript中称为回调地狱。对于这一点,await async不过是一个简单的解决方案。

票数 1
EN

Stack Overflow用户

发布于 2018-09-11 14:09:26

在javascript/node应用程序中实际使用异步功能是在处理网络请求和/或I/O操作(或可能需要很长时间的事情)时发挥作用的。

--网络呼叫示例

以聊天应用程序为例。客户端(您)向某人发送消息。该消息被发送到服务器或直接发送给收件人(P2p),以便根据通信模型进行进一步处理。您还希望向其他人发送另一条消息;person B。但是,如果不异步处理请求,客户端(您)可能必须等待一段不确定的时间;取决于您的网络速度、收件人的网络速度、网络超时时间或任何其他负责因素。

考虑到你必须等待两个单位的时间才能完成你的请求。

代码语言:javascript
运行
复制
time:        1                2             3         4                   5        
action: SendToA(message)     waitA         waitA     ResponseFromA       SendToB(message)

但是如果相同的请求是异步的。您发送由客户机(用于p2p通信)或客户机和服务器(用于客户机/服务器)通信异步处理的请求。这就是浏览器中实际发生的情况。浏览器异步处理请求,以便在等待请求完成时,浏览器代码的任何其他部分都不会被卡住。

代码语言:javascript
运行
复制
time:        1                    2                         3                    4                   5          
action: SendToA(message)  waitA/SendToB(message)         waitA/waitB        ResponseFromA       ResponseFromB

因此,在同步情况下,只有一个请求在5个时间单元内成功,而在异步情况下,只有两个请求在5个时间单元内成功。

注意到:实际的实现可能以时间为单位推迟,这只是实际发生的事情的一般想法。

I/O读写示例

I/O读/写非常类似于网络调用;也就是说,完成它需要时间。假设您的应用程序有两个表,从两个不同的文件中读取并填充每个表。如果同步处理这两个请求,则总体执行会出现大量延迟,而异步则会有所帮助。

同步:

代码语言:javascript
运行
复制
time:        1                       2             3           4                       5        
action: ReadFromFileA(message)     waitA         waitA     ResponseFromA       ReadFromFileB(message)

对于异步:

代码语言:javascript
运行
复制
time:        1                   2                3           4                       5        
action: ReadFromFileA()     ReadFromFileB()   waitA/waitB     ResponseFromA       ResponseFromB

这是对异步调用/函数可以做什么的一个非常普遍的解释。然而,异步并不总是所要做的事情。正如您在问题中提到的,有时确实需要同步调用/函数。

打印是一个非常特殊的操作,必须是同步的。不能异步打印两份文件。

相关的函数也必须是同步的。

所有这一切,异步是一个非常强大的功能,如果使用correctly.There几乎总是可能的异步性在一个实时应用程序。如果你的应用程序不使用它,你的用户可能会抱怨你的应用程序中的坏用户。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52268715

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档