我已经开发了几年的JavaScript,我根本不理解有关承诺的大惊小怪.
似乎我所做的只是改变:
api(function(result){
api2(function(result2){
api3(function(result3){
// do work
});
});
});
Run Code Online (Sandbox Code Playgroud)
无论如何,我可以使用像async这样的库,例如:
api().then(function(result){
api2().then(function(result2){
api3().then(function(result3){
// do work
});
});
});
Run Code Online (Sandbox Code Playgroud)
哪个代码更多,可读性更低.我没有在这里获得任何东西,它也不会突然神奇地"平坦".更不用说必须将事物转换为承诺.
那么,这里的承诺有什么大惊小怪?
我知道Node.js使用单线程和事件循环来处理请求,一次只处理一个(非阻塞).但是,如何工作,让我们说10,000个并发请求.事件循环将处理所有请求?这不会花太长时间吗?
我无法理解它是如何比多线程Web服务器更快的.据我所知,多线程Web服务器的资源(内存,CPU)会更昂贵,但它不会更快吗?我可能错了; 请解释这个单线程如何在大量请求中更快,以及在处理大量请求(例如10,000)时它通常会做什么(在高级别).
而且,那个单线程是否能够很好地扩展?请记住,我刚刚开始学习Node.js.
我在想它,这就是我提出的:
假设我们有这样的代码:
console.clear();
console.log("a");
setTimeout(function(){console.log("b");},1000);
console.log("c");
setTimeout(function(){console.log("d");},0);
Run Code Online (Sandbox Code Playgroud)
请求进来,JS引擎开始逐步执行上面的代码.前两个呼叫是同步呼叫.但是当谈到setTimeout方法时,它就变成了异步执行.但是JS立即从它返回并继续执行,这被称为Non-Blocking或Async.并继续致力于其他等
执行结果如下:
ACDB
所以基本上第二个setTimeout完成第一个,它的回调函数比第一个更早执行,这是有道理的.
我们在这里谈论单线程应用程序.JS引擎继续执行此操作,除非它完成第一个请求,否则它不会进入第二个请求.但好处是它不会等待阻塞操作,比如setTimeout解决所以它会更快,因为它接受新的传入请求.
但我的问题出现在以下几个方面:
#1:如果我们讨论的是单线程应用程序,那么setTimeouts当JS引擎接受更多请求并执行它们时,什么机制会处理?单个线程如何继续处理其他请求?什么工作,setTimeout而其他请求继续进入并执行.
#2:如果这些setTimeout函数在幕后执行,而有更多请求进入和执行,那么在幕后执行异步执行的是什么?我们谈到的这件事叫EventLoop什么?
#3:但是不应该将整个方法放入,EventLoop以便整个事件被执行并调用回调方法?这是我在谈论回调函数时所理解的:
function downloadFile(filePath, callback)
{
blah.downloadFile(filePath);
callback();
}
Run Code Online (Sandbox Code Playgroud)
但在这种情况下,JS引擎如何知道它是否是异步函数,以便它可以将回调EventLoop? Perhaps something like the放在C#中的async`关键字中,或者某种属性指示JS引擎将采用的方法是异步方法并应相应地对待.
#4:但是一篇文章说的与我猜测事情可能如何起作用完全相反:
Event Loop是一个回调函数队列.执行异步函数时,回调函数将被推入队列.在执行异步函数之后的代码之前,JavaScript引擎不会开始处理事件循环.
#5:这里有这个图像可能会有所帮助,但图像中的第一个解释是说第4个问题中提到的完全相同:

