JavaScript规范提供了一系列强大的数组遍历和操作方法,但是不是所有的浏览器和运行时环境都能支持这些新规范中的方法。Dojo提供了跨平台的方案来弥补这一空缺,使用这些方法,可以减少代码行数,提升执行效率。
常用的数组操作之一就是在一个数组中查找某个元素,dojo为此提供了两个方法: dojo.indexOf 和dojo.lastIndexOf. dojo.indexOf 方法从前至后挨个的搜索数组中的元素,dojo.lastIndexOf则从后向前逐个搜索。 两个方法的参数是一样的,被搜索的数组,以及要查找的元素,还有一个可选的参数,即从何处开始搜索。 下面我们来看一个例子:
如果某元素没有找到,两个方法都会返回-1. 要注意这两个方法在搜索时都使用严格的比较操作(===),所以你除了可以查找简单数据类型(primitive), 你还可以查找对象
小结

另一个常用的数组操作是循环遍历所有数组元素。使用传统的JavaScript代码通常可以写成这样
var item; for(var i = 0; i < arr.length; i++){ item = arr[i]; // 对item进行操作 }
这样写的一个缺点是,如果你在一个事件处理函数中去访问item,你没法取到的你想要的作用域。(参考后面的例子)
使用dojo.forEach, 它提供了一个标准的方法来循环遍历数组,并且在作用域链查找时保留了元素。 它基本遵守Array.prototype.forEach的行为,只有两处不同: 1. dojo.forEach会遍历那些未定义的值:即便数组中存在一些未定义的值,它仍然会对该值执行操作。
2. dojo.forEach会在数组对象上直接遍历,而浏览器的forEach会在一个数组的拷贝上执行。 所以如果你在dojo.forEach 中对数组本身做了修改,这一修改将会生效。
下面让我们看一个例子
dojo.forEach 接受3个参数:被遍历的数组,回调函数(遍历的数组时,1.95金牛无内功,每个元素包括未定义的元素将作为参数传递给该回调函数), 以及一个可选的作用域对象,用来规定执行该回调函数时所用的作用域。
回调函数将会被反复执行,直到数组中最后一个有值的位置。 回调函数被调用时将会被传入3个参数,数组当前位置上的元素(可能是一个对象或一个原始值),当前位置的序号,以及一个数组的引用. 回调函数将会在指定的作用域中执行,如果forEach省略了第三个参数没有指定作用域,那么回调函数将会在全局的作用域中执行。
让我们在来看一下dojo.forEach的作用域参数究竟有什么好处
通过设定回调函数的作用域对象,使得回调函数能够在正确的作用域中被调用。 这种模式在对dojo widget编程时经常会用到,请牢记。
如果熟悉network server architecture的话,很容易知道HDFS在这里采用的是one thread per request的模型。它没有采用当下流行的基于epoll的event-driven architecture,甚至于,它都没有采用thread pool的方式,而是使用了一种“很土很土”的模型。众所周知,one thread per request模型一个很明显的缺陷在于如果访问的并发数太高,可能产生大量的thread而导致thread间的context swith开销过大。 我个人想法,HDFS之所以采用这样的一个模型,一方面是编程上比较简单,另一个方面,可能是开发人员认为HDFS这样的一个系统并不容易出现高并发的访问。从图中看,需要和DataNode进行数据消息交互的模块有两个:一个是DFSClient,一个是其它的DataNode。 先说后者,DataNode与DataNode之间的数据消息交互只发生在一种情况下,就是某个DFSClient对block进行了写操作,那么被写的DataNode需要将这些数据复制到这个block副本所在的其它DataNode上。是一种链式结构: DFSClient -->DataNode A -->DataNode B --> DataNode C 所以,DataNode之间的链接是与DFSClient和DataNode之间的链接一一对应的。 再说DFSClient,它并不同于Web Server所要面对的client。Web Serve的client是终端的浏览器,可能成千上万,这是不可控的。而DFSClient是系统内的client,它的数量不会太多(就好比是对Database的连接数,是开发人员控制的,所以不会太大)。由于DFSClient在系统内部的数量不会太多,所以DataNode从DFSClient过来的连接也就不会太多。既然DFSClient发起的连接不多,那么DataNode之间的连接也不会多。 结合以上二点,整个HDFS很难产生高并发的情况,所以采用one thread per request的架构也就说得过去了。
DataXceiver也是一个线程,它负责处理对应的一个连接,主要完成4种任务: opReadBlock: 读取一个block opWriteBlock: 写一个block到disk上 opCopyBlock: 读一个block,然后送到指定的目的地 opReplaceBlock: 替换一个block
匹配
简单而言,HDFS分为了三个部分: NameNode,处于master的地位,维护了数据在DataNode上的分布情况,热血传奇私服网,并且,还要负责一些调度任务; DataNode,存储真实数据的地方; DFSClient,一个client端,通过它提供的接口访问NameNode和DataNode; 三者之间的通信全部是基于TCP/Socket; 如图所示:
Dojo 已经将数组的遍历简化了许多,接下来我们如果要想对数组中的元素做一些修改那该如何做呢?
假设我们有一个字符串数组,我们希望把其中的字符串转化成一组对象,并且每个对象的“name“属性就是字符串数组中的对应字符串。
根据我们前面已经学过的,传奇私服加速器,我们可能写出如下代码
这样写当然没有错,不过现在新版的JavaScript和Dojo.map方法可以让代码进一步简化:
dojo.map的参数和forEach是一样的。 两者的区别是:dojo.map中回调函数的返回值将会被按顺序存储在一个新的数组中。而这个新数组就是dojo.map的返回值
另一个Dojo提供的常用转换功能是 dojo.filter。 顾名思义,它允许你在原有数组元素中根据一定规则和条件过滤出某些元素。当然,你也可以用forEach来写,但是使用dojo.filter 会将这一过程大大简化。
原题:Arrays Made Easy 原文链接: http://dojotoolkit.org/documentation/tutorials/1.6/arrays/ 作者: Bran Forbes 译者: feijia (tiimfei@gmail.com)
在本教程中你将会学到如何使用dojo提供的跨平台的JavaScript数组操作
难度:初学者
适用Dojo版本:1.6
访问并操作数组是开发Web应用中的重要部分。JavaScript语言设计时就考虑到了这种需求,因此在语言层面已经加入了一些针对数组操作的方法来简化这一工作。遗憾的是不是所有浏览器都实现了同样的JavaScript标准。Dojo作为一个跨浏览器平台的框架提供了一系列数组操作方法,来弥补这一缺憾。
-- END --
图中,连线表示两者之间存在通信,箭头一方表示接收请求,没有箭头的一端表示发起请求的一方;图中的黑色细线表示控制消息的通路,红色粗线表示数据消息的通路;
可以看得出来,NameNode是一个典型的Server端程序,它总是处于接受请求,返回响应的状态中。NameNode永远不会主动的向其它组件发起请求(依稀记得GFS的论文中也是这样做的)。如果NameNode需要向DataNode发送一些调度或者控制命令的话,必须等待DataNode向NameNode发送heartbeat之后,作为heartbeat的response返回给DataNode。 DataNode就比较忙了,它不仅需要定时的发送heartbeat给NameNode,并且heartbeat的返回往往还附带了很多的控制消息需要处理,同时,DataNode要接收DFSClient来的读写数据的请求和一些控制请求,最后,DataNode之间还有数据消息和控制消息的传输。
而事实上,HDFS确实没有用RPC机制传输数据消息。当HDFS中的DFSClient对DataNode上保存的文件数据进行读写的时候,它其实采用了另外一个机制,简单介绍一下:
在程序中我们有时需要判断数组中的某元素是否满足某些条件:例如你想知道其中是否有某些元素定义了error属性,或者你想确定是否数组中每个元素都定义了text属性。 这时就可以使用dojo.some 或dojo.every 方法。
这两个函数的签名和dojo.filter 完全一样,使用的回调函数也是一个返回布尔值的函数。 不过dojo.some 和dojo.every 两个函数本身不返回一个新数组,而是返回布尔值:dojo.every返回true表示,对数组中每个元素回调函数的都返回true,而dojo.some 返回true表示,数组中至少存在一个函数,对其调用回调函数时返回了true
HDFS中所有的控制消息的传输都基于它自实现的RPC模块。介绍过这个RPC的实现,这里简单回顾一下: RPC模块会对两个需要通信的Node之间各创建一个socket,这两个Node之间的所有的控制消息都通过这对socket进行传输;对于RPC的client一端来说,会有两个线程参与到这个过程中。一个线程是调用本次RPC的线程,它会将消息写入到socket中,然后就执行wait()阻塞住;另一个线程则是RPC模块内部负责该socket读的工作,它从socket中读取消息,然后执行notify()唤醒阻塞线程; 我在之前的blog中就提到,这个机制不太适合大数据量的传输,因为两个Node之间只用一个socket进行通信,网络的吞吐量不一定上得去。
在数组中查找某个对象的位置
遍历,循环
所以,当HDFS进行数据传输的时候,对于每一个链接创建一个thread进行处理,这样,如果两个Node之间的数据传输很频繁的话,那么有可能会创建多个链接,吞吐量就上去了。
这阵子花了点时间读了读HDFS的源代码。有所得。 不过网上关于Hadoop源代码的解析已经挺多了,所以自称为“边角料”,也就是一些零散的心得和想法。
数组元素操作
每个DataNode在启动的时候会创建一个线程DataXceiverServer来专门负责block数据的读写的链接。而DataXceiverServer做的事情很简单 --一旦有一个连接,就创建一个新的DataXceiver来处理这个连接:
HDFS中很有意思的一点是,它的控制消息的传输和数据消息的传输采用的是不一样的模块。这也是接下来我想探讨的重点。 |