同步和异步编程之间有什么区别(在node.js中)

Aze*_*rah 181 javascript asynchronous synchronous node.js

我一直在阅读nodebeginner 而且我遇到了以下两段代码.

第一个:

    var result = database.query("SELECT * FROM hugetable");
    console.log("Hello World");
Run Code Online (Sandbox Code Playgroud)

第二个:

    database.query("SELECT * FROM hugetable", function(rows) {
       var result = rows;
    });
    console.log("Hello World");
Run Code Online (Sandbox Code Playgroud)

我得到了他们应该做的事情,他们查询数据库以检索查询的答案.然后console.log('Hello world').

第一个应该是同步代码.第二个是异步代码.

两件作品之间的区别对我来说非常模糊.输出会是什么?

谷歌搜索异步编程也没有帮助我.

Sal*_*lab 215

不同之处在于,在第一个示例中,程序将在第一行中阻塞.下一行(console.log)必须等待.

第二个示例中,console.log将在处理查询时执行.也就是说,查询将在后台处理,而您的程序正在执行其他操作,一旦查询数据准备就绪,您将随心所欲地执行任何操作.

所以,简而言之:第一个例子将阻止,而第二个例子不会阻止.

以下两个例子的输出:

// Example 1 - Synchronous (blocks)
var result = database.query("SELECT * FROM hugetable");
console.log("Query finished");
console.log("Next line");


// Example 2 - Asynchronous (doesn't block) 
database.query("SELECT * FROM hugetable", function(result) {
    console.log("Query finished");
});
console.log("Next line");
Run Code Online (Sandbox Code Playgroud)

将会:

  1. Query finished
    Next line
  2. Next line
    Query finished

注意
虽然Node本身是单线程的,但有些任务可以并行运行.例如,文件系统操作发生在不同的进程中.

这就是Node可以执行异步操作的原因:一个线程正在执行文件系统操作,而主节点线程继续执行您的javascript代码.在像Node这样的事件驱动的服务器中,文件系统线程通知主节点线程某些事件,例如完成,失败或进度,以及与该事件相关的任何数据(例如数据库查询或错误的结果)消息)并且主节点线程决定如何处理该数据.

