2014年10月12日星期日

setTimeout的若干坑 - LonelyClick

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
setTimeout的若干坑 - LonelyClick  阅读原文»

第一坑:作用域

首先,有一个关于this的面试题,是这样的:


var fullname = 'John Doe';
var obj = {
fullname: 'Colin Ihrig',
prop: {
fullname: 'Aurelio De Rosa',
getFullname: function() {
return this.fullname;
}
}
};
console.log(obj.prop.getFullname());
var test = obj.prop.getFullname;
console.log(test());

主要考察的是this的指向,很明显,this是根据上下文的执行环境决定的,obj.prop.getFullname()的上下文是obj.prop,而执行var test = obj.prop.getFullname,实际上是window.test = obj.prop.getFullname; 所以window.test()的this指向的是window,该题的结果为:先打印出Colin Ihrig,然后再打印出John Doe。但是,但问题还没有结束,变个形:


var fullname = 'John Doe';
var obj = {
fullname: 'Colin Ihrig',
prop: {
fullname: 'Aurelio De Rosa',
getFullname: function() {
setTimeout(function () {
console.log(this.fullname);
},100);
return this.fullname;
}
}
};
console.log(obj.prop.getFullname());
var test = obj.prop.getFullname;
console.log(test());

那现在呢,在setTimeout中会弹出什么?当时确实有那么几毫秒难住了我,一想,这个setTimeout,不就相当于window.setTimeout嘛,所以,setTimeout中的this依旧指向window,打印的结果为:Colin Ihrig。

第二坑:执行顺序

还是一个面试题,如下:


setTimeout(function(){ t = false; }, 1000);
while(true){}
alert('end');

问题来了:alert是否能够弹出?为什么?问题的答案是:不能弹出来,因为JS的单线程的,永远的单线程。在while(true)的时候陷入了死循环,就再先出不来了。关于JS的执行机制,请看这里:JavaScript 运行机制详解:再谈Event Loop这篇文章,已经很详细了,我就不多说了。

疑惑:时间点问题

然后,同事问了我个比较诡异的问题,如下:


console.log(1);

setTimeout(function() {
console.log('timeout invoke');
console.timeEnd('timeout');
}, 2000);

console.log(2);

console.time('hard');
console.time('timeout');

for (var i = 0;i<2000000000;i++) {}

console.timeEnd('hard');

console.log(3);

在chrome下,time的标志点hard的大概时间的13秒左右,那么问题来了,setTimeout的第二个参数若为2000(2秒),timeout这个时间为多少?如果为16000(16秒),时间为多少? 经过测试发现,如果这个setTimeout的时间设置为小于13秒,setTimeout会在console.log(3)后立即执行(与hard标志点间隔特别小),如果大于13秒,就在console.log(3)后的t-13秒后触发。 这就让我们很是疑惑,疑惑的点在于在浏览器内部。

  • 是什么时候开始进行setTimeout的时间打点呢?
  • JS是单线程的,是哪个线程打的点呢?

而经过测试发现,是在执行到setTimeout这句话的时候, 就已经打了点,如果回头执行队列的时间大于setTimeout设置的时间,就再等到了那个时间在触发setTimeout的回调, 如果小于setTimeout设置的时间,就立即执行(实际上已经延时太多了,这就是证明setTimeout不准的铁证,其实就算没有这种影响,也是不准的)。 具体可以参考这篇 JavaScript的单线程性质以及定时器的工作原理
但是第二个问题呢?我是这么想的:JS的单线程的,但是浏览器不是啊,所以是浏览器的另外一个线程负责的打点,如果您有不同的想法,请反馈给我吧,不胜感激。

最后

最近在研究一些原生JS的基础以及深入,发现真是路漫漫其修远兮,为自己加油!


本文链接:setTimeout的若干坑,转载请注明。

一个winform带你玩转rabbitMQ(三) 附源码 - 熬夜的虫子  阅读原文»

第一章. 安装,简介和初探

第二章. exchange,queue,binding介绍 订阅发布 工作队列(消费者集群)

本章收尾 介绍API CommandLine 以及其他功能

