欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

宁皓网 Node.js

了解一下 Node.js 。
准备
1)准备

先进入到桌面上 .. 然后去克隆一个小项目 .. 位置是
git clone https://github.com/ninghao/ninghao-node
.. 进入到这个目录的下面 .. 执行一下 npm install .. 去安装需要的东西 ..

用编辑器打开这个项目 ... 在这个 index.js 里面,我们可以去练习使用 nodejs ... 比如用一个 console.log .. 输出一个 hello ...

回到终端 .. 执行一下 node index.js .. 会输出一个 hello ..

再执行一下 npm run start ...

现在,我们再去编辑一下 index.js 里面的内容 .. 保存一下文件 .. 会自动使用 node 去执行这个 index.js 文件 ..

Events
2)Events

事件,是 pub/sub ,也就是发布/订阅模式。用个现实生活的例子,比如一个视频网站上更新了某部电视剧的内容,会通知所有订阅了这部电视剧的用户,这些用户收到通知以后可以决定是不是要来看一下更新的电视剧内容。这里的更新就是一个事件,发布了这个事件,订阅的用户可以收到通知,用户的决定就是要执行的动作。

在 node 里面,这个事件的功能是在 events 模块里面,它给我们返回一个类,这个类上会包含事件的发布与订阅的功能,我们可以让自己定义的类去继续它,这样就可以使用它上面提供的一些方法了。

3)使用事件:EventEmitter

想在我们自己的代码里使用事件,我们需要用到 events 这个模块,它会给我们一个叫 EventEmitter 的类 .. 定义一个常量 .. 名字可以是 EventEmitter .. Event 是事件 .. Emit 是发出或者发表的意思 .. 把导入进来的 events 交给这个 EventEmitter ..

现在它会是一个类 .. 你可以直接使用它上面的 on 方法去注册事件 .. 使用 emit 方法去触发事件 .. 这里我们可以定义一个自己的类 .. 比如一个播放器 .. 名字可以是 Player .. 然后让它去继承一下这个 EventEmitter ..

现在 Player 这个类的实例就可以使用 EventEmitter 里面的方法了 .. 创建一个 Player 类的实例 .. 名字可以是 player ..

注册

然后再去注册一个事件,或者叫监听一个事件,可以使用 emitter 的 on 这个方法 ... 这里我们用一下 player 这个对象的 on 方法 .. 因为它是 Player 这个类的一个实例 .. 这个类继承了 EventEmitter .. 所以它的实例里面会包添加事件监听器的这个方法 ..

要监听的事件的名字可以是 play ... 发生这个事件的时候,要做的事可以交给它的第二个参数 ..

这里我们在控制台上输出一个 正在播放 ..

触发

然后你可以在需要的时候去触发一下指定的事件,用的是 emit 这个方法 .. 发出 play 这个事件 .. 这样 node 会去执行所有绑定到 play 这个事件上的动作 ..

执行一下 .. 这里会显示一个 正在播放 .. 在我们的应用里,绑定了 play 这个事件 .. 发生它的时候,要做的事情就是在这里输出这几个字儿 ...

4)事件的参数

在发布事件的时候,我们可以带一些参数,这样在订阅这个事件的地方我们可以去利用一下这些参数 .. 比如这里 emit 了一个 play 事件 .. 在这个 emit 方法里面,第一个参数就是事件的名字 .. 第二个参数可以是传递给订阅事件的参数的值 ..

比如添加一个表示正在播放的音乐的标题 ...

然后在这个订阅事件的地方 .. 给它添加一个参数 .. 名字是 track .. 这样在它里面,我们就可以使用一下传递给 track 这个参数的值 .. 也就是在发布事件的时候传递过来的 ..

这里的 track 的值,就是在发布事件时候带的这个 再见理想 ... 执行一下 .. 现在,这个控制台上显示的内容里面会包含这个 再见理想 ...

5)只执行一次的事件监听器

如果在订阅事件,或者叫监听事件的时候,用的是 on 这个方法 .. 这样每次发表这个事件的时候都会去执行它 ... 这里再试一下,再去发布一下这个 play 事件 .. 设置一下要传递给监听器的参数的值 ..

执行一下 ... 这里会显示两行内容 .. 一个是正在播放再见理想 .. 一个是正在播放海阔天空 ..

