想要深入实践JavaScript,所以尝试学习Node.js。
先上参考链接:Node.js 包教不包会
练习代码:Node.js练习
首先需要安装nvm,就是Node Version Manager,负责Node.js的版本管理。因为考虑不涉及Node.js新老版本的切换,因此这里没有安装nvm,直接进入了下一步。(主要是安装时遇到了问题不想花时间解决QAQ)
然后安装Node.js,之前已经借助brew安装过了。
最后需要安装npm,负责自动管理包的依赖,就是Node.js Package Manager的意思。之前用brew安装过。
lession2:一个简单的express应用
express是Node.js应用最广泛的web框架,express官网。
Node.js的依赖是以项目为单位的,不是安装在全局的,直接安装在项目的node_modules目录下,每个依赖都可以有指定版本的其他依赖。
1 |
npm install express |
写第一个express代码:
1 |
var express = require('express'); |
这里需要理解的知识点:
- 端口:通过端口来区分出同一电脑内不同应用或者进程,从而实现一条物理网线同时连接多个程序(通过分组交换技术)。端口号是一个16位的uint,所以范围是1-65535,对TCP,port 0被保留,UDP的source端端口号是可选的,为0时表示无端口。
- URL:常见的格式
<scheme>://<host>:<port>/<url-path>
lession3:使用外部模块
package.json文件的用法:
定义了项目的各种元信息,包括项目的名称,git repo地址,作者等等,定义了项目的依赖,这样项目在部署的时候不需要将node_modules目录也上传到服务器,npm install即可。
安装依赖的具体步骤:
npm init。初始化项目并帮我吗创建一个package.json文件;npm install express utility --save。安装依赖,同时--save命令会帮助我们把依赖写入package.json文件。
这里分不清http的query和body了,所以还是翻了《自顶向下》,有空了应该把这本再看一遍…query实际上就是URL上带着的para参数。
这里记录网络中应用层里几个之前有疑惑的点:
- HTTP一定使用TCP支撑运输协议。
- HTTP请求报文:
1 |
GET /somedir/page.html HTTP/1.1 |
- HTTP响应报文:
1 |
/* 状态行 */ |
这一部分的代码就不贴出来了。
lession4:简单的superagent与cheerio爬虫
- superagent是一个http库,可以发起get或者post请求
- cheerio用来从网页中以css selector取数据
这一段代码不是很理解,所以研究了一下cheerio这个库到底在干嘛,先贴代码:
1 |
var $ = cheerio.load(sres.text); |
以上代码做的其实是以下几件事:
- 装载html文件。
- 选择器:
$(selelctor,[context],[root])。选择器在context范围内进行搜索,context又在root范围内搜索。 attr(name, value)获得和修改属性。在匹配的元素中只能获得第一元素的属性,如果设置一个属性的值为null,则移除这个属性。只传第一个参数,则获得属性;传两个参数,则是修改属性。
ref: cheerio 笔记
eventproxy控制并发
Node.js的异步并发是一大亮点。eventproxy这个库是用来管理异步操作是否完成,监听异步操作,在他们都被完成之后自动调用提供的处理函数,并将抓取到的数据当参数传出来。
哈哈哈哈哈,这一段好逗,贴出来乐一下:

