最近看到nodejs,因为有一个处理里面有好几个异步操作,调入回调大坑,不禁觉得很恶心,真的很讨厌发明这种写法的人,简直反社会!!!遂转载一篇解坑的文章,原文地址:http://www.infoq.com/cn/articles/nodejs-callback-hell/。
Node.js需要按顺序执行异步逻辑时一般采用后续传递风格,也就是将后续逻辑封装在回调函数中作为起始函数的参数,逐层嵌套。这种风格虽然可以提高CPU利用率,降低等待时间,但当后续逻辑步骤较多时会影响代码的可读性,结果代码的修改维护变得很困难。根据这种代码的样子,一般称其为"callback hell"或"pyramid of doom",本文称之为回调大坑,嵌套越多,大坑越深。 坑的起源
后续传递风格
为什么会有坑?这要从后续传递风格(continuation-passing style–CPS)说起。这种编程风格最开始是由Gerald Jay Sussman和Guy L. Steele, Jr. 在AI Memo 349上提出来的,那一年是1975年,Schema语言的第一次亮相。既然JavaScript的函数式编程设计原则主要源自Schema,这种风格自然也被带到了Javascript中。
这种风格的函数要有额外的参数:“后续逻辑体”,比如带一个参数的函数。CPS函数计算出结果值后并不是直接返回,而是调用那个后续逻辑函数,并把这个结果作为它的参数。从而实现计算结果在逻辑步骤之间的传递,以及逻辑的延续。也就是说如果要调用CPS函数,调用方函数要提供一个后续逻辑函数来接收CPS函数的“返回”值。 回调
在JavaScript中,这个“后续逻辑体”就是我们常说的回调(callback)。这种作为参数的函数之所以被称为回调,是因为它一般在主程序中定义,由主程序交给库函数,并由它在需要时回来调用。而将回调函数作为参数的,一般是一个会占用较长时间的异步函数,要交给另一个线程执行,以便不影响主程序的后续操作。如下图所示: 下面一个例子说明回调样例的恶心之处:
module.exports = function (param, cb) { asyncFun1(param, function (er, data) { if (er) return cb(er); asyncFun2(data,function (er,data) { if (er) return cb(er); asyncFun3(data, function (er, data) { if (er) return cb(er); cb(data); }) }) }) } 像function(er,data)这种回调函数签名很常见,几乎所有的Node.js核心库及第三方库中的CPS函数都接收这样的函数参数,它的第一个参数是错误,其余参数是CPS函数要传递的结果。比如Node.js中负责文件处理的fs模块,我们再看一个实际工作中可能会遇到的例子。要找出一个目录中最大的文件,处理步骤应该是:
用fs.readdir获取目录中的文件列表; 循环遍历文件,获取文件的stat; 找出最大文件; 以最大文件的文件名为参数调用回调。 这些都是异步操作,但需要顺序执行,后续传递风格的代码应该是下面这样的: var fs = require('fs') var path = require('path') module.exports = function (dir, cb) { fs.readdir(dir, function (er, files) { // [1] if (er) return cb(er) var counter = files.length var errored = false var stats = [] files.forEach(function (file, index) { fs.stat(path.join(dir,file), function (er, stat) { // [2] if (errored) return if (er) { errored = true return cb(er) } stats[index] = stat // [3] if (--counter == 0) { // [4] var largest = stats .filter(function (stat) { return stat.isFile() }) // [5] .reduce(function (prev, next) { // [6] if (prev.size > next.size) return prev return next }) cb(null, files[stats.indexOf(largest)]) // [7] } }) }) }) } 对这个模块的用户来说,只需要提供一个回调函数function(er,filename),用两个参数分别接收错误或文件名:
因为爬虫项目需要模拟登陆,可是有一个网站的登录需要输入验证码。其实这种登录有2种解决方案,一种是利用cookie,一种是识别图片。前者需要人工登录一次,而且有时效限制,故不太现实。后者可以,但是难点是如何识别出验证码。 这里面就要介绍一个神器了,tesseract-ocr这个项目是一个开源项目,可以用于图像识别。不过这个项目现在托管于google,所以不好下载,你可以搜一下,选择在国内下载。http://download.csdn.net/detail/neal1991/9502931 一开始我觉得我的验证码还挺好识别的,因为都是数字,如下图: 但是我发觉直接来识别还是来识别不了的,最好还是先要对图片进行一些预处理。说到图片的预处理就要说到另外一个软件了,就是imagemagick,这个是一个开源的图片处理项目,你可以去http://www.imagemagick.org/script/binary-releases.php根据你自己的系统进行相应得下载。这个软件还有相应的开发api,你可以自行的根据需要去下载。记住,这个软件安装后,配置环境变量后,需要重新启动的,一开始我还以为是什么问题呢。后来发现重新启动之后,就生效了,可以直接在cmd中使用。在这我就不说什么别的了。 首先是对图片进行预处理:
convert 1.jpg -colorspace gray -normalize -threshold 50% 1.tif 这里主要是先做一个灰度图转化,然后进行归一化处理,最后设立一个阈值,进行二值化,这样最后的结果还是比较清晰的,如下图: 然后再用tesseract进行识别:
tesseract 1.tif result 是不是很简单? 在github上面写了一个nodejs的程序可以直接执行,不过需要安装nodejs,链接如下: https://github.com/neal1991/code-recognition
这两天在做一个nodejs的爬虫项目,需要模拟post请求获得网站数据。遇到2个asp.net的网站,掉到坑里面,调试了好几天。总结一下过程。 一般我们模拟post请求的时候最重要的就是post请求里面的formdata就可以了。怎么看formdata呢,以谷歌浏览器为例,打开开发者工具,到network中,点击查询,然后找到你所请求的网页,点击,就能看到请求的各种详细信息了。 我们可以看到里面包含了各种各样的属性,但一般.net网站会多一些特殊的属性,比如上图里面的compressedviestate和eventvalidation属性。我查了一下这些属性貌似是.net机制自有的一些属性。compressedviewstate好像是反映webform的控件的状态信息,而eventvalidation好像是用于服务器端的验证。后来我发现一个规律,如果我在postdata不加这些属性,返回来的响应是一个空的页面,就是其他的部分都有,但是就是包含数据的div里面没有任何数据。但是如果你把这些属性的值填错,就会返回一些乱码的响应数据。后来就一直调试,也苦苦不知道原因。 后来,别人和我介绍了一个神器,curl,这个linux系统自带的,但是windows需要自己安装,不过下载的速度很慢。你用这个可以直接模拟post请求,这样就可以很方便的验证这个请求到底是不是有效的。你在network哪个请求的页面右键,copy as cURL,然后把这个命令拿去执行,这个其实就是一个curl命令。我把它放在linux终端执行能够获得正确的相应,但是放到windows下却不行,后来发现是因为windows里面命令行长度限制,而这个命令有一万多个字符。但是这表明如果使用正确的参数,是可以获得正确的响应的。 高潮来了,我准备在记事本删掉这些属性值的时候,突然发现__COMPRESSEDVIEWSTATE那个是2个下划线,我突然感觉就是这个原因,果然。。。。。。。 这个问题是在是太坑爹了,主要自己一开始写属性的时候也没注意,也没想到这一块,所以花了这么长时间来调试。绕来绕去,发现还不是那个问题。但是现在还有一个问题,我直接是把这些属性用一些固定值的,我并不知道这些值是不是一直有效的。本来我想先发送一个空的post请求然后获取这些属性的,然后填充进去再实现post请求,但是还是一些奇怪的问题,所以我也就没这么做了。 总的来说,写代码还是特别坑,小心入坑!!!!
最近再做一个nodejs网站爬虫的项目,但是爬一些网站的数据出现了中文字符乱码的问题。查了一下,主要是因为不是所有的网站的编码格式都是utf-8,还有一些网站用的是gb2312或者gbk的编码格式。所以需要做一个处理来进行编码的解码。至于网站的编码怎么看,可以通过去检查中的network去看。 根据相应的编码格式,进行相应的设置。utf-8就不要说了,下面就以gbk为例,说一下解码的方式。
var request = require('request'); var cheerio = request('cheerio'); var iconv = require('iconv-lite'); request ({ url : 'http://www.taobao.com', encodeing = null },function(err,res,body){ if (err) throw err; // decode the content of the website body = iconv.decode(body,'gbk'); var $ = cheerio.load(body); console.log($('head title').text()); }) 或者是使用一个gbk包,但我觉得还是上面的方式比较好。
面试问到js的事件流,当时说的不是很清楚,现在觉得有必要把这个弄清楚。
事件捕获和事件冒泡 事件流描述的是从页面中接收事件的顺序,也可理解为事件在页面中传播的顺序。 事件流主要分为两种,即事件捕获和事件冒泡,这二者接受事件处理的顺序不同。假设下面的代码:
<body> <div id="outer"> <div id="inner"></div> </div> </body> 这两个事件流分别的是IE公司和netspace公司提出来的,冒泡事件流支持的浏览器更多。 冒泡事件流中,事件的传递顺序是从子元素向父元素传递。假设我们给div绑定一个click事件。那么在冒泡事件流中,事件的传递顺序是:inner->outer->body。然而捕获事件流的顺序则截然想法:body->outer->innner。
DOM事件流 DOM2级事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。还是以上面的代码为例,单击inner则会按照下面的顺序触发事件:document->html->body->outer->ineer->outer->body->html->document。在DOM事件流中,实际的目标inner在捕获阶段不会接受到事件。这意味着在捕获阶段,事件到outer就停止了,下一个阶段是“处于目标”阶段,于是事件在inner 上发生,并在事件处理中呗看成是冒泡阶段的一部分。然后,冒泡阶段发生,事件又传播回文档。
事件处理程序 响应某个时间的函数叫做事件处理程序。DOM0级的事件处理程序很简单,onclick就是常用的DOM0级事件处理函数,只会在冒泡阶段被处理。 而DOM2级事件定义了两个方法用于处理置顶和删除事件处理程序的操作addEventListener()和removeEventListener(),所有DOM节点都包含这两个方法,并且它们都接受3个参数:要处理的事件名,作为事件处理的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序,反之则是在事件冒泡阶段处理程序。DOM2级方法添加事件处理程序的好处是可以添加多个事件处理程序,会按照添加顺序被处理(无论是捕获还是冒泡)。 而IE不同的它有自己的方法attachEvent()和detachEvent,这两个接受相同的两个参数:事件处理程序名称和事件处理程序函数。
跨浏览器的事件处理程序 var EventUtil = { addHandler: function(element,type,handler) { if (element.addEventListener) { element.addEventListener(type,handler,false); } else if (element.attachEvent) { element.attachEvent('on'+type,handler); } else { element['on'+type] = handler; } }, removeHandler: function(element,type,handler) { if (element.removeEventListener) { element.removeEventListener(type,handler,false); } else(element.detachEvent) { element.detachEvent('on' +type,handler); } else { element['on'+type] = null; } } }
去百度面试基础架构部的前端开发实习生,感觉应该跪得很惨。百度上海研发中心挺偏的,离张江还挺远的,还要打车过去。到了百度那边门卫管的挺严的,还要面试官来接。后来,就一个程序员来接我,也就是我的面试官。后来就在他们三楼一个休息的地方开始面试。首先就是自我介绍了,然后就是blabla我一些经历项目而已了。他强调了了一下前端相关的项目经历,但是讲道理我是真心没有前端的项目经历,所以也说不上什么。唯一做的也就是我自己的个人主页,还基本上都是静态页面。然后开始正式面试,他首先问了我标签和标签有什么区别,然后我说了和的本质区别是他们的默认display 属性不同,然后他又问了有没有其他的不同,我并不知道。然后他接着问了常见的块级标签和行内标签有哪一些。接着他问了我清除浮动的知识,我只是临时记住了一些清楚浮动的方法,但是还是没有弄懂实际的原理,所以场面也是比较的尴尬。他问了怎么优化网页,说可以怎么做。我不禁一喜,把之前准备的东西背出来,刚说到第一条,减少 http请求,他就问我如何减少 http请求。尴尬,一下子gg,我也想不起来如何减少http请求。后来他看我说不上来就让我继续往下说,我又说了压缩,以及代码精简之类的。然后他又问了具体的,我说了一下,他好像也不是特别满意。我的简历,尼玛,我为什么要写个对于html5有充分的认识!!!我天天又懒得改,每个面试官都要问我这个问题。不过我事先也准备了,就把一些基础的特性说了一下。他说还有别的,然后提醒我缓存之类的,然后就说起来sessionStorage,localStroage之类的,并问了我和cache之间的区别之类的。这里面有个问题他炸了我一下,他说你确定localStorage在本地是不会删除的么,很明显是不会的。然后他问对于缓存请求有没有了解,很明显我并没有什么了解。他又问了我一些对于哪些开源的框架比较熟悉,那也就只有jQuery和bootstrap。他问我对于这些开源框架的更新清不清楚,很明显,宝宝不清楚啊!!!然后他问了一系列图标改变颜色如何实现,实现鼠标挪上去,就改变颜色。这个我说用hover改变css 属性,但他应该是质疑这样的做法吧。后来他又说道bootstrap其实有这样的实现,其实我好像也看到过,但是我也没关注过是如何实现的,真是悲剧。接着他问了js的问题。首先问了一下事件流,这个地方我说错了,事件流应该是补货,处理,冒泡。我把顺序说反了,反正事件流还问了详细的问题,但是我对这个并不是特别了解,所以说的也是不好的。后来出了一个js的题目,如何实现像trim一样去掉两端的空白,我用js写了一下,里面有很多问题,具体就是不说了。后来他提示说是用正则表达式,我说我只会python的,然后他说可以。但是宝宝也写不出来啊,然后他说那你就说下原理吧。然而我并不知道如何做,然后就罢了。 第二个面试官就长得更像程序员了,直接穿个拖鞋就过来了。他是直接让我写代码的,第一题如何实现三列布局,两边各100px,中间自动拓展,我说了用float或者css3的新属性。他直接让我写代码了,然后就写一写,估计也不太对。第二个,他说ie和chrome等绑定的事件的方法不同,如何写一个函数进行不同的处理。这一题我并不知道如何区分,所以也就没写。第三题,他说有没有做过移动端的开发,我说没有。然后我就老实说了,其实自己并没有接触太多的前端。然后她说也看了我简历没什么前端的经历之类的,然后就是说说,然后就没了。 总结一下,这次面试经历讲道理并不是特别困难的。前端的书我也是看了好几本,但其实并没有什么特别的意思,还是做项目成长的比较快。所以,赶紧实习,实际参与项目对于我来说实在是太重要了。
html语义话 img标签alt属性和title属性的区别
alt属性是图片在因浏览器兼容、加载失败活着地址出错等原因无法显示为浏览用户所做的代替语言,其性质为图片的代替;而title属性是表达该图片的一些额外信息,其性质为一种备注或注释,鼠标过去显示该文字。
css布局 常见的布局有四种:表格布局,浮动布局,css框架,flexbox 两列布局,三列布局可以由浮动来实现 css3已经实现了多列布局,主要属性包括 column-count column-gap column-rule-style column-rule-width column-rule-color column-rule column-span column-width
div{ -webkit-column-count: 3; Chorome, Safari, Opera -moz-column-count :3; Firefox -column-count:3; }
清除浮动的知识 在浮动元素后面增加标签 在浮动元后面增加一个清楚浮动层:
ajax 基本实现步骤 1、创建XMLHttpRequest对象 2、使用XMLHttpRequest对象打开一个连接,制定连接方式<post/get> 和链接地址以及是否同步 3、设置请求的头部(请求的类型和请求的编码格式) 4、设置回调函数 5、发送请求 6、更新页面显示
XMLHttpRequest状态码: 0 uninitialized 初始化状态,XMLHttpRequest已经被创建或者重置 1 open open 方法已经调用,但是send 方法还没有调用,还没有发送请求 2 sent send方案已经发送,请求已经发送到服务器,但是还没有接受到请求 3 receiving 所有响应头已经接受到,响应体开始接受,但没有接受完成 4 loaded 请求已经完全接受
取消a链接默认跳转行为 href属性设置为javascript:void(0)
作为一名演化计算会议的学生,要懂得这方面的会议啦,不过我最熟悉的只是CEC了,其他的会议还真没怎么见过。 【原创】演化计算&演化硬件相关会议评价(07.07.15) Copy to clipboard Posted by: dareios Posted on: 2007-07-13 00:27
欢迎大家提意见,补充^^
Revised Date(v4): 2007/10/03 (修改: ICES) Revised Date(v3): 2007/07/15 (追加:CEC, AUS-AI, ICCS) Revised Date(v2): 2007/06/05(追加:GECCO, ICONIP) Revised Date(v1): 2007/05/29
写这个段子纯粹是因为受了南大周志华教授写的AI Conferences那篇文章的影响,于是起了写一篇自己心目中的conferences tier list的念头. List中的会议评价主要根据我本人这几年接触到的会议论文集的质量,参加会议过程的感观,CiteSeer的那个Estimated impact of publication venues in Computer Science,会议的专业性-我本人偏重evolvable hardware,大部分的LNCS出版的会议和少量的其他重要相关会议将做探讨. grade A 的会议是演化硬件方向最权威的国际会议,其中发表的论文大多有一读的价值. B 的会议也是质量非常不错的会议, C 的会议, 我个人认为去发表论文还是不错的,但是通常不会在这个档次的会议proceeding中找参考论文.D 的会议,通常是一些发表论文数量超过500篇,或者永远在中国国内打转的"国际"会议.
grade A:
ICES (A0): International Conference on Evolvable Systems: From Biology to Hareware. 基本上是从90年代evolvable hardware(EHW)的研究引起学术界的关注就开始举行的重要会议.EHW方面最重要的2个会议之一.首次举行是在1995年的瑞士(当时还不叫 ICES,96年才开始现在的名字),基本上当时的EHW开创性人物瑞士的Eduardo Sanchez,日本的Tetsuya Higuchi等人都参加了这次会议.此会基本2年一次,2001年以后是单数年召开.奇怪的是2007,2008又连续在中国和捷克分别举行,实在是没什么规律.ICES的proceeding一直在LNCS上出版,每届发表的papers大概在40篇以下.例如ICES2005包括了21篇论文,而 ICES2007发表了41篇,接受率33%.
数据结构线性表是数据结构最基础的一章内容,也是数据结构最基础的一段,包括线性表的定义,线性表的初始化,线性表的插入,删除,合并。下面贴上代码
#include <stdio.h> #include <malloc.h> #include<iostream> using namespace std; //线性表的定义 typedef int ElemType; typedef struct LNode{ ElemType data; struct LNode *next; }LNode,*LinkList; //线性表的初始化 int InitList_L(LinkList &L) { L = (LinkList)malloc(sizeof(LNode)); L->next = NULL; return 1; } //线性表的插入 int ListInsert_L(LinkList &L,int i,ElemType e) { LinkList p; p = L; int j = 0; while(p&&j<i-1) { p=p->next; ++j; } if(!p||j>i-1) return 0; LinkList s = (LinkList)malloc(sizeof(LNode)); s->data = e; s->next=p->next; p->next=s; return 1; } //清空线性表 void Delete_L(LinkList L) { LinkList p = L->next; if(!p) cout << "this list is empty!"; while(p) { cout << p->data; p = p->next; } cout << endl; } //合并线性表 void MergeList_L(LinkList &La,LinkList &Lb,LinkList &Lc) { LinkList pa = La->next; LinkList pb = Lb->next; LinkList pc = Lc=La; while (pa&&pb) { if(pa->data<pb->data) { pc->next=pa; pc=pa; pa=pa->next; } else { pc->next=pb; pc=pb; pb=pb->next; } } pc->next=pa?pa:pb; free(Lb); } int main() { LinkList La,Lb,Lc; InitList_L(La); InitList_L(Lb); InitList_L(Lc); ListInsert_L(La,1,2); ListInsert_L(La,2,3); ListInsert_L(La,3,5); Delete_L(La); }
今天打包一个安装程序,总是出现报错,internal build error -6213,然后搜遍都没有找到什么解决方案。看到一个帖子,说是因为installsheild里面的build的时候自动扫描.NET依赖库造成的原因,要把这个自动扫描功能给关掉,但是他说的在什么地方关说的不是很清楚,所以我一直找不到。 http://1978l.blog.163.com/blog/static/4494441620098704049756/原文帖子如下 后来找了半天,终于找到地方了。 如图1,图2所示,把components里面所有.NET scan at Build设置为none,这个可能是这个软件的bug把,我使用的是2011版本,免费的版本。 真心的,我实验室解决问题的能手,实验室这些妹子如果没有我,我都不知道她们该怎么活下去。