有谁能简单地解释一下node.js的微信支付异步通知回调和回调函数

posts - 12,&
comments - 3,&
trackbacks - 0
回调,是非常基本的概念,尤其在现今NodeJS诞生与蓬勃发展中变得更加被人们重视。很多朋友学NodeJS,学很久一直摸不着门道,觉得最后在用Express写Web程序,有这样的感觉只能说明没有学懂NodeJS,本质上说不理解回调,就不理解NodeJS。
NodeJS有三大核心:&-&CallBack回调&-&Event事件&-&Stream流
先来看什么不叫回调,下面是很多网友误认为的回调:
//代码示例1
//Foo函数意在接收两个参数,任意类型a,和函数类型cb,在结尾要调用cb()
function Foo(a, cb){
console.log(a);
// do something else
// Maybe get some parameters for cb
var param = Math.random();
cb(param);
//定义一个叫CallBack的函数,将作为参数传给Foo
var CallBack = function(num){
console.log(num);
Foo(2, CallBack);
以上代码不是回调,以下指出这里哪些概念容易混淆:&-&变量CallBack,被赋值为一个匿名函数,但是不因为它名字叫CallBack,就称知为回调&_&Foo函数的第二个形式参数名为cb,同理叫cb,和是不是回调没关系&_&cb在Foo函数代码最后被以cb(param)的形式调用,不因为cb在另一个函数中被调用,而将其称之为回调
直白来讲,以上代码就是普通的函数调用,唯一特殊一点的地方是,因为JS有函数式语言的特性,可以接收函数作为参数。在里可以用指向函数的指针来达到类似效果。
讲到这里先停一下,大家注意到本文的标题是解读异步、回调和EventLoop,回调之前还有异步呢,这个顺序对于理解很有帮助,可以说理解回调的前提,是理解异步。
说到异步,什么是异步呢?和分布、并行有什么区别?
回归原始,追根溯源是我们学习编程的好方法,不去想有什么高级的工具和概念,而去想如果我们只有一个浏览器做编译器和一个记事本,用plain JS写一段异步代码,怎么写?不能用事件系统,不能用浏览器特性。
小明:刚才上面那段代码是异步的吗?&老袁:当然不是,即便把Foo改为AsyncFoo也不是。这里比较迷惑的是cb(param)是在Foo函数的最后被调用的。&小明:好像觉得异步的代码,确实应该在最后调一个callback函数,因为之后的代码不会被执行到了。&老袁:异步的一个定义是函数调用不返回原来代码调用处,而cb(params)调用完后,依旧返回到Foo的尾部,即便cb(params)后还有代码,它们也可以被执行到,这是个同步调用。
Plain JS 异步的写法有很多,以经典的为例:
//代码示例2
// ====同步的加法
function Add(a, b){
return a+b;
Add(1, 2) // =& 3
// ====异步的加法
function LazyAdd(a){
return function(b){
return a+b;
var result = LazyAdd(1); // result等于一个匿名函数,实际是闭包
//我们的目的是做一个加法,result中保存了加法的一部分,即第一个参数和之后的运算规则,
//通过返回一个持有外层参数a的匿名函数构成的闭包保存至变量result中,这部是异步的关键。
//极端的情况var result = LazyAdd(1)(2);这种极端情况又不属于异步了,它和同步没有区别。
// 现在可以写一些别的代码了
console.log('wait some time, doing some fun');
// 实际生产中不会这么简单,它可能在等待一些条件成立,再去执行另外一半。
result = result(2) // =& 3
上述代码展示了,最简单的异步。我们要强调的事,异步是异步,回调是回调,他俩半毛钱关系都没有。
Ok,下面把代码改一改,看什么叫回调:
//代码示例3
//注意还是那个Add,精髓也在这里,随后说到
function Add(a, b){
return a+b;
//LazyAdd改变了,多了一个参数cb
function LazyAdd(a, cb){
return function(b){
//将Add传给形参cb
var result = LazyAdd(1, Add)
// doing something else
result = result(2); // =& 3
这段代码,看似简单,实则并不平凡。
小明:这代码给人的第一感觉就是脱裤子放屁,明明一个a+b,先是变成异步的写法就多了很多代码,人都看不懂了,现在的这个加了所谓的“回调”,更啰嗦了,最后得到的结果都是1+2=3,尼玛这不有病吗?&老袁:你只看到了结果,却不知道为什么人家这么写,这样写为了什么。代码示例2和3中,同样的Add函数,作为参数传到LazyAdd中,此时它是回调。那为什么代码示例1中,Foo中传入的cb不是回调呢?要仔细体会这句话,需要带状态的才叫回调函数,own state,这里通过闭包保存的a就是状态。&小明:我伙呆&老袁:现在再说为什么要有回调,单看输出结果,回调除了啰嗦和难于理解之外没有任何意义。但是!!!
现在说吧,CallBack的好处是:保证API不撕裂&也就是说,异步是很有需求的,处理的好能使计算效率提高,不至于卡在某处一直等待。但是异步的写法,我们看到了非常难看,把一个加法变成异步,都如此难看,何况其他。那么CallBack的妙处就是“保证API不撕裂”,代码中写到的精髓所在,还是那个Add,对,让程序员在写异步程序的时候,还能够像同步写法那样好理解,Add作为CallBack传入,保证的是Add这个方法好理解,作为API设计中的重要一个环节,保证开发者用起来方便,代码可读性高。
以NodeJS的readFile API为例进一步说明:&fs.readFile(filename, [options], callback)&有两个必填的参数filename和callback&callback是实际程序员要写代码的地方,写它的时候假设文件已经读取到了,该怎么写还怎么写,是API历史上的一次大进步。
//读取文件'etc/passwd',读取完成后将返回值,传入function(err, data) 这个回调函数。
fs.readFile('/etc/passwd', function (err, data) {
if (err) throw
console.log(data);
回调和闭包有一个共同的特性:在最终“回调 ”调用以前,前面所有的状态都得存着。
这段代码对于人们的疑惑常常是,我怎么知道callback要接收几个参数,参数的类型是什么?&答:是API提供者事先设计好的,它需要在文档中说明callback接收什么参数。
如代码3展示的那样,API设计者通过种种技巧,实现了回调的形式,这种种技巧写起来很痛苦。而fs.readFile看起来写的很轻巧,这是因为它不光包含异步、回调,还引入的新的概念EventLoop。
EventLoop是很早前就有的概念,如MFC中的消息循环,浏览器中的事件机制等等。
那为什么要有EventLoop,它的目的是什么呢?
我们用一个简单的伪示例,看没有EventLoop时是怎么工作:
//代码示例4
function Add(a, b){
return a+b;
function LazyAdd(a, cb){
return function(b){
var result = LazyAdd(1, Add)
// 假设有一个变量button为false,我们继续调用result的条件是,当button为true的时候。
var button = false;
// 常用的办法是观察者模式,派一个人不断的看button的值,
//只要变了就开始执行result(2), 当然得有别人去改变button的值,
//这里假设有人有这个能力,比如起了另外一个线程去做。
while(true){
if(button){
result = result(2);
result = result(2); // =& 3
所以如果有很多这样的函数,每一个都要跑一个观察者模式,在一定条件下看上去比较费计算。这时EventLoop诞生了,派一个人来轮询所有的,其他人都可以把观察条件和回调函数注册在EventLoop上,它进行统一的轮询,注册的人越多,轮询一圈的时间越长。但是简化了编程,不用每个人都写轮询了,提供API变得方便,就像fs.readFile一样简单明白,fs.readFile读取文件’/etc/passwd’,将其注册到EventLoop上,当文件读取完毕的时候,EventLoop通过轮询感知到它,并调用readFile注册时带的回调函数,这里是funtion(err, data)
换一个说法再说一遍:在特定条件下,单台机器上用空间换计算。原本callback执行了就不等了,存在一个地方,其他依赖它的,用观察着模式一直盯着它,各自轮询各自的。现在有人出来替大家统一轮询。
再换一个说法说一遍,重要的事情,换着方法说3遍:在单台机器上,统一轮询看上去比较省,也带来了很多问题,比如NodeJS中单线程情况下,如果一个函数计算量非常复杂,会阻碍所有其他的事件,所以这种情况要将复杂计算交给其他线程或者是服务来做。&我们一直在强调单台机器,如果是多台,用一个统一的人来轮询,就比较恐怖了,大家把事件都注册到一台机器上,它负责轮询所有的,这个namenode就容易崩溃。所以在多台机器上,又适合,每天机器各自轮询各自的,带来的问题是状态不一致了。好的,这才是程序有意思的地方,我们需要知道为什么发明EventLoop,也需要知道EventLoop在什么地方遇到问题。那些天才的程序员,又提出了各种一致性来解决这个问题,本文暂不讨论。
到目前为止,我们梳理了他们之间的关系:&异步 –& 回调 –& EventLoop&每一次进步都是上一个台阶,都需要智慧来解决。
回调还产生了很多问题,最严重的问题是callback hell回调地狱。
fs.readFile('/etc/password', function(err, data){
// do something
fs.readFile('xxxx', function(err, data){
//do something
fs.readFile('xxxxx', function(err, data){
// do something
这个例子可能不恰当,但也能理解,在类似这种情况会出现一层套一层的代码,可读性、维护性差。
在ES6 里面给出了Generator,来解决异步编程的问题。
阅读(...) 评论() &问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
看了好几篇文章,还是没能很彻底的搞明白异步编程
如这篇说到第一种"异步模式"编程的方法
function f1(callback){
    setTimeout(function () {
      // f1的任务代码
      callback();
    }, 1000);
我的问题就是:如果没有setTimeout,这个还是回调函数还是异步函数么?
包括后面说的几种方式,都有用setTimeout,是否可以理解为使用了setTimeout的就是异步编程??
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
异步编程的含义只有一个:
你不能在函数返回时,立即获得你想要执行的结果。
于是,你传入一个callback用以等待任务完成时,把结果告诉你。
setTimeout(xx,1000) 是模拟1秒后你所需要的指令完成任务告诉你结果的形式。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
我表哥要去我姑妈家帮我 拿回我的剃须刀
他拿回来之前 我不能 刮胡子
他拿回来之前 我可以 洗澡
剃须刀拿回来之后 我就可以刮胡子
洗澡和拿回我的剃须刀 是异步的
刮胡子是拿回剃须刀的 回调callback
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
js中setTimeout是在所有代码都单步执行完才执行里面的回调函数,可以把settimeout理解成一个事件。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
异步和回调没有关系,
同步的也有很多用回调的,
回调只是异步传输结果的一个方式,
只不过是二者同时出现的场合多一点,
并没有依存关系。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
不是。&--先回答问题,然后来瞎掰掰
不要扣概念,写你的代码,解决你的问题
不是说非得先熟读异步编程的4种方法5种模式6个思想什么的才能会异步编程的,那是给“已经会”的人看,让他们“精通”的
先写一个ajax拉数据反馈在页面上
然后写一个ajax同时发2个请求,合并结果反馈在页面上
那就是异步编程
等你写的系统里有10种不同的ajax请求/加载图片请求,有的串行有的并行,有的需要作为校验阻碍另一个动作,有的动作包含几个不同的请求,还有的需要循环发N个请求,你发现原来你的写法崩溃了完成不了功能了,这时候再来找你现在看的这些资料。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
如果是同步的,也就是说代码是这样的:
function f1(callback){
      // f1的任务代码
      callback();
代码2 调用f2同步的同步实现
那么调用完f1(f2)之后,f2会被立即执行。
但是你给出的代码是异步的,调用完f1(f2)之后,f2不会被立即执行。
为啥你把异步和回调搞混了呢,我认为是由于一般人不会写我给出的那段同步代码,如果想调用f2,你就直接调用就行了,干嘛还把它封装到f1函数中呢,显得很没必要了,但是这么写你也不能说语法是错的啊。但是如果你使用异步就不一样了,调用完setTimeout之后,如果你不加个回调,我都无法捕获到setTimeout啥时候执行,我要setTimeout函数处理完成之后要做下一步操作,怎么办?只能加一个回调函数了吧。
关于异步的详细介绍还可以参见我的博文:
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
看了下这篇文章,里面没有解释事件循环等机制,可以看一下篇文章
同步到新浪微博
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 Appnodejs中异步 - 简书
nodejs中异步
1 nodejs 中的异步存在吗?
现在有点 javascript 基础的人都在听说过 nodejs ,而只要与 javascript
打交到人都会用或者是将要使用 nodejs 。毕竟 nodejs 的生态很强大,与 javascript 相关的工具也做的很方便,很好用。
javascript 语言很小巧,但是一旦与 nodejs 中的运行环境放在一起,有些概念就很难理解,特别是异步的概念。有人会说不会啊,很好理解啊?不就是一个ajax请求加上一个回调函数,这个ajax函数就是能异步执行的函数,他在执行完了就会调用回调函数,我承认这个样做是很容易,早些时候我甚至认为在 javascript 中加了回调函数的函数都可以异步的,异步和回调函数成对出现。多么荒谬的理解啊!
直到有一天,我在写程序时想到一个问题:在 nodejs 中在不调用系统相关 I/O ,不调用 c++ 写的 plugin 的情况下,写一个异步函数?我查了资料,有人给我的答案是调用 setTimeout(fn,delay) 就变成了异步了。但是我还是不明白为什么要调用这样一个函数,这个函数的语义跟async完全不一样,为什么这样就行?
带着这个疑问,我查了很多资料,包括官方文档,代码,别人的blog。慢慢的理解,最后好像是知道了为什么会是这样,整篇文章就是对所了解东西的理解。恳请大家批评指正。
说明:nodejs 的文档是用的 ,而代码方面:nodejs 和 libuv 是用的 master 分支。
2 nodejs 的架构基础
在探索 nodejs 的异步时,首先需要对 nodejs 架构达成统一认识:
nodejs 有 javascript 的运行环境,目前它的实现是 chrome 的 V8 引擎。
nodejs 基于事件驱动和非阻塞 I/O 模型,目前它的实现是 libuv。
当前的 libuv 是多线程的,中有说明。
nodejs 在运行时只生成了一个 javascript 运行环境 的实例,也就是说 javascript 解释器只有一个。
nodejs 在主线程中调用 V8 引擎的实例执行 javascript 代码。
如果以上 5 点你不认同的话,那下面就不需要看了,看了会觉得漏洞百出。
上面的 5 点主要说明另一层意思了:
nodejs 的 javascript 运行环境可以换,在 nodejs 官方 github中 PR,可以看,微软想把 javascript 运行环境换成自己家的。
nodejs 的事件驱动和非阻塞 I/O 模型也可以换,目前来看 libuv 运行的不错,大家都很高兴。另外,你可能不知道,chromium 和 chrome 中使用了另一个实现 libevent2,证据在这里:。
nodejs 不是单线程,它是多线程程序,因为 libuv 就已经是多线程了。
因为是嵌入式 js 引擎,只能调用宿主环境中提供的方法。当前来说,nodejs 主要把 libuv 的 io/timer 接口提供给了 js 引擎,其他的没有提供(包括 libuv 的工作线程)。
nodejs 也没有提供给 js引擎 新建调用系统线程的任何方法,所以在nodejs中执行 javascript,是没有办法新开线程的。
js 引擎只有一个实例且在 nodejs 的主线程中调用。
nodejs 中存在异步,集中在 I/O 和 Timer 调用这一块,其他的地方没有。
js 引擎没有异步或者并行执行可能,因为 js 引擎是在 nodejs 的主线程调用,所以 js 引擎执行的 javascript 代码都是同步执行,没有异步执行。所以你想写出来一个不调用 I/O和 的异步方法,不可能。
那nodejs中常谈的异步和回调是怎么回事?
3 nodejs 中的回调和异步的关系是什么?
在 javascript 中使用回调函数可所谓登峰造极,基本上所有的异步函数都会要求有一个回调函数,以至于写 javascript 写多了,看到回调函数的接口,都以为是异步的调用。
但是真相是回调函数,只是javascript 用来解决异步函数调用如何处理返回值这个问题的方法,或这样来说:异步函数调用如何处理返回值这个问题上,在系统的设计方面而言,有很多办法,而 nodejs 选择了 javascript 的传统方案,用回调函数来解决这个问题。
这个选择好不好,我认为在当时来说,很合适。但随着 javascript 被用来写越来越大的程序,这个选择不是一个好的选择,因为回调函数嵌套多了真的很难受,我觉得主要是很难看,(就跟 lisp 的 )))))))))))) ),让一般人不好接受,现在情况改善多了,因为有了Promise。
回调函数与异步没有关系,只是在 javascript 中用来解决异步的返回值的问题,所以异步函数必须带一个回调函数,他们成对出现,让人以为有关系。
在 javascript 中有回调不一定是异步函数,而异步必须带一个回调函数。
4 nodejs 中怎样解决异步的问题?
前面也说了,nodejs 的 js 引擎不能异步执行 javascript 代码。那js中我们常使用的异步是什么意思的?
答案分为两部分:
第一部分:与I/O和timer相关的任务,js引擎确实是异步,调用时委托 libuv 进行 I/O 和timer 的相关调用,好了之后就通知 nodejs,nodejs 然后调用 js 引擎执行 javascript 代码;
第二部分:其它部分的任务,js 引擎把异步概念(该任务我委托别人执行,我接着执行下面的任务,别人执行完该任务后通知我)弱化成稍后执行(该任务我委托自己执行但不是现在,我接着执行下面的任务,该任务我稍后会自己执行,执行完成后通知我自己)的概念。
这就是 js 引擎中异步的全部意思。基本上等同我们常说的:我马上做这件事。不过还是要近一步解释一下第二部分:
任务不能委托给别人,都是自己做。
如果当前我做的事件需要很长时间,那我马上要做的事一直推迟,等我做了完手头这件事再说。
nodejs 中 js 引擎把异步变成了稍后执行,使写 javascript 程序看起来像异步执行,但是并没有减少任务,因此在 javascript 中你不能写一个需要很长时间计算的函数(计算Pi值1000位,大型的矩阵计算),或者在一个tick(后面会说)中执行过多的任务,如果你这样写了,整个主线程就没有办法响应别的请求,反映出来的情况就是程序卡了,当然如果非要写当然也有办法,需要一些技巧来实现。
而 js 引擎稍后执行中稍后到底是多久,到底执行哪些任务?这些问题就与 nodejs 中四个重要的与时间有关的函数有关了,他们分别是:setTimeout,setInterval,process.nextTick,setImmediate。下面简单了解一下这四个函数:
setTimeout 和 setInterval
setImeout 主要是延迟执行函数,其中有一个比较特别的调用:setTimeout(function(){/* code */},0),经常见使用,为什么这样使用看看后面。还有 setInterval 周期性调用一个函数。
setImmediate 和 process.nextTick
setImmediate 的意思翻译过来是立刻调用的意思,但是官方文档的解释是:
Schedules "immediate" execution of callback after I/O events' callbacks and before timers set by setTimeout and setInterval are triggered.
翻译过来大意就是:被 setImmediate 的设置过的函数,他的执行是在 I/O 事件的回调执行之后,在 计时器触发的回调执行之前,也就是说在 setTimeout 和 setInterval 之前,好吧这里还有一个顺序之分。
process.nextTick 可就更怪了。官方的意思是:
It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.
翻译过来大意就是:他运行在任何的 I/O 和定时器的 subsequent ticks 之前。
又多了很多的概念,不过别慌,在下面会讲 nodejs 的EventLoop,这里讲的很多的不理解地方就会在 EventLoop 中讲明白。
5 nodejs 中神秘的 EventLoop
EvevtLoop大体上来说就是一个循环,它不停的检查注册到他的事件有没有发生,如果发生了,就执行某些功能,一次循环通常叫tick。这里有讲,还有。
在 nodejs 中也存在这样一个 EventLoop,不过它是在 libuv 中。它每一次循环叫 tick。而在每一次 tick 中会有不同的阶段,每一个阶段可以叫 subTick,也就说是这个tick的子tick,libuv就有很多的子 tick,如I/O 和定时器等。下面我用一张图来表示一下,注意该循环一直在 nodejs 的主线程中运行:
+-------------+
+-----v----------------------+
| uv__update_time(loop)
+-----+----------------------+
+-----v----------------------+
| uv__run_timers(loop)
+-----+----------------------+
+-----v----------------------+
| uv__io_poll(loop, timeout) |
+-----+----------------------+
+-----v----------------------+
| uv__run_check(loop)
+-----+----------------------+
+-------------+
以上的流程图已经进行了裁减,只保留重要的内容,如果你想详细了解,可在 libuv/src/unix/core.cc,第334行:函数进行详细了解。
下面来解释一下各个阶段的作用:
uv__update_time是用来更新定时器的时间。uv__run_timers是用来触发定时器,并执行相关函数的地方。uv__io_poll是用来 I/O触发后执行相关函数的地方。uv__run_check的用处代码中讲到。
了解到 nodejs 中 EventLoop 的执行阶段后,需要更深一步了解在 nodejs 中 js引擎和EvevtLoop是如何被整合在一起工作的。以下是一些伪代码,它用来说明一些机制。
不过你需要知道在 nodejs 中 setTimeout、setInterval、setImmediate和process.nextTick都是系统级的调用,也就是他们都是c++ 来实现的。setTimeout和setInterval 可看看这个文件:。另外两个我再补吧。
class V8Engine {
let _jsVM;
V8Engine(){
_jsVM = /*js 执行引擎 */;
void invoke(handlers){
// 依次执行,直到 handlers 为空
handlers.forEach(handler,fun =& _jsVM.run(handler));
class EvenLoop {
let _jsRuntime =
let _callbackHandlers = []; 【1】
let _processTickHandlers = []; 【2】
let _immediateHandlers = []; 【3】
// 构造函数
EvenLoop(jsRuntime){
_jsRuntime = jsR
void start(){
where(true){
_jsRuntime.invoke(_processTickHandlers); 【4】
_processTickHandlers.clear();
update_time();
run_timer();
run_pool();
run_check();
if (process.exit){
_jsRuntime.invoke(_processTickHandlers); 【5】
_processTickHandlers.clear();
void update_time(){
更新 timer 的时间
void run_timer(){ 【6】
let handlers = getTimerHandler();
_callbackHandlers.push(handlers);
_jsRuntime.invoke(_callbackHandlers);
_jsRuntime.invoke(_processTickHandlers);
_callbackHandlers.clear();
_processTickHandlers.clear();
void run_pool(){
let handlers = getIOHandler();
_callbackHandlers.push(handlers);
_jsRuntime.invoke(_callbackHandlers);
_jsRuntime.invoke(_processTickHandlers);
_callbackHandlers.clear();
_processTickHandlers.clear();
void run_check(){
let handlers = getImmediateHandler();
_immediateHandlers.push(handlers);
_jsRuntime.invoke(_immediateHandlers);
_immediateHandlers.clear();
JsRuntime jsRuntime = new V8Engine();
EventLoop eventLoop = new EventLoop(jsRuntime);
eventLoop.start();
// 主线程中执行
以上代码是 nodejs 的粗略的执行过程,还想进一步了解,可以看这从入口函数看起:
按标号进行说明:
全局的回调事件先进先出队列,包括了 I/O 事件和 Timer 事件的回调对象。
全局的nextTick的回调对象先进先出队列。
全局的setImmediate的回调对象先进先出队列。
开始时会执行 nextTick的队列。
程序退出时会执行 nextTick的队列。
可以看出nextTick队列会在run_timer 和 run_pool之后执行。回到第三节说的nextTick的执行时机,看出来该队列确实会在 I/O 和 Timer 之前运行。在中特别说明如果你递归调用 nextTick 会阻 I/O 事件的调用就像调用了 loop。依照上面的伪代码,发现如果你递归调用nextTick,那nextTick回调对象先进先出队列就不会为空,js 引擎就一直在执行,影响之后的代码执行。
setImmediate 回调对象先进先出队列,每一次 tick 就执行一次。
可以从代码中看出这四个时间函数执行时机的区别,而setTimeout(fn,0)是在 _callbackHandlers的队列中,而setImmediate,还有 nextTick 都在不同的队列中执行。
总体来说,nextTick执行最快,而setTmmediate能保证每次tick都执行,而setTimeout是 libuv 的 Timber 保证,可能会有所延迟。
有人觉得得 process.nextTick 名不副实,得改个名字,变成 process.currentTick,没有通过,理由是太多的代码依赖这个函数了,没有办法改名字,。
如果你觉得 EventLoop 我说的不清楚,你还可以看看这篇博客:。
如果你觉得 setImmediate 和 nextTick 说的不清楚,可以看这:。
这个也可以:。
6 nodejs 回调和大数据与大计算量的解决方案
回调解决方案- promise
我相信你一但用了promise,你就回不去以往的回调时代,promise 非常好使用,强列推荐使用。如果你还想了解promise怎么实现的,我给你透个底,必不可少setTimeout这个函数,可以参考 ,还有也不错。
大数据与大计算量的解决方案 - 分片数据或者分片计算
如果要写一个处理数据量很大的任务,我想这个函数可以给你思路:
yielding processes
function chunk(array,process,context){
setTimeout(function(){
var item = array.shift();
process.call(context,item);
if (array.length &0){
setTimeout(arguments.callee,100);
如果要写一个计算量很大的任务,这个函数也可以给你思路:
var process = {
timeout = null,
// 实际进行处理的方法
performProcessing:function(){
// 实际执行的代码
// 初始处理调用的方法
process:function(){
clearTimeout(this.timeoutId);
var that =
this.timeoutId = setTimeout(function(){
that.performProcessing();
这两个函数是从第612-615页摘出来的,本质是不要阻塞了Javascript的事件循环,把任务分片了。
做服务器请求多了,使用
cluster 的方案就是多进程方案。cluster 能包证每个请求被一个 nodejs 实例处理。这样就能减少每个 nodejs 的处理的数据量。
从现在来看 nodejs 架构中对 js 引擎不支持线程调用是一个较大的遗憾,意味着在 nodejs 中你甚至不能做一个很大的计算量的事。不过又说回来,这也是一件好事。因为这样做的,使 javascript 变简单,写 js 不需要考虑锁的事情,想想在 java 中集合类加锁,你还要考虑同步,你还要考虑死锁,我觉得写 js 的人都很幸福。
同样的问题也出现在 python、ruby 和 php 上。这些语言在当前的主流版本(用c实现的版本)中都默认一把大锁 GIL,所有的代码都是主线程中运行,代码都是线程安全的,基本上第三方库也利用这个现实。导致的事实是它们都没有办法很好的利用现在的多核计算机,多么悲剧的事情啊!
不过好在,计算这事情,它们干不了,还有人来干,就是老大哥 c、c++还有 java 了。你没有看到分布式计算领域和大数据中核心计算被老大哥占领,其他是想占也占不了,不是不想占,是有心无力。
就目前的分析,我觉得说的很对。
当前 nodejs 的发展还是在填别的语言中经历过的坑,因为 nodejs 发展毕竟才七年的时间(2009年建立),流行也才是近几年的事情。不过 nodejs 的进步很快(后发优势),做一个轻量级的网页应用已经是继 python、ruby、php之后的另一个选择了,可喜可贺。
但是如果还要更近一步发展,那就必须解决计算这个问题。当前 javascript 对于这个问题的解决基本还是按着沿用 python、ruby 和 php 走过的路线走下去,采用单线程协程的方案,也就是 yield、async/wait 方案。在这之后,也基本上会采用多线程方案
worker 。从这样的发展来看,未来的 nodejs 与 python、ruby、php 是并驾齐驱的解决方案,不见得比
python、ruby 和 php 更好,它们都差不多,唯一不同的是我们又多了一种选择而已。
想到程序员在论坛上问:新手学习网站开发,javacript、python、ruby和 php 哪个好?我想说如果有师博他说什么好就学什么,如果没有师博那就学 javascript 吧,因为你不用再去学一门后端的语言了。}

我要回帖

更多关于 微信支付异步通知回调 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信