个人觉得js这种随意的语言,真的非常不符合我的严谨型人格…
这里解读一下eventproxy的用法(先会用再理解吧):
1 |
var ep = new eventproxy; |
- 创建
eventproxy的实例; .after()方法的三个参数,第一个参数表示监听的是'topic_html',第二个参数表示要监听达到topicURLs.length次才会执行回调函数,第三个参数就是要执行的回调函数。.map()方法是Array方法,他会返回一个新数组,数组中的元素为原数组元素调用函数处理后返回的值,并不会改变原数组的值。trim()函数用来去除字符串开头和结尾的空格。- 这一段代码刚看到的时候没看懂,实际上
eventproxy的使用是先执行ep.emit('topic_html', [topicurl, res.text]);语句,指定监听的事件,这些被监听的事件是异步完成的,当监听的事件全部完成后,再抛出事件,即执行after()。先监听,后抛出。 topic_html实际上只是为监听事件起一个事件名,能够使回调时对应正确的监听事件。topicURLs.length才是实际上指定监听结束发起回调的时刻。.eq()方法将匹配元素集缩减至指定index上的一个。forEach()和each()之间的区别:前者是用来遍历数组和json对象的,而后者是专门用来遍历jquery对象的。- jquery到底是什么?jQuery API中文文档
jQuery 是一个高效、精简并且功能丰富的 JavaScript 工具库。它提供的 API 易于使用且兼容众多浏览器,这让诸如 HTML 文档遍历和操作、事件处理、动画和 Ajax 操作更加简单。
jQuery库通常用于前端操作DOM节点,后端通常使用cheerio写爬虫脚本。cheerio是专门为服务端设计的快读、灵活精简实现的jQuery。cheerio模块引入了jquery核心的一部分,去除了jquery库中所有在dom和浏览器的不兼容部分,只保留了核心API。两者的API很类似,例如前文说到的each()也是用来遍历cheerio对象的。这样就说得通了。
有一个eventproxy的源码分析:eventproxy原理分析
lession5:使用async控制并发
当发起请求过多时,大部分网站会因此禁止恶意请求而封IP,因此需要控制并发数量。
async常用的控制并发数量的接口:mapLimit(arr, limit, iterator, callback)。另一个常用的控制并发数量的接口queue(worker, concurrency)。
这里用到setTimeout(function, delay)这个函数,是在等待delay毫秒后执行function。
lession6:测试:mocha, should, istanbul
直接上代码,用来跑测试用例:
1 |
describe('test/main.test.js', function () { |
这里的教程看的比较懵了,使用mocha和istanbul的目的是什么。这里参考了阮一峰的代码覆盖率工具 Istanbul 入门教程.
测试的时候需要关注是否所有的代码都测试到了,所以引入“代码覆盖率”这个指标,从四个维度测试代码:
- 行覆盖率:是否每一行都执行了
- 函数覆盖率:是否每个函数都调用了
- 分支覆盖率:是否每个if代码块都执行了
- 语句覆盖率:是否每个语句都执行了
istabbul就是js中这样一个测试工具,常常和测试框架mocha结合使用。
相关的命令行:
1 |
istanbul cover _mocha |
lesssion7:浏览器端测试:mocha, chai, phantomjs
总结一下这几个工具:
- islanbul:js代码股概率测试工具
npm i istanbul -g - mocha:测试框架,即运行测试的工具,使用
describe和it方法对不同的测试情况进行分组npm install mocha -g - chai:mocha本身不提供assert断言,chai是一个断言库
- phantomjs:帮助搭建测试需要的前端浏览器环境
npm i -g mocha-phantomjs
这里运行phantomjs出现了问题,运行mocha-phantomjs index.html --ssl-protocol=any --ignore-ssl-errors=true显示phantomjs terminated with signal SIGSEGV,随后执行mocha-phantomjs --path /usr/local/lib/node_modules/mocha-phantomjs/node_modules/phantomjs ./index.html抛出错误An error occurred trying to launch phantomjs at "/usr/local/lib/node_modules/mocha-phantomjs/node_modules/phantomjs": TypeError: Cannot read property 'pipe' of undefined.
官网上显示:PhantomJS development is suspended until further notice.
不再提供支持了。所以这里不再追究了,没有进行进一步的调研,直接进入下一节学习。
lession8:supertest
supertest和superagent的API一模一样,superagent是用来抓取页面的,supertest是专门用来配合express进行集成测试的。
这里区别一下npm install的时候--save</code>–save-dev的区别:
--save会把依赖包添加到package.json文件的dependencies键下,--save-dev会把依赖添加到package.jsondevDependencies键下;dependencies是运行时依赖,而devDependencies是开发时依赖。如果发布后用不到这个模块,只有开发时用得到,使用后者。
lession9:正则表达式
不详述了,主要是之前看过,但是不用到的话又记不住那么多规则,用到的时候再查询吧。
lession10: benchmark
这个课程的缺点就是不解释这些都是啥东西,默认已经知道了…
benchmark:A robust benchmarking library that supports high-resolution timers & returns statistically significant results.
这个课程的目标是测试将字符串的100转换成Number类型的100的三种方法哪个更快,使用benchmark作为测试速度的工具。
1 |
+ x 861,361,931 ops/sec ±0.64% (47 runs sampled) |
运行代码会显示每秒钟代码运行的次数(ops/sec),对比出最快的计算方式。
lession11:作用域和闭包
这一部分主要是理解两个点:
第一,js是没有块级作用域这个概念的。
第二,理解闭包。
1 |
for (var i = 0; i < 5; i++) { |
这个例子看到过很多次了,这里的解释我觉得还比较明白:
上面这个代码块会打印五个 5 出来,而我们预想的结果是打印 0 1 2 3 4。
之所以会这样,是因为 setTimeout 中的 i 是对外层 i 的引用。当 setTimeout 的代码被解释的时候,运行时只是记录了 i 的引用,而不是值。而当 setTimeout 被触发时,五个 setTimeout 中的 i 同时被取值,由于它们都指向了外层的同一个 i,而那个 i 的值在迭代完成时为 5,所以打印了五次 5。
为了得到我们预想的结果,我们可以把 i 赋值成一个局部的变量,从而摆脱外层迭代的影响。
1 |
for (var i = 0; i < 5; i++) { |
到此为止后面的部分不想再跟着研究了。觉得自己研究js这么长时间,理解上有进展,但是实际上没有什么长足的进步,主要原因就是自己并没有从头至尾的搭建一个完整的项目,始终停留在简单的demo阶段,这里主要原因是自己在写代码的思路上总是依赖模仿的,这是我停留在这个初级阶段始终不前进的原因之一吧,对于一个工程没有什么思路上的构想。
但是我想我也不可以急功近利吧,继续从模仿做总有一天也会有自己的想法产生,能够把握一个较为完整的程序。接下来想要写一个博客项目,希望能够在两周的时间内搭建起来基本功能,当然这取决于我找的这个例子的代码规范能不能满足我的要求 = =试试看咯。每一天都要加油鸭!




近期评论