本文面向的读者已是了解JavaScript基本使用的前端程序员,可是缺少服务端的经验,接下来将带你走进在服务端的世界,看看运行在服务端的JavaScript是如何工做的,它与运行在浏览器端的JavaScript有何异同,相比于浏览器能多作哪些事情,有何优点。javascript
文章经过实例的方式,让你了解Nodejs可以作什么,能够解决一些什么样的问题,而且知道它的使用场景。若是你有兴趣,请记住必定要本身动手,哪怕照着实例写一遍,真真实实的感觉代码运行时的喜悦与兴奋,激发本身对新领域的兴趣。html
默认你已经安装了Nodejs和npm包管理器,而且熟悉一些简单的操做,如nodejs代码的运行启动,npm包的安装命令等基础操做。前端
1.hello world java
首先经过一个前端工程师最常接触却不属于前端范畴的内容去了解一下Nodejs,建立一个http服务。这里使用Nodejs自带的http模块建立一个http服务,你可使用经过浏览器或者命令行来发起一个http请求,直观的感觉服务端的JavaScript。node
// http.js
const http = require('http');
http.createServer((req, res) => {
res.end('Hello World!');
}).listen(8000, ()=> {
console.log('listen on 8000!');
})复制代码
复制代码
上面的例子中,经过使用node自带的http模块,调用其http.creatServer方法在本机上开启了一个http服务,监听了本地的8000端口,代码逻辑很简单,当接收到一个req请求时,调用res.end返回一个字符串"hello world"给带客户端,旨在让你对Nodejs有一个直观的体验。ios
可使用node http.js命令来执行这段代码,经过浏览器来访问http://127.0.0.1:8000或者http://localhost:800来查看结果。git
一个由Nodejs的http服务提供的hello world跑起来了,简洁快速吧。接下来再来实现一个前端工做中与服务端最紧密的内容来看看Nodejs的魅力,数据接口。程序员
2. 如何提供一个API github
首先这里肯定所要提供的api是咱们最经常使用的json格式,因此咱们要注意后端返回给前端的数据类型。ajax
const http = require('http');
const data = {
name: 'Nodejs 入门示例',
description: '这是返回信息的描述内容',
date: new Date()
};
http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json;charset=utf-8');
const result = JSON.stringify(data);
res.end(result);
}).listen(8000, ()=> {
console.log('listen on 8000!');
})复制代码
上例子中,先肯定了一个数据模型data,内部一共有三个字段。这里的数据模型就是前端开发前与后端所定义的返回格式,最终前端要拿到这个JSON格式的数据在客户端进行处理。代码逻辑相比于Hello World,规定了返回的数据格式,以及设定了返回请求的文本类型为application/json,而后调用res.end返回到客户端。
能够继续使用浏览器发起http请求来查看结果,一个简单且熟悉的JSON数据接口已经完成了。你能够按照前端最经常使用的调用方式,如ajax或者axios来请求接口来在你的前端项目使用它。
可是上面例子中的接口和咱们经常使用的接口有一个差别点,就是接口名称和返回内容均不规范,使用者直接经过没有路径的http://127.0.0.1:8000来使用接口,这跟咱们平常使用的接口是彻底不同的,那咱们接下来再看一下如何给提供一个规范化的接口呢?
3.一个规范的接口
规范的接口具有哪些条件呢?简单总结一下。
接口名称:接口名称要体现出大体的使用场景,例如增删改查的动做。
接口返回:接口返回要有规范化的标识,如成功与否错误内容等。
接下来经过上面这两个点,按照标准的接口规范来实现一下上面的接口,看看Nodejs是如何给前端提供接口的。这里先约定要提供的接口名称内含api标志,api所要作的动做等一些关键信息。以下格式:
http://localhost:8000/api/search/data?userId=12345
const http = require('http');
const url = require('url');
const qs = require('querystring');
// 生成一段返回值
const genResponse = userId => ({
success: true,
data: {
userId,
name: 'Nodejs 入门示例',
description: '这是返回信息的描述内容',
date: new Date()
}
});
// http服务
http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json;charset=utf-8');
const reqUrl = url.parse(req.url);
// 判断接口路径是不是约定好的
if (reqUrl.pathname === '/api/search/data') {
// 获取连接上传来的userId参数
const uid = qs.parse(reqUrl.query).userId;
// 生成返回值
const result = JSON.stringify(genResponse(uid));
res.end(result);
} else {
res.writeHead(404);
res.end('NotFund');
}
}).listen(8000, ()=> {
console.log('listen on 8000!');
})
复制代码
上面的例子中,新使用Nodejs另外一个自带的模块url,url模块顾名思义是一个处理href的库,它将href拆分红各个子内容,同时为了能处理客户端带来的userId参数还使用了自带的querystring模块,它能够将连接上问号后的query参数获取到,以便服务端代码能使用他们,他们均属于工具库,下面看看官方对于URL模块将href拆分的颗粒度图,清晰的了解一下一个请求连接,能够被拆分红什么颗粒度。
实例中的源码简单解析一下,当服务接收到请求时,先判断请求的api名称是否是事先约定好的/api/search/data,判断经过后,将前端传递在连接上的参数userId获取到,处理后插入到返回的json数据中,便可经过res.end来下发数据,若是路径判断失败,则返回404的状态码,而且进入Notfund页面,
一个规范的接口已经开发完成了,简单总结一下,上面以渐进式的方式了解了Nodejs如何给前端来提供一个规范化的http接口,了解了服务端的JavaScript所具有的能力,接下来再从另外一个前端工程师比较少接触的内容——文件操做,来进一步了解Nodejs。
对于文件操做相关的内容,前端程序员通常是不会触及的,并且JavaScript语言自己也并无暴露操做文件的方法。而在Nodejs中,自己便提供了fs文件操做模块,这个模块模块底层并非JavaScript来编写的,是具有操做文件的C++语言编写的,其封装完成后将上层暴露给Nodejs,而后即可以使用JavaScript的语法来调用它。
1.读一个文件
在Nodejs中,读文件有两种形式,一种是同步的另外一种是异步的,同步能够理解为读文件这个过程要等待,就是一旦执行的读这个操做的时候,你的代码就被”卡“住了,直到文件读完才能继续执行,来看看下面的例子。
先新增一个test.md文件配合读操做,文件内容为:### 我是一个文件
// fsread.js
const fs = require('fs');
const file = fs.readFileSync('./test.md', 'utf8');
console.log(file);复制代码
使用node fsread.js来运行上面的代码,从上面简单的几行你就能够发现成功将test.md文件里的内容读出来,能够打印到了命令行console里,忽然发现JavaScript语言的强大了吧,很神奇吧。
可是Nodejs天生是为异步而生的,因此必需要体验一下异步读文件是怎么的过程,与同步的表现有何异同。因此 下面示例一个异步回调的方式去读一个文件,异步的意思就是读文件这个操做进行的同时,读操做下面的JavaScript代码也在执行,就如同咱们熟悉的软件后台运行同样,你能够继续你的桌面操做。
const fs = require('fs');
console.log('sync start');
fs.readFile('./test.md', 'utf8', (err, data) => {
console.log('test.md 的内容');
console.log(data);
});
console.log('sync progress');
fs.readFile('./test2.md', 'utf8', (err, data) => {
console.log('test2.md 的内容');
console.log(data);
});
console.log('sync finish');复制代码
复制代码
在上面的例子中,要求是一次读取两个文件,两个文件之间并无相关依赖性,因此这种 场景下咱们更但愿他们各作各的,无需去等。因此没有必要像上面同步的方式,等第一个结束再进入第二个的读取,因此使用异步方式更合适。
从上面的执行结果也能够看出来,fs.readFile这个异步回调操做均在三个同步代码 console的后面,并无像同步等待读操做的结束。
下面来个图看看这个同步API和异步API有何异同。
图片上半部分是异步读文件,能够看出来,读的操做能够理解为同时刻执行的。
图片下半部分是同步读文件,第二个读的操做须要先等待第一个读完才能够。
举个现实生活中同步的场景,运动会接力赛,A,B两个班比赛接力,虽然A,B两个班无依赖,可是A班的第二名同窗则须要第一名同窗的接力棒拿到后才可继续跑,此时A班的运动员之间就属于同步阻塞类型。
在举个异步的场景,老板经过全员会议下达了一个任务,任务是你们作一百个俯卧撑,谁先作完任务则能够领取10000元红包的奖励,你们听到后纷纷原地作起,在这时候各个员工之间就是异步的,他们各作各的,谁先作完就能够执行老板给他们的开始说的领取奖励操做,这个操做能够理解为异步回调函数。
2. 写一个文件
Nodejs写文件也是有两个类型,同步与异步,实际执行流程与上面的“读”是同样的。
下面进入同步读文件的例子,执行下面的代码你会发现多了一个test3.md文件,而且写入'### 我是测试文件test3'的内容
const fs = require('fs');
const body = '### 我是测试文件test3的内容';
fs.writeFileSync('./test3.md', body);复制代码
再来看一下异步写一个文件的例子,作一个对比。
// 来一个异步的看看。
const fs = require('fs');
const body = '### 我是测试文件test4的内容';
fs.writeFile('./test4.md', body, (err) => {
if (err) throw err;
console.log('文件test4已被保存');
});
const body2 = '### 我是测试文件test5的内容';
fs.writeFile('./test5.md', body2, (err) => {
if (err) throw err;
console.log('文件test5已被保存');
});复制代码
这是写文件的结果,这时候你的本地会多出两个文件test4.md和test5.md出来。
3.其余文件操做
其实Nodejs提供了丰富的文件操做接口,除了读写,还有像复制,给文件受权,删除一个文件,文件夹的操做,文件内容的监听等,若是你有对文件的操做需求,请先在文档查一下看是否可以知足你。
文档地址:http://nodejs.cn/api/fs.html
下面来一个文件内容监听的例子,带你看看一个文件变化时也能被观察到乐趣。
const fs = require('fs');
fs.watch('./test6.md', 'utf8', (eventType, filename)=>{
// eventType 是 'rename' 或 'change',
// filename 是触发事件的文件的名称
console.log('eventType', eventType);
console.log('filename', filename);
});复制代码
我将test6.md的内容进行手动的变化,而且改了名字,这里都被监听到了,是否是颇有趣,跟我一块儿来练习吧。
本文从前端工程师们最常接触却又不属于前端领域的两个方面,http服务与文件操做展开了学习,从几个简单易懂的例子带领去了解了Nodejs。回想当初我为何学习Nodejs,其实就是由于它的简单便捷,几行代码就能作出一些我想要的效果,能快速的完成个人要求。
若是上面的入门示例也让你对Nodejs有了浓厚的兴趣,那么请快速动手学习起来吧,看再多文章不如本身手写一遍,从零到一,跟我一块儿学习吧。
文章用到的代码都可在此获取:
https://github.com/FantasyGao/Practice-book/tree/master/nodejs
如上内容均为本身总结,不免会有错误或者认识误差,若有问题,但愿你们留言指正,以避免误人,如有什么问题请留言,会尽力回答之。若是对你有帮助不要忘了分享给你的朋友或者点击右下方的“在看”哦!也能够关注做者,查看历史文章而且关注最新动态,助你早日成为一名全栈工程师!