想让事件的监听器只能执行一次的话,可以使用 once 这个方法 .. 把这个 on 换成 once .. 再执行一下 .. 你会发现,这里虽然我们发布了两次 play 这个事件 ... 但这里只会显示一个结果 .. 因为用 once 这个方法订阅的事件,它的监听器只能被执行一次 ...

File System
6)得到文件与目录的信息:stat

想得到文件或者文件的信息,比如大小,创建或者修改的日期这些东西 .. 我们可以使用 stat 这个方法 .. 使用一下 fs 的 stat 这个方法 .. 先把要得到信息的文件或目录交给这个方法 .. 比如我们看一下项目下的这个 index.js 文件 ..

第二个参数是一个回调函数 .. 有两个参数,一个是 error ,发生的错误会在这个参数里 .. 一个是 stats ,得到的信息会在它里面 ..

如果的错误的话,就输出这个错误 ..

没错误,可以再输出得到的状态信息 .. stats 上面还有几个方法可以判断要获取信息的是什么类型的东西,比如 isFile() 可以判断是不是文件 .. isDirectory 可以判断是不是目录 ..

我们再把这两个方法返回的结果输出到控制台上看一下 ... 这里显示的就是获取到的 index.js 这个文件的相关的信息 .. 有文件的 size ... 大小 .. atime ,是访问它的时间 .. mtime 是修改的时间 .. ctime 是创建这个文件的时间 ..

下面还会显示,它是一个文件 .. 因为用 stats 的 isFile() 方法的时候,它返回的是 true .. 用 stats 的 isDirctory() 方法返回的是 false .. 说明它不是一个目录 ...

7)创建一个目录:mkdir

创建一个目录可以使用 mkdir ,或者它的同步方法 mkdirSync .. 比如我要在项目根目录下创建一个叫 logs 的目录 ..

使用一下 fs 的 midir 这个方法 .. 要创建的目录可以作为它的第一个参数 .. 这里就是 logs .. 执行完任务以后要作的事放在后面的这个回调函数里 .. 出现的错误会在 error 这个参数里面 ..

然后判断一下,如果有 error 就把它显示出来 .. 没有的话,说明创建目录成功了 .. 我们也可以再输出一个成功的信息 ..

这里会提示,成功创建了 logs 这个目录 ...

在项目的根目录的下面,你可以看到这个空白的 logs 目录 ...

8)创建文件并写入内容:writeFile, appendFile

writeFile 可以往文件里面写入内容,如果文件不存在的话,会去创建它,如果存在的话,文件里面的内容会被覆盖掉。现在我想在 logs 目录下面创建一个新的文件 .. 用一下 writeFile 这个方法 ..

先把文件的名字交给这个方法 .. logs/hello.log .. 然后是要往这个文件里写入的内容 .. 'hello ~ \n' .. 执行完任务以后,要做的事情可以放在这个回调函数里面 .. 发生的错误会在它的 error 这个参数里面得到 ..

如果有错误就在控制台上输出它 .. 没有的话,就输出一个成功的提示 .. 执行一下 .. 这里会显示成功的写入了文件 .. 打开 logs 这个目录 .. 它下面的 hello.log 就是刚才我们要创建的文件 ..

里面的内容就是一个 hello ..

再试一下,修改一下要写入的内容 .. 换成 您好 .. 然后执行一下 .. 打开 hello.log .. 你会看到,writeFile 这个方法会覆盖掉文件里面的内容 ..

如果你只想往文件里面添加新的内容,可以使用 appendFile 这个方法 .. 它的用法跟 writeFile 差不多 .. 复制一下这块代码 ..

再用一下 appendFile 这个方法 .. 设置一下要追加到文件里面的内容 ... 执行一下 ..

再打开 hello.log .. 这个文件现在会多了一行内容,它就是刚才我们用 appendFile 添加进来的 ...

9)读取文件里的内容:readFile

readFile 可以读取文件里的内容 .. 用一下这个方法 .. 先把要读取内容的文件的路径告诉它 .. 后面是一个回调函数 .. 里面的 error 参数是出错的错误 .. 读取出来的数据会在 data 里面 ..

如果有错误,就显示它 .. 没有话,我们可以输出读取回来的数据 .. 执行一下 .. 现在显示的是二进制的内容 .. 这里可以把 data 转换成字符串 .. 使用一下 toString 这个方法 ..