源码地址 https://github.com/dubing/MaoyaRabbit


RabbitMQ API

  RabbitMQ Server提供了丰富的http api。

  举个列子

  

  需要HTTP基本身份验证。默认的用户名/密码为guest/guest。

  这些返回值得意义我从官网搬来解释,为了避免翻译的问题导致大家理解的误差这里直接给出原文

cluster_nameThe name of the entire cluster, as set with rabbitmqctl set_cluster_name.
erlang_full_versionA string with extended detail about the Erlang VM and how it was compiled, for the node connected to.
erlang_versionA string with the Erlang version of the node connected to. As clusters should all run the same version this can be taken as representing the cluster.
exchange_typesA list of all exchange types available.
listenersAll (non-HTTP) network listeners for all nodes in the cluster. (See contexts in /api/nodes for HTTP).
management_versionVersion of the management plugin in use.
message_statsA message_stats object for everything the user can see - for all vhosts regardless of permissions in the case of monitoring and administrator users, and for all vhosts the user has access to for other users.
nodeThe name of the cluster node this management plugin instance is running on.
object_totalsAn object containing global counts of all connections, channels, exchanges, queues and consumers, subject to the same visibility rules as for message_stats.
queue_totalsAn object containing sums of the messages, messages_ready and messages_unacknowledged fields for all queues, again subject to the same visibility rules as for message_stats.
rabbitmq_versionVersion of RabbitMQ on the node which processed this request.
statistics_db_nodeName of the cluster node hosting the management statistics database.
statistics_levelWhether the node is running fine or coarse statistics.

  又或者通过api查询虚拟主机
  
  许多api的URI需要一个虚拟主机路径的一部分的名字,因为名字只有唯一在一个虚拟主机识别物体。作为默认的虚拟主机称为“/”,这将需要被编码为“%2F”。

  在我的demo程序中对应的api功能可以通过这里的功能来实现

  

  其更丰富的功能可以参考官网说明文档 http://hg.rabbitmq.com/rabbitmq-management/raw-file/3646dee55e02/priv/www-api/help.html

  以及 http://hg.rabbitmq.com/rabbitmq-management/raw-file/rabbitmq_v3_3_5/priv/www/api/index.html

  一般来说我们常用的我在应用程序中已经给出 例如查看所有队列等

  


RabbitMQ CommandLine

  除了丰富的http api,rabbitmq server自然也有其很全面命令行。

  例如查询所有exchange。

  

  查询所有队列以及他们包含的消息数目

   

  rabbitmqctl更多的命令说明参考 http://www.rabbitmq.com/man/rabbitmqctl.1.man.html


Message的BasicGet于consume的区别

  consume的功能上一张介绍过,basicget更偏向于我们平时用过的其他类型的MessageQueue,它就是最基本的接受消息,consume的消费针对basicget来说属于一个长连接于短连接的区别。

消费者关系一旦确定,基本上默认它就是在侦听通道的消息是否在生产。而basicget则是由客户端手动来控制。

  在demo中在下图所示处区分

  

  如果你选择了消费消息,那么基本上代码层面是这样来完成的

var consumer = new QueueingBasicConsumer(channel);
channel.BasicQos(0, 1, false);
channel.BasicConsume(queue.name, rbAckTrue.Checked, consumer);
while (true)
{
var e = consumer.Queue.Dequeue();
MessageBox.Show(string.Format("队列{0}获取消息{1},线程id为{2}", queue.name, Encoding.ASCII.GetString(e.Body), Process.GetCurrentProcess().Id));
Thread.Sleep(1000);
}

上一章节介绍了 消费者如何做分布式或者说是集群,很多同学可能对server端的集群也很感兴趣,鉴于单机的应用程序这里就不多介绍了,给出官网的传送门

http://www.rabbitmq.com/clustering.html

本篇收尾 有点狗尾续貂的感觉 旨在按照之前的计划 放出源码 希望对大家有帮助


本文链接:一个winform带你玩转rabbitMQ(三) 附源码,转载请注明。

阅读更多内容

没有评论:

发表评论