您可以在此处阅读更多相关信息:单线程非阻塞IO模型如何在Node.js中工作

  • 基本上,当我执行第一段代码时,它会执行以下操作:`request query.; 5秒后请求完成; console.log`; 当第二个执行时:`请求查询; 的console.log; 处理查询`; (9认同)
  • 异步示例是否可能输出与#1相同的内容?例如,`database.query`完成得如此之快,以至于当我们到达`console.log`时,任务已经完成. (4认同)
  • **简答**:是的@Abdul,你是对的.**长答案**:嵌套函数(回调)是顺序执行的方式,"一个接一个".但这在技术上并非"同步".匿名函数仍然在"阻塞操作完成时"执行,或者换句话说,"异步".Node.js可以在阻塞操作发生时执行其他功能.函数保持异步,只是你链接它们.同步功能块执行,这是关键. (4认同)
  • @TheBronx如果`console.log("下一行");`示例2中的`在匿名函数内部,所以就在`console.log("query finished")之后;`,这将意味着"下一行"将被打印在"查询完成"之后对吗?所以,如果我以嵌套方式拥有所有内容,那么一切都将以同步方式运行,因此我不必担心使用某些函数的同步版本.我的理解是正确的吗? (2认同)

San*_*nda 72

这两种方法的区别如下:

同步方式: 等待每个操作完成,之后只执行下一个操作.对于您的查询:console.log()除非查询已完成执行以从数据库获取所有结果,否则将不会执行该命令.

异步方式: 它永远不会等待每个操作完成,而是仅在第一个GO中执行所有操作.一旦结果可用,将处理每个操作的结果.对于您的查询:该方法console.log()后不久将执行该命令Database.Query().数据库查询在后台运行,并在检索完数据后加载结果.

用例

  1. 如果你的操作没有像从DB那里查询大量数据那么繁重,那么继续使用Synchronous方式,否则采用异步方式.

  2. 在异步方式中,您可以向用户显示一些进度指示器,而在后台,您可以继续进行重量级工作.这是GUI应用程序的理想方案.

  • 这是否意味着db.query(cmd,callback)正在并发运行(如在线程中)?它们是在同一时间运行吗? (2认同)

Mar*_*ijn 23

如果在两个示例中添加一行,这将变得更加清晰:

var result = database.query("SELECT * FROM hugetable");
console.log(result.length);
console.log("Hello World");
Run Code Online (Sandbox Code Playgroud)

第二个:

database.query("SELECT * FROM hugetable", function(rows) {
   var result = rows;
   console.log(result.length);
});
console.log("Hello World");
Run Code Online (Sandbox Code Playgroud)

尝试运行这些,您会注意到第一个(同步)示例,result.length将在'Hello World'行之前打印出来.在第二个(异步)示例中,result.length将(很可能)在"Hello World"行之后打印.

那是因为在第二个例子中,它database.query是在后台异步运行的,并且脚本继续直接使用"Hello World".在console.log(result.length)当数据库查询完成时才会执行.

  • @humanityANDpeace:这是异步访问的全部要点:你不知道什么时候会完成.也许这是一个荒谬的快速数据库,即使在Javascript到达"Hello World"行之前,数据库查询也会返回... (9认同)

Jay*_*Jay 18

首先,我意识到我迟到了回答这个问题.

在讨论同步和异步之前,让我们简要地看看程序是如何运行的.

同步情况下,每个语句在运行下一个语句之前完成.在这种情况下,程序将按语句的顺序进行精确评估.

这就是异步在JavaScript中的工作方式.JavaScript引擎中有两个部分,一部分用于查看代码并将操作排入队列,另一部分用于处理队列.队列处理在一个线程中发生,这就是为什么一次只能发生一个操作的原因.

当看到异步操作(如第二个数据库查询)时,将解析代码并将操作放入队列中,但在这种情况下,将注册回调以在此操作完成时运行.队列中可能已经有很多操作.处理队列前面的操作并从队列中删除.处理完数据库查询操作后,请求将被发送到数据库,完成后将在完成时执行回调.此时,具有"处理"操作的队列处理器在下一操作上移动 - 在这种情况下

    console.log("Hello World"); 
Run Code Online (Sandbox Code Playgroud)

数据库查询仍在处理中,但console.log操作位于队列的前面并得到处理.这是一个同步操作立即执行,导致输出"Hello World".一段时间后,数据库操作完成,然后只调用和处理向查询注册的回调,将变量结果的值设置为行.

一个异步操作可能会导致另一个异步操作,第二个操作将被放入队列中,当它到达队列的前面时,它将被处理.调用使用异步操作注册的回调是JavaScript运行时在完成操作时返回操作结果的方式.

知道哪个JavaScript操作是异步的简单方法是注意它是否需要回调 - 回调是在第一个操作完成时将执行的代码.在问题的两个例子中,我们只能看到第二种情况有一个回调,所以它是两者的异步操作.情况并非总是如此,因为处理异步操作的结果的风格不同.

要了解更多信息,请阅读承诺.Promise是另一种可以处理异步操作结果的方法.关于promises的好处是编码风格更像是同步代码.

许多库如节点'fs',为某些操作提供同步和异步样式.如果操作不需要很长时间并且没有经常使用 - 例如在读取配置文件的情况下 - 同步样式操作将导致代码更容易阅读.


the*_*abb 5

主要区别在于异步编程,否则您不会停止执行。您可以在发出“请求”时继续执行其他代码。


rel*_*ted 5

在同步情况下,在SQL查询完成执行之前,不会执行console.log命令.

在异步情况下,将直接执行console.log命令.然后,稍后将通过"回调"函数存储查询的结果.