这回显示的就是这个 hello.log 文本文件里的内容了 .. 我们也可以这样 .. 在读取文件的时候设置一下读取的格式 .. 用一下 utf8 这种格式 ..

这样我们就可以去掉 data 后面的 toString 这个方法了 .. 执行一下 .. 会显示 hello.log 这个文件里面的文本内容 ..

11)列出目录里的东西:readdir

现在我想知道一个指定的目录下面都包含哪些东西,可以使用 readdir 这个方法 ... 使用一下这个方法 ... 然后先告诉它要读取的目录的位置 .. 这里我们看一下 logs 下面都有什么东西 ..

然后是一个回调函数 .. 执行完这个读取目录的任务以后会调用这个函数 .. 出现的错误会在 error 里面 .. 读取出来的结果在 files 这个参数里 ..

如果有错误的话就把它显示在控制台上 .. 没有的话可以输出这个 files ... 执行一下 ..

这里返回的是一个数组 .. 里面包含的就是 logs 这个目录下的东西 .. 现在它这里只有一个名字是 hello.log 的文件 ...

12)重命名目录或文件:rename

重命名文件或者目录可以使用 rename 这个方法 ... 比如我要重命名一下 logs 目录下的 hello.log 这个文件 .. 使用一下 rename 这个方法 .. 先是要重命名的文件或者目录的位置 .. 这里就是 logs/hello.log .. 接着是重命名以后的位置 .. 我们可以叫它 logs/greeting.log ..

这个重命名的任务完成以后会调用一个回调函数 ... 执行任务的时候出现的错误会交给 error 这个参数 .. 这里我们判断一下,有错误的话就去显示它 .. 没有的话,就去显示一个成功的提示 ..

执行一下 .. 会显示重命名成功 ..

再找开这个 logs 目录看一下 .. 它里面之前的 hello.log 这个文件已经被重命名成了 greeting.log ...

你可以使用同样的方法去修改目录的名字 ..

13)删除目录与文件:rmdir, unlink

删除目录可以使用 rmdir ,删除文件用的是 unlink .. 我们要先试着去删除项目下的 logs 这个目录 .. 使用一下这个 rmdir 方法 ... 把要删除的目录的位置交给它 ...

再用一个回调函数 .. 出现的错误会交给这个 error 参数 ... 如果有错误的话就把它输出到控制台上 .. 没有的话显示一个成功的提示 ..

这里会显示一个错误 .. 提示 directory not empty ,目录不是空的 .. 也就是想要删除掉目录,我们需要先删除掉它里面的所有的文件还有目录 ..

这里我们先去读一下 logs 这个目录 .. 可以使用它的同步的版本 .. readdirSync .. 要读的是 logs 目录 .. 后面再用一个 map 去循环处理一下这些文件 ..

删除文件用的是 unlink 这个目录 .. 删除的是 logs 下面的文件 .. 出错的话把它输出到控制台 .. 没有错误的话可以显示删除的文件 ..

执行一下 .. 这里会显示,先删除掉了 logs 目录下面的文件 .. 然后又删除掉了 logs 这个目录 ...

Stream
14)读取文件流

对于体积比较大的文件,我们可以去创建一下可读的文件流去读取这种大文件,这样我们就可以一点一点的去处理文件的内容了,不至于把它全部都读取到内存里,有可能会让应用崩溃 ..

先导入 fs 这个模块 .. 然后去创建一个可读的流 .. 名字叫它 fileReadStream .. 使用一下 fs 的 createReadStream 这个方法 .. 把要读取的文件交给这个方法 .. 比如 data.json ..

读取到文件里的数据以后,会发生 data 事件 .. 可以再去订阅一下这个事件 .. 使用 fileReadStream 的 on 这个方法 .. 事件的名字是 data .. 读取过来的数据是一块一块的 ..

这些数据交给这个监听器的参数 .. 名字可以是 chunk ,表示一块儿数据 .. 再输出每次读取过来的数据的字符数量 .. 前面可以再加上一个计数用的东西 .. 先去定义一个变量 .. 名字是 count ,让它先等于 0 .. 然后每次发生 data 事件的时候 ,让这个 count 加上 1 ..

我们可以再用一个 once 去只订阅一次 data 这个事件 .. 这回我们把 chunk 输出到控制台上 ..

下面再去创建一个要读取的文件 .. 这里可以请求一下豆瓣的 top250 这个 api ... 要求返回 100 个项目 ... 复制一下返回来的内容 ..

