我一直在读node初学者 我看到了下面两段代码。

第一个问题:

    var result = database.query("SELECT * FROM hugetable");
    console.log("Hello World");

第二点:

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

我知道他们应该做什么,他们查询数据库来检索查询的答案。然后是console。log('Hello world')。

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

这两件作品之间的区别对我来说很模糊。输出是什么?

在谷歌上搜索异步编程也没什么用。


不同之处在于,在第一个示例中,程序将在第一行阻塞。下一行(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");

是:

查询完成 下一行 下一行 查询完成

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

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

你可以在这里阅读更多:单线程非阻塞IO模型如何在Node.js中工作


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


在同步情况下,console.log命令直到SQL查询执行完毕才执行。

异步情况下,将直接执行console.log命令。查询的结果稍后会被“回调”函数存储。


如果你在两个例子中都加上一行,这将变得更清楚:

var result = database.query("SELECT * FROM hugetable");
console.log(result.length);
console.log("Hello World");

第二点:

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

尝试运行这些程序,您将注意到第一个(同步)示例的结果。长度将在'Hello World'行之前打印出来。 在第二个(异步)示例中,结果。length将(很可能)打印在"Hello World"行之后。

这是因为在第二个例子中,数据库。查询在后台异步运行,脚本直接继续“Hello World”。console.log(result.length)只在数据库查询完成时执行。


这两种方法的区别如下:

同步方式: 它等待每个操作完成,之后只执行下一个操作。 如有查询: console.log()命令直到&才会执行,除非查询已经完成从Database中获取所有结果。

异步方式: 它从不等待每个操作完成,而是只在第一个GO中执行所有操作。一旦结果可用,就会处理每个操作的结果。 如有查询: console.log()命令将在Database.Query()方法之后很快执行。而数据库查询在后台运行,并在检索数据完成后加载结果。

用例

如果你的操作不是很繁重,比如从DB中查询大量数据,那么就使用同步方式,否则就使用异步方式。 在异步方式中,你可以向用户显示一些进度指示器,而在后台你可以继续你的繁重工作。这是GUI应用程序的理想场景。


该函数使第二个函数是异步的。

第一个命令迫使程序等待每一行完成运行,然后才能继续运行下一行。第二种方法允许每一行同时(独立地)运行。

允许异步或并发的语言和框架(js, node.js)对于需要实时传输的事情来说是很棒的。聊天,股票应用程序)。


首先,我意识到我回答这个问题有点晚了。

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

在同步情况下,每条语句在运行下一条语句之前完成。在这种情况下,程序完全按照语句的顺序求值。

这就是异步在JavaScript中的工作原理。JavaScript引擎中有两部分,一部分查看代码和队列操作,另一部分处理队列。队列处理发生在一个线程中,这就是为什么一次只能发生一个操作。

When an asynchronous operation (like the second database query) is seen, the code is parsed and the operation is put in the queue, but in this case a callback is registered to be run when this operation completes. The queue may have many operations in it already. The operation at the front of the queue is processed and removed from the queue. Once the operation for the database query is processed, the request is sent to the database and when complete the callback will be executed on completion. At this time, the queue processor having "handled" the operation moves on the next operation - in this case

    console.log("Hello World"); 

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

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

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

要了解更多,请阅读有关承诺的内容。承诺是处理异步操作结果的另一种方式。承诺的好处是它的编码风格更像同步代码。

许多库,如节点'fs',同时为某些操作提供同步和异步样式。在操作不需要很长时间,也不经常使用的情况下——比如读取配置文件的情况下——同步风格的操作将导致代码更容易阅读。


同步编程

像C, c#, Java这样的编程语言是同步编程,所以无论你写什么,都会按照你写的顺序执行。

-GET DATA FROM SQL.
//Suppose fetching data take 500 msec

-PERFORM SOME OTHER FUNCTION.
//Performing some function other will take 100 msec, but execution of other 
//task start only when fetching of sql data done (i.e some other function 
//can execute only after first in process job finishes).

-TOTAL TIME OF EXECUTION IS ALWAYS GREATER THAN (500 + 100 + processing time) 
msec

异步

NodeJs提供了异步特性,它本质上是非阻塞的,假设在任何需要时间的I/O任务(获取,写入,读取)中,NodeJs不会保持空闲状态并等待任务完成,它会开始执行队列中的下一个任务,每当该时间任务完成时,它会使用回调通知。 下面的例子会有所帮助:

//Nodejs uses callback pattern to describe functions.
//Please read callback pattern to understand this example

//Suppose following function (I/O involved) took 500 msec
function timeConsumingFunction(params, callback){
  //GET DATA FROM SQL
  getDataFromSql(params, function(error, results){
    if(error){
      callback(error);
    }
    else{
      callback(null, results);
    }
  })
}

//Suppose following function is non-blocking and took 100 msec
function someOtherTask(){
  //some other task
  console.log('Some Task 1');
  console.log('Some Task 2');
}

console.log('Execution Start');

//Start With this function
timeConsumingFunction(params, function(error, results){
    if(error){
      console.log('Error')
    }
    else{
      console.log('Successfull'); 
    }
  })

//As (suppose) timeConsumingFunction took 500 msec, 
//As NodeJs is non-blocking, rather than remain idle for 500 msec, it will start 
//execute following function immediately
someOtherTask();

简而言之,输出如下:

Execution Start
//Roughly after 105 msec (5 msec it'll take in processing)
Some Task 1
Some Task 2
//Roughly After 510 msec
Error/Successful //depends on success and failure of DB function execution

区别很明显,同步将花费超过600 msec(500 + 100 +处理时间),异步可以节省时间。


同步函数是阻塞的,而异步函数不是。在同步函数中,语句在运行下一个语句之前完成。在这种情况下,程序完全按照语句的顺序求值,如果其中一条语句花费了很长时间,则程序的执行将暂停。

Asynchronous functions usually accept a callback as a parameter and execution continue on the next line immediately after the asynchronous function is invoked. The callback is only invoked when the asynchronous operation is complete and the call stack is empty. Heavy duty operations such as loading data from a web server or querying a database should be done asynchronously so that the main thread can continue executing other operations instead of blocking until that long operation to complete (in the case of browsers, the UI will freeze).

最初发布在Github:链接


JS中的异步编程:

同步

停止执行进一步的代码,直到完成此操作。 因为它停止了进一步的执行,同步代码被称为“阻塞”。阻塞是指没有其他代码将被执行。

异步

它的执行被延迟到事件循环中,这是JS虚拟机中的一个构造,它执行异步函数(在同步函数堆栈为空之后)。 异步代码之所以称为非阻塞代码,是因为它不会阻塞进一步的代码运行。

例子:

//该函数是同步的 函数日志(参数){ console.log (arg) } 日志(1); //该函数是异步的 setTimeout(() => { console.log (2) }, 0); 日志(3)

示例记录1、3、2。 2被记录在最后,因为它在一个异步函数中,该函数在堆栈为空后执行。