所以我的问题是要对上面列出的项目做一些澄清?
我很好奇所有的javascript回调是否都是异步的,或者只是在某些情况下是这种情况.此外,我确定是什么让javascript代码异步(或使用异步javascript的方法)在浏览器和nodejs之间有所不同,所以我想知道在每种情况下什么构成真正的异步javascript.
我的印象是,在下面的场景中,我实际上并没有编写异步代码.
function addOne(value){
value = value + 1;
return value;
}
function simpleMap(values, callback){
for(i = 0; i < values.length; i++){
val = values[i];
val = callback(val);
values[i] = val;
}
return values;
}
newValues = simpleMap([1,2,3], addOne);
Run Code Online (Sandbox Code Playgroud)
但是,例如,我知道jQuery的AJAX函数是真正异步的(不考虑现在可用的承诺).是什么让jQuery的AJAX异步?是否涉及XHR请求这么简单,在浏览器中,所有XHR请求都是异步的?
我对nodejs环境有同样的问题.节点中的某些东西只有在涉及文件i/o,process.nextTick,setTimeout或setInterval之类的东西时才能是异步的吗?为什么当我使用mongodb/mongoose进行数据库调用时,是异步的?幕后发生了怎样的事情呢?
异步"情况"是否由环境预先确定?或者是否有某种方法可以使自己的函数真正异步而不利用环境的非常特定的函数(例如xhr,节点中的文件io,process.nexttick等)?
以下是"practise01.js"文件中的代码,
function fn(name){
return f;
function f(){
var n = name;
console.log("Next TICK "+n+", ");
}
}
function myTimeout(time,msg){
setTimeout(function(){
console.log("TIMEOUT "+msg);
},time);
}
process.nextTick(fn("ONE"));
myTimeout(500,"AFTER-ONE");
process.nextTick(fn("TWO"));
myTimeout(500,"AFTER-TWO");
process.nextTick(fn("THREE"));
myTimeout(500,"AFTER-THREE");
process.nextTick(fn("FOUR"));
Run Code Online (Sandbox Code Playgroud)
运行上面代码的输出是
rahul@rahul:~/myPractise/PlainNodeJSPractise01/Process$ node practise01.js
Next TICK ONE,
Next TICK TWO,
Next TICK THREE,
Next TICK FOUR,
TIMEOUT AFTER-ONE
TIMEOUT AFTER-TWO
TIMEOUT AFTER-THREE
Run Code Online (Sandbox Code Playgroud)
现在我在"practise02.js"中不使用process.nextTick编写代码,如下所示,
function myTimeout(time,msg){
setTimeout(function(){
console.log("TIMEOUT "+msg);
},time);
}
function fn(name){
return f;
function f(){
var n = name;
console.log("Next TICK "+n+", ");
}
}
fn("ONE")();
myTimeout(500,"AFTER-ONE");
fn("TWO")(); …Run Code Online (Sandbox Code Playgroud) 从这里我发现node.js实现了非阻塞的i/o模型.但我不明白怎么做.
因为javascript是单线程的.单个线程如何执行I/O操作并同时执行进一步的过程.
我正在通过节点文档进行事件循环,我感到非常困惑.它说 -
timers: this phase executes callbacks scheduled by setTimeout() and
setInterval().
I/O callbacks: executes almost all callbacks with the exception of close callbacks, the ones scheduled by timers, and setImmediate().
idle, prepare: only used internally.
poll: retrieve new I/O events; node will block here when appropriate.
check: setImmediate() callbacks are invoked here.
close callbacks: e.g. socket.on('close', ...).
Run Code Online (Sandbox Code Playgroud)
然后在详细的轮询阶段,他们说它执行使用计时器调度的计时器,并且还处理轮询队列中的i/o事件.我的困惑是,我们已经有那些回调的计时器阶段和i/o回调阶段,然后轮询阶段完成的工作是什么.它还说线程可能在轮询阶段睡觉,但我没有正确.
我的问题是 -
在这一点上我很困惑.任何帮助将不胜感激.
我对Node js的架构和性能有疑问.
我已经完成了一些关于这个主题的阅读(包括Stack Overflow),我还有几个问题.我想做两件事:
Node具有单线程,异步事件处理架构
单线程 - 有一个事件线程可以调度异步工作(结果通常是I/O但可以是计算)并执行回调执行(即处理异步工作结果).
事件线程在无限的"事件循环"中运行,执行上述2个作业; a)通过调度异步工作来处理请求,以及b)注意先前的异步工作结果已准备好并执行回调以处理结果.
这里的常见类比是餐厅订单接收者:活动线程是一个超级快速的服务员,从餐厅接受订单(服务请求)并将订单发送到厨房准备(发送异步工作),但也注意到当食物准备就绪(异步结果)并将其送回表格(回调执行).
服务员不做任何食物; 他的工作是尽快从餐厅到厨房来回走动.如果他陷入餐厅的订单陷入困境,或者如果他被迫回到厨房准备其中一餐,系统就变得效率低下并且系统吞吐量受损.
异步 由请求(例如Web请求)产生的异步工作流在逻辑上是一个链:例如
FIRST [ASYNC: read a file, figure out what to get from the database] THEN
[ASYNC: query the database] THEN
[format and return the result].
Run Code Online (Sandbox Code Playgroud)
上面标有"ASYNC"的作品是"厨房工作","FIRST []"和"THEN []"代表服务员开始回调的参与.
像这样的链以3种常见方式以编程方式表示:
嵌套函数/回调
用.then()链接的承诺
async()异步结果的异步方法.
所有这些编码方法都非常相同,尽管asynch/await似乎是最干净的,并且使得异步编码的推理更容易.
问题
我的问题涉及使用OS支持的异步操作,实际执行异步工作的人,以及这种体系结构比"按每个请求生成一个线程"(即多个cooks)体系结构更高效的方式:
通过使用跨平台异步库libuv设计节点库是异步的,对吗?这里的想法是libuv为节点(在所有平台上)提供一致的异步I/O接口,但随后使用平台相关的异步I/O操作吗?在I/O请求"一直向下"到OS支持的异步操作的情况下,谁正在"做工作"等待I/O返回并触发节点?它是内核,使用内核线程吗?如果不是,谁?无论如何,这个实体可以处理多少个请求?
我已经读过libuv也在内部使用了一个线程池(通常是pthreads,每个核心一个?).这是为了"包装"不像"async"那样"完全向下"的操作,这样一个线程就可以用来等待同步操作了,所以libuv可以提供一个异步API吗?
关于性能,用于解释类似节点的体系结构可以提供的性能提升的通常说明是:画出(可能更慢和更胖)线程每请求方法 - 产生的延迟,CPU和内存开销一堆线程只是坐在等待I/O完成(即使他们没有忙碌等待)然后将它们拆除,节点很大程度上让它消失了,因为它使用了一个长期存在的事件线程来将异步I/O发送到OS /内核,对吗?但是在一天结束的时候,SOMETHING正在睡眠互联网并在I/O准备就绪时被唤醒...是否认为内核比用户线程更有效?最后,请问由libuv的线程池处理的情况怎么样...这似乎与每个请求线程的方法类似,除了使用池的效率(避免启动和拆除),但是在这种情况下,当有很多请求并且池有积压时会发生什么?...延迟增加,现在你做的比每个请求的线程更糟,对吧?
网上有很多文章将 NodeJS 演示为反应器模式的示例。这不是相当积极主动吗?
据我了解,两者的区别是:
例如在这篇文章中:
Reactor 模式是 Node.js 中非阻塞 I/O 操作的一种思想。该模式提供了一个与每个 I/O 操作关联的处理程序(对于 Node.js,是一个回调函数)。当生成 I/O 请求时,会将其提交给解复用器。
这实际上不是proctor的定义吗?
我正在开发NodeJS应用程序。有一个特定的RESTful API(GET),当用户触发该API时,它要求服务器执行大约10到20个网络操作才能从不同来源获取信息。所有这些网络操作都是异步回调,一旦它们全部完成,结果将由nodejs应用程序合并并发送回客户端。所有这些操作都是通过async.map函数并行启动的。
我只想了解一下,因为nodejs是单线程的,并且不使用多核计算机(至少不是没有集群),所以当节点有许多回调要处理时,节点如何扩展?回调的实际处理是取决于节点的单线程是否空闲,还是与主线程并行处理回调?
我问的原因是,我看到我的20个回调的性能从第一个回调降到了最后一个。例如,第一个网络操作(从10到20)需要141毫秒才能完成,而最后一个网络操作则需要约4秒钟(以从执行该功能到函数的回调返回值或一个错误)。它们都是相同的网络操作,因此命中相同的数据源,因此数据源不是瓶颈。我知道一个事实,即数据源响应单个请求所花费的时间不超过200ms。
我找到了这个线程,所以在我看来,一个线程需要处理所有回调和即将出现的新请求。
所以我的问题是,对于将触发许多回调的操作,优化其性能的最佳实践是什么?
不久前我开始使用node.js进行开发。最近,我深入 研究了节点的“事件循环”和异步机制。但我仍然不完全理解同步和异步回调之间的区别。
在这个来自node.js API的示例中,我理解为什么不清楚首先调用哪个函数。
maybeSync(true, () => {
foo();
});
bar();
Run Code Online (Sandbox Code Playgroud)
但是,如果我们有:
syncOrAsync(arg, () => {
if (arg) {
cb(arg);
return;
}
});
syncOrAsync(true, function(result) {
console.log('result');
});
console.log('after result);
Run Code Online (Sandbox Code Playgroud)
我不清楚为什么它们总是按同步顺序执行,尽管我做了一个回调函数,该函数应该在堆栈为空后由事件循环执行( console.log('after result') 完成)。我是否总是需要添加 process.nextTick(cb);才能实现异步?process.nextTick 和 process.nextTick 之间有什么区别setTimeout();?
我一直在思考像 React 这样的代码和库,它们可以自动对发生的事件做出反应,并且想知道所有这些是如何在 C++ 和机器代码的较低级别实现的。
我似乎无法想出任何其他方式可以使用 if not with while loop 在另一个线程上运行来实现诸如事件侦听器之类的东西。
那么这一切都在幕后吗?只是 while 一直循环下去?例如,RethinkDB 将自己宣传为具有repubsub库的“实时数据库” 。“订阅”方法是否只是在后台使用 while 循环实现的?我似乎无法找到任何相关信息。
像,插座之类的,也是。当计算机在端口上“侦听”套接字连接时,该计算机是否正在运行类似以下内容:
while(1) {
if (connectionFound) {
return True;
}
}
Run Code Online (Sandbox Code Playgroud)
或者有什么我想念的吗?
我浏览了下面的链接,了解单线程javascript及其异步性质
https://www.sohamkamani.com/blog/2016/03/14/wrapping-your-head-around-async-programming/
但是我仍然有一些问题,即javascript是单线程的,并且它总是以顺序方式向前移动,直到它完成执行.
每当我们调用具有回调函数时,该函数将在函数接收到响应后执行.在响应的等待时间内继续执行javascript代码.通过这种方式,执行顺序执行后如何在收到响应后恢复执行回调执行.这就像线程向后移动以进行回调执行.
执行线程应始终向前移动righy?
请澄清一下.
javascript ×11
node.js ×10
asynchronous ×4
callback ×3
event-loop ×2
architecture ×1
async-await ×1
bluebird ×1
events ×1
loops ×1
nonblocking ×1
promise ×1
q ×1
reactjs ×1
reactor ×1
rethinkdb ×1
synchronous ×1