在项目根目录下创建一个 data.json .. 把复制的内容粘贴到这里 .. 保存一下 ..

再去执行一下 ...

这里会先把第一次读取过来的数据输出到控制台上 ... 然后你会看到, data 事件一共发生了 4 次 .. 也就是 data.json 这个文件会被分成四份读取过来 ..

这个数据现在是 Buffer .. 把它转换成能看的字符串,可以用一下 toString 这个方法 ..

现在这里显示的第一次读取过来的数据就会是字符串形式的 ..

15)可读流的事件

用 Stream 去读取文件的时候,一旦有可以使用的数据了,就会发生 data 事件 .. 这里我们订阅了一下这个事件 .. 每次可用的一小块数据会交给它的监听器 .. 这里我们做的就是去输出每块数据的大小 ..

读取结束以后 .. 会发生一个 end 事件 .. 再去订阅一下这个事件 .. 结束以后输出一个 结束 ..

如果出现错误的话,会发生一个 error 事件 .. 我们也可以去监听一下这个事件,去处理一下发生错误这种情况以后要做的事件 ..

错误信息会在这个 error 参数里面 .. 这里我们还是简单把它输出到控制台上 ..

执行一下 ... 你会看到 .. data 事件一共发生了四次 .. 结束的时候,会触发 end 事件,输出一个 结束 ..

下面我们再让它去读取一个不存在的文件 .. 比如 data1.json .. 执行一下 .. 这样会发生一个 error 事件 .. 在控制台上会输出这个错误的提示 ...

16)可写的文件流

有些流是可写的,也就是我们可以一块一块的输出数据。比如现在我想把 data.json 这个文件一块一块的写入到另一个文件里面 ...

先去创建一个可写的文件流 ... 名字是 fileWriteStream .. 用一下 fs 的 createWriteStream .. 写入到 data-1.json 这个文件 ...

然后在发生 data 这个事件的时候,我们同时去把读取过来的数据写入到文件里面 .. 用的是写入流的 write 这个方法 ... 写入的数据就是每次读取到的这小块数据 ..

执行一下 ... 这里会在项目下面创建一个 data-1.json .. 它里面的内容跟 data.json 是一样的 ...

17)pipe

在可读流上面有一个 pipe 方法,使用它可以把读过来的各种流,输出到其它的流上面。这个 pipe 有点像是一个管道,你给读取过来的流去接上一些 pipe ,也就是管道,在每个管道里面,你都可以去加工一下读取过来的数据,然后再把加工好的数据输出到其它的地方 ...

在我这里,fileReadStream 是一个读取文件的流,fileWriteStream 是一个写入文件的流 .. 这里我们可以用一下 fileReadStream 的 pipe 这个方法 .. 把读取过来的数据交给 fileWriteStream ..

先删除掉根目录下的 data-1.json ...

然后执行一下 ... 在这个根目录下面,又会出现一个 data-1.json ...

18)链式使用 pipe

我们可以把很多个 pipe 链接到一块儿用 ... 比如我现在要压缩一下 data.json 文件,然后再输出它 .. 先导入 nodejs 的 zlib 这个模块,它可以压缩或者解压文件 ..

const zlib = require('zlib');

修改一下输出的文件的名字 .. data.json.gz ..

在这个 fileReadStream 这里,再添加一个 pipe 方法 .. 在它里面,用一下 zlib.createGzip() 去处理一下读取过来的文件流 ..

后面再用一下 pipe ,把数据写入到一个文件 ...

在写入流上面会有一个 pipe 事件 .. 我们可以去订阅一下 ... 名字是 pipe .. source 表示的是源流 ... 把它输出到控制台上 ..

执行一下 .. 你会看到这里,会出现一个 data.json.gz 的压缩文件 ...

在控制台上会输出源流的相关信息 ...

HTTP
19)request

使用 http 模块的 request 方法可以向远程服务发出请求 ... 下面我们使用它向 douban 的 api 发出一个 get 请求,也就是去请求一些数据 ..

这个请求需要用到一些选项 .. 名字可以是 options .. 它是一个对象 .. 里面先用一个 protocol .. 设置一下请求的协议 .. 使用一下 http: .. 再添加一个 hostname 指定一下请求的主机名 .. api.douban.com .. 再设置一下端口号 .. 用一个 port 属性 .. 默认它的值就是 80 端口 ..

