同步和异步编程(在node.js中)的区别是什么?

我一直在读 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')

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

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

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

204720 次浏览

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

是:

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

这就是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"行之后

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

这两种方法的区别如下:

< >强同步方式: 它等待每个操作完成,之后只执行下一个操作。 如有查询: console.log()命令直到&

.

.

.

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

用例

  1. 如果你的操作不是很繁重,比如从DB中查询大量数据,那么就使用同步方式,否则就使用异步方式。

  2. 在异步方式中,你可以向用户显示一些进度指示器,而在后台你可以继续你的繁重工作。这是GUI应用程序的理想场景。

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

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

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

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

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

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

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

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

    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 +处理时间),异步可以节省时间。

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

异步函数通常接受回调作为参数,并在异步函数被调用后立即在下一行继续执行。只有在异步操作完成且调用堆栈为空时才调用回调。繁重的操作,如从web服务器加载数据或查询数据库,应该异步完成,以便主线线程可以继续执行其他操作,而不是阻塞,直到长时间的操作完成(在浏览器的情况下,UI将冻结)。

最初发布在Github: 链接

JS中的异步编程:

同步

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

异步

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

例子:

// This function is synchronous
function log(arg) {
console.log(arg)
}


log(1);


// This function is asynchronous
setTimeout(() => {
console.log(2)
}, 0);


log(3)

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