快速开始 Hello World
Node 是什么
简史
2009年2月,Ryan Dahl在博客上宣布准备基于V8创建一个轻量级的Web服务器并提供一套库。
2009年5月,Ryan Dahl在GitHub上发布了最初版本的部分Node.js包,随后几个月里,有人开始使用Node.js开发应用。
2009年11月和2010年4月,两届JSConf大会都安排了Node.js的讲座。
2010年年底,Node.js获得云计算服务商Joyent资助,创始人Ryan Dahl加入Joyent全职负责Node.js的发展。
2011年7月,Node.js在微软的支持下发布Windows版本。
Node.js是一个Javascript运行环境(runtime environment),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。Node.js 不是一个 JavaScript 框架,不同于CakePHP、Django、Rails。Node.js 更不是浏览器端的库,不能与 jQuery、ExtJS 相提并论。Node.js 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与PHP、Python、Perl、Ruby 等服务端语言平起平坐的脚本语言。
是什么
发展史
特征
回调模式下的异步是有明显缺陷的,程序的执行顺序必须依靠回调来保证,没有层层回调,就没有可以保障的逻辑顺序,这也就注定了,node不能做复杂的业务逻辑。
回调山真不是必须的。
不适合CPU密集型应用
只支持单核CPU,不能充分利用CPU
可靠性低,一旦代码某个环节崩溃,整个系统都崩溃,原因:单进程,单线程。
Debug不方便,错误没有stack trace
高并发(最重要的优点)
适合I/O密集型应用
RESTful API
npm,前后端分离
Node通过事件驱动的方式处理请求时无需为每一个请求创建额外的线程。在事件驱动的模型当中,每一个IO工作被添加到事件队列中,线程循环地处理队列上的工作任务,当执行过程中遇到来堵塞(读取文件、查询数据库)时,线程不会停下来等待结果,而是留下一个处理结果的回调函数,转而继续执行队列中的下一个任务。这个传递到队列中的回调函数在堵塞任务运行结束后才被线程调用。
非阻塞I/O(单线程、非阻塞)&事件轮询【Single Threaded Event Loop】
优点
缺陷
nodejs中的库方法是异步的,异步方法是约定。
环境配置
Hello World 示例
Once you have installed Node, let's try building our first web server. Create a file named "app.js", and paste the following code:
const http = require('http');const hostname = '127.0.0.1';const port = 3000;const server = http.createServer((req, res) => { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain'); res.end('Hello World\n'); }); server.listen(port, hostname, () => { console.log(`Server running at http://${hostname}:${port}/`); });
After that, run your web server using node app.js, visit http://localhost:3000, and you will see a message 'Hello World'
NPM 使用介绍
npm 简介
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
允许用户从NPM服务器下载别人编写的第三方包到本地使用。
允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
由于新版的nodejs已经集成了npm,所以之前npm也一并安装好了。同样可以通过输入 "npm -v" 来测试是否成功安装。命令如下,出现版本提示表示安装成功:
$ npm -v6.4.1
如果你安装的是旧版本的 npm,可以很容易得通过 npm 命令来升级,命令如下:
$ sudo npm install npm -g
Node 架构与运行原理
Node 架构分析
架构图
nodejs组成部分
http server 建立过程
由js写成,提供我们应用程序调用的库,同时这些模块又依赖builtin modules来获取相应的服务支持
由C++代码写成各类模块,包含了crypto,zlib, file stream etc 基础功能。(v8提供了函数接口,libuv提供异步IO模型库,以及一些nodejs函数,为builtin modules提供服务)
基于事件驱动的异步IO模型库,我们的js代码发出请求,最终由libuv完成,而我们所设置的回调函数则是在libuv触发
虚拟机的功能,执行js代码
提供C++函数接口,为nodejs提供v8初始化,创建context,scope等
v8 engine
libuv
builtin modules
native modules
建立http server为例
ES6 features
Node.js ES2015 Support
Node 模块系统
简介
创建模块
加载模块
Node 全局对象
是什么
JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。
在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。
在 Node.js 我们可以直接访问到 global 的属性,而不需要在应用中包含它。
文件操作
简介
Node.js 提供一组类似 UNIX(POSIX)标准的文件操作API。 Node 导入文件系统模块(fs)语法如下所示:
var fs = require("fs")
异步和同步
Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。
异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。
建议大家使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。
阻塞代码实例
创建一个文件 input.txt ,内容如下:
Node.js 极简教程
创建 main.js 文件, 代码如下:
var fs = require("fs");var data = fs.readFileSync('input.txt');console.log(data.toString());console.log("程序执行结束!");
以上代码执行结果如下:
$ node main.js Node.js 极简教程 程序执行结束!
非阻塞代码实例
创建一个文件 input.txt ,内容如下:
Node.js 极简教程
创建 main.js 文件, 代码如下:
var fs = require("fs"); fs.readFile('input.txt', function (err, data) { if (err) return console.error(err); console.log(data.toString()); });console.log("程序执行结束!");
以上代码执行结果如下:
$ node main.js 程序执行结束! Node.js 极简教程
以上两个实例我们了解了阻塞与非阻塞调用的不同。第一个实例在文件读取完后才执行完程序。 第二个实例我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。
因此,阻塞是按顺序执行的,而非阻塞是不需要按顺序的,所以如果需要处理回调函数的参数,我们就需要写在回调函数内。
Web 模块
Web 服务器简介
Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式及URL,与客户端的网络浏览器配合。
大多数 web 服务器都支持服务端的脚本语言(php、python、ruby)等,并通过脚本语言从数据库获取数据,将结果返回给客户端浏览器。
目前最主流的三个Web服务器是Apache、Nginx、IIS。
使用 Node 创建 Web 服务器
Node.js 提供了 http 模块,http 模块主要用于搭建 HTTP 服务端和客户端,使用 HTTP 服务器或客户端功能必须调用 http 模块,代码如下:
var http = require('http');
以下是演示一个最基本的 HTTP 服务器架构(使用 8080 端口),创建 index.js 文件,代码如下所示:
实例
var http = require('http');var fs = require('fs');var url = require('url'); // 创建服务器http.createServer( function (request, response) { // 解析请求,包括文件名 var pathname = url.parse(request.url).pathname; // 输出请求的文件名 console.log("Request for " + pathname + " received."); // 从文件系统中读取请求的文件内容 fs.readFile(pathname.substr(1), function (err, data) { if (err) { console.log(err); // HTTP 状态码: 404 : NOT FOUND // Content Type: text/plain response.writeHead(404, {'Content-Type': 'text/html'}); }else{ // HTTP 状态码: 200 : OK // Content Type: text/plain response.writeHead(200, {'Content-Type': 'text/html'}); // 响应文件内容 response.write(data.toString()); } // 发送响应数据 response.end(); }); }).listen(8080); // 控制台会输出以下信息console.log('Server running at http://127.0.0.1:8080/');
接下来我们在该目录下创建一个 index.html 文件,代码如下:
index.html 文件
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Node.js 极简教程</title></head><body> <h1>我的第一个标题</h1> <p>我的第一个段落。</p></body></html>
执行 index.js 文件:
$ node index.js Server running at http://127.0.0.1:8080/Request for / received. { [Error: ENOENT: no such file or directory, open ''] errno: -2, code: 'ENOENT', syscall: 'open', path: '' } Request for /index.html received. Request for /favicon.ico received. { [Error: ENOENT: no such file or directory, open 'favicon.ico'] errno: -2, code: 'ENOENT', syscall: 'open', path: 'favicon.ico' } Request for /index.html received. Request for /favicon.ico received. { [Error: ENOENT: no such file or directory, open 'favicon.ico'] errno: -2, code: 'ENOENT', syscall: 'open', path: 'favicon.ico' }
直接访问 http://127.0.0.1:8080/, 提示 HTTP ERROR 404 Not found:
因为,我们代码里没有对根路径进行映射处理。
接着我们在浏览器中打开地址:http://127.0.0.1:8080/index.html,显示如下图所示:
MySQL数据库操作
安装驱动
$ cnpm install mysql
连接数据库
在以下实例中根据你的实际配置修改数据库用户名、及密码及数据库名:
test.js 文件代码:
var mysql = require('mysql');var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', database : 'test'}); connection.connect(); connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) { if (error) throw error; console.log('The solution is: ', results[0].solution); });
执行以下命令输出结果为:
$ node test.js The solution is: 2
数据库 CRUD 操作
查询数据
查询数据
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var sql = 'SELECT * FROM websites';//查connection.query(sql,function (err, result) { if(err){ console.log('[SELECT ERROR] - ',err.message); return; } console.log('--------------------------SELECT----------------------------'); console.log(result); console.log('------------------------------------------------------------\n\n'); }); connection.end();
插入数据
插入数据
var mysql = require('mysql'); var connection = mysql.createConnection({ host : 'localhost', user : 'root', password : '123456', port: '3306', database: 'test', }); connection.connect(); var addSql = 'INSERT INTO websites(Id,name,url,alexa,country) VALUES(0,?,?,?,?)';var addSqlParams = ['菜鸟工具', 'https://c.runoob.com','23453', 'CN'];//增connection.query(addSql,addSqlParams,function (err, result) { if(err){ console.log('[INSERT ERROR] - ',err.message); return; } console.log('--------------------------INSERT----------------------------'); //console.log('INSERT ID:',result.insertId); console.log('INSERT ID:',result); console.log('-----------------------------------------------------------------\n\n'); }); connection.end();
执行以下命令输出就结果为:
$ node test.js --------------------------INSERT---------------------------- INSERT ID: OkPacket { fieldCount: 0, affectedRows: 1, insertId: 6, serverStatus: 2, warningCount: 0, message: '', protocol41: true, changedRows: 0 } -----------------------------------------------------------------
作者:东海陈光剑
链接:https://www.jianshu.com/p/3b134939daf5