method 可以指定一下请求的方法 .. 我们要请求一些数据,所以这个方法是 GET ... 再添加一个 path ,再设置一下请求的具体的路径 ... /v2/movie/top250 ..

下面再去用一下 http 的 request 方法 .. 它会返回一个 ClientRequest 类的对象 ... 给这个对象起个名字 .. 比如 request ... 用一下 http 的 request 方法 .. 第一个参数就是请求的时候需要的一些选项,这里可以使用上面定义的 options 来表示 ... 然后是一个回调函数 .. 它有一个参数,名字是 response ..

我们先在控制台上输出这个 response 里的内容 ..

然后再去订阅一下 error 这个事件 .. 使用 request 的 on 这个方法 .. 事件的名字是 error .. 出现错误的时候,我们可以把错误输出到控制台上 ...

最后再用一个 request 的 end 这个方法结束这个请求 ... 执行一下 ...

这里会显示 response 里的内容 ... 它是 IncomingMessage 对象 ... 里面会包含一些有用的信息还有方法 ..

比如我们要输出响应回来的代码 .. 可以访问一下 response 的 statusCode 这个属性 ...

这里显示的是 200 ,表示成功的请求回了数据 .. 响应的头部信息 .. 在它的 headers 这个属性里面 ...

20)利用请求回来的数据

请求响应回来的数据会被一块一块的读取过来,它会是一个数据流 .. 一旦有可用的数据以后,会发生 data 事件 .. 我们去监听一下 data 这个事件 .. 得到的数据在 chunk 里面.. 在控制台上我们可以输出这块数据 ... 再执行一下 ..

你会看到请求回来的一块一块的数据 .. 现在它们都是 Buffer .. 我们可以先设置一下编码 .. 用一下 response 的 setEncoding 这个方法 .. 设置成 utf8 ..

现在这里得到的就是 utf8 编码的数据了 ...

在上面我们再定义一个变量 .. 名字是 responseData .. 然后把每次得到的数据放到这个变量里面 ...

不再有响应的数据以后,会发生一个 end 事件 .. 去订阅一下这个事件 .. 先用 JSON.parse 去处理一下 responseData .. 访问一下它的 subjects 属性 .. 它是一个数组 ... 所以可以使用一个 map 方法循环的处理一下它 ..

在控制台上输出每个项目里的 title 这个属性 ..

再执行一下 ... 在控制台上会显示请求回来的电影列表的标题 ...

21)创建服务器

下面我们使用 nodejs 的 http 模块去创建一个服务器,先创建一个新的文件 .. 名字是 server.js .. 导入 http 模块 ..

然后再用一下 http 模块的 createServer 方法 ...

这个方法会返回一个 Server 实例 .. 这个方法的参数是 requestListener ,请求的监听器 .. 也就是每次服务器发生请求,也就是发生 request 事件的时候,就会自动执行这个请求监听器 ..

我们也可以手工的去监听一下 reqeust 这个事件 .. 用一下 server 的 on .. 监听一下 request 方法 .. 设置一个监听器 ... 里面有两个参数,一个是 request ,它是 InComingMessage 的一个实例 .. 还有一个参数是 response,它会是 ServerResponse 的一个实例 ..

在这个监听器里面,我们先去设置一下响应的头部信息 .. 用的是 response 的 writeHead 这个方法 .. 它的第一个参数是响应的状态码 .. 200 表示成功 ... 第二个参数是一个表示头部信息的对象 .. 这里我们先添加一个 Content-Type ,设置一下响应的内容的类型 ... 这里设置成 text/html ,表示响应的内容是 html ..

再用一下 response 的 end 方法,可以把响应的数据放到这个方法里面 ... 用一个 h1 标签,里面的文字是 hello ~ ..

下面再去设置一下服务器监听的端口号 ... 使用 server 的 listen 方法 .. 监听的端口号是 8080 ...

启动这个服务器可以执行一下 node server.js ... 这里我提前使用 gulp 创建了一个小任务,它可以监视服务器的变化,发生变化以后,它会自动重启服务器 ... 执行一下 npm run server ..

然后打开浏览器 .. 访问一下 localhost:8080 ... 这样会发生 request 事件 .. 我们的服务器要做的就是响应回一个 html 的内容 .. 具体的内容就是一个 h1 标签包装的文字 ...


来自 https://ninghao.net/course/3912#info
普通分类: