摘要:当某个执行完毕时,将以时间的形式通知执行操作的线程,线程执行了这个事件的回调函数。为了处理异步,线程必须有事件循环,不断的检查是否有未处理的时间。这种处理机制,称为事件环机制。方面使用第三方模块。
简介
V8引擎本身就是用于Chrome浏览器的JS解释部分,但是Ryan Dahl,把V8搬到服务器,用于做服务器的软件。
Node是一个专注于实现高性能Web服务器优化的专家,在遇到V8而诞生的项目
没有历史包袱,没有同步I/O。不会出现一个同步I/O导致事件循环性能急剧降低的情况。
V8性能足够好,远远比Python,Ruby等其它脚本语言的引擎快。
JavaScript语言的闭包特性非常方便,比C中的回调函数好用。
Node可以让JavaScript运行在服务器端的平台开发,它让JavaScript的触角延伸到了服务器端,可以与PHP,JSP,Python,Ruby等语言实现后端开发。
但Node似乎有点不同:
Node不是一种独立的语言,与PHP,JSP,Python,Perl,Ruby的“即使语言,也是平台”不同,Node使用的是JavaScript进行编程,运行在JavaScript引擎上(V8)
与PHP,JSP等相比(PHP,JSP,.net都需要运行在服务器程序上,Apache,Naginx,Tomcat,IIS),Node跳过了Apcahe,Naginx,IIS等HTTP服务器,它自己不用建设在任何服务器任何之上。Node的设计理念与经典架构(LAMP = Linux + Apache + MySQL + PHP) 有着很大的不同,可以提供强大的伸缩能力。
Node没有Web容器。
Node是花最小的硬件成本,追求更高的并发,更高的处理性能。
Node特点所谓特点,就是Node如果解决服务器高性能瓶颈问题。
JavaScript有什么特点的时候,会立即想到 单线程,事件驱动, 面向对象。但是JavaScript精髓 觉得是 this, 闭包 ,作用域链, 函数。才使得这门语言魅力无穷。
单线程
在Java,PHP,或者.net 等服务器端语言中,会为每一个用户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。理论上,一个8GB内存的服务器可以同时连接的最大用户数4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本就上升了。
Node不为每个用户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,并通过非阻塞I/O,事件驱动机制,让Node程序宏观上也是并行的。Node中,一个8GB内存的服务器,可以同时处理超过4万用户的连接。
单线程好处:操作系统完全不再有线程创建,销毁的时间开销。
单线程坏处:就是一个用户造成了线程的奔溃,整个服务都奔溃了,其它人的服务也就奔溃了。
单线程也能够造成宏观上的“并发”。
非阻塞I/O
非阻塞I/O non-blocking I/O
例子:访问数据库取得数据的时候,需要一段时间。
在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说I/O阻塞了代码的执行,极大降低了程序执行的效率。
Node采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行后面的代码,把数据库返回的结果的处理代码放在回调函数中,从而提高了程序的执行效率。
当某个I/O执行完毕时,将以时间的形式通知执行I/O操作的线程,线程执行了这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查是否有未处理的时间。依次予以处理。
阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。 有一种类似 : 与其多人工作,但是好多人闲着,倒不如一个人工作,往死里干活。
事件驱动
事件驱动 event-driven
在Node中,客户端请求建立连接,提交数据等行为,会触发相应的时间。在Node中,在一个ie时时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其它事件(比如:有新用户连接),然后返回继续执行原事件的回调函数。这种处理机制,称为:"事件环"机制。
Node底层是C++(V8也是C++) 编写。底层代码中,近半数都用户事件队列,回调函数队列的构建。用事件驱动来完成服务器的任务调度。用一个线程,担负起了处理非常多的任务。
单线程,减少内存开销,操作系统的内存换页。
如某一个任务,执行了,但是被I/O阻塞了,所以这个县城就阻塞了。非阻塞I/O,不会傻等I/O语句结束,而会执行后面的语句。利用事件驱动,不管是新用户的请求,还是老用户的I/O完成,都将以事件方式加入事件环中,等待调度。
Node所有的I/O都是异步的,回调函数嵌套回调函数。
Node是单进程单线程应用程序,但是通过事件和回调支持并发,所以性能非常高。
Node的每个API都是异步的,并作为一个独立线程运行,使用异步函数调用,并处理并发。
Node基本上所有的事件机制都是用设计模式中的观察者模式实现的。
Node单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数。
Node中,以模块为单位划分所有功能,并且提供一个完整的模块加载机制,可以将应用程序话费为各个不同的部分。
Node中,一个JavaScript文件中定义的变量,函数,都只在这个文件内部有效果。
侠义的说,每一个JavaScript文件都是一个模块,而多个JavaScript文件之间可以相互require,共同实现一个功能,整体外对,又称之为广义上的模块
好处:
减少重复代码量,增加可读性。
方便进行代码规划。
方面使用第三方模块。
当需要从JS文件外部引用到这些变量,函数时,必须使用exprots对象,或者module.exprots进行暴露。使用者需要使用require(); 函数引入这个JS文件。
function People( name,sex,age ){ this.name = name; this.sex = sex; this.age = age; } People.prototype = { sayHello: function(){ console.log(this.name+this.sex+this.age); } }; // 暴露 module.exports = People;
// 使用 var People = require("./People.js"); var p1 = new People("zf","nv","23"); p1.sayHello();
一个JavaScript文件,可以向外exprots无数个变量,函数,对象,但是require(); 的时候,仅仅需要 载入一次JS文件即可。 所以,无形之后,会增加一个顶层命名空间。
// 变量 // 需要变量引用 使用 exports.a = 10; // 直接需要变量值使用. module.exports = name; // 对象 module.exports = { name1: 123, name2: 456 } // 暴露结果: { name1: 123, name2: 456 } exports.msg = { name1: 1, name2: 2 } // 暴露结果 : { msg: { name1: 1, name2: 2 } } // 函数 exports.showMsg = function () { } // 暴露结果 : { showMsg: [Function] } // 在 引用结果 需要 通过 变量 引用对象 执行 // var msg = require(); // msg.showMsg(); module.exports = function () { } // 暴露结果 [Function] // 引入文件的 变量 直接执行模板引擎
数据绑定,成为一个完整的HTML字符串。
Node中使用的模板:ejs 和 jade
后台模板引擎:
// 模板中需要的数据 var dictionary = { a:6, news : ["xixi","haha"] };HTTP模块 主要类
Class: http.Server
var server = http.createServer();
server就是http.Server类的实例。
常用的方法有:
server.listen(port, [hostname], [backlog], [callback])
Class: http.ServerResponse
var server = http.createServer(function(req,res){ });
res就是 http.ServerResponse类的实例。
Class: http.IncomingMessage
``
var server = http.createServer(function(req,res){ });
``
req就是http.IncomingMessage类的实例。
可以使用on语法监听某个事件。
var http = require("http"); var server = http.createServer(); server.on("request",function ( req,res ) { res.setHeader("Content-type","text/html;charset=utf8"); if ( req.url == "/" ){ res.end("index"); } else { res.end("404"); } }); server.listen(8080,"localhost");req对象
每次上行请求头对象
req.headers //HTTP上行请求头
req.httpVersion // http请求的版本。现在基本上都是1.1 req.method // “GET”、”POST”就是请求的类型 req.url // 用户请求的网址res对象
每次下行响应对象
res.end() // 每次都要有这个语句,表示这次的发送已经结束 // 参数必须是string、buffer(图片、文件)。 res.write() // 就是写HTTP下行请求的body res.setHeader() // 设置返回的报文头部 res.statusCode = 404; // 设置状态码 res.writeHead() // 和res.setHeader差不多 res.writeHead(288 , {"Content-Type":"text/plain"});url模块
作用内置模块,解析url,解析地址。 分析和解析 URL 的工具
url.parse()url.parse()就是用来解析网址,接收一个字符串,返回一个JSON:
var obj = url.parse("http://localhost:8080/a/b/c/1.html?name=ting&age=21");
url.parse方法第二个参数如果是true,那么返回的对象中的query就是json
query: { xingming: "xiaoming", age: "12" }querystring模块
querystring模块是专门用来解析GET请求的查询字符串的。
console.log( qs.parse("name=ting&age=21&hobby=run&hobby=sing") ); // 返回:{ name: "ting", age: "21", hobby: [ "run", "sing" ] }path模块
处理和转换文件路径的工具集,专门处理路径
path.basename() 返回路径中的文件名 path.dirname() 返回路径中的文件夹名 path.extname() 返回路径的拓展名 console.log( path.basename("/xixi/haha/a.html") ); //a.html console.log( path.extname("/xixi/haha/a.html") ); //.html console.log( path.dirname("/xixi/haha/a.html") ); ///xixi/hahafs模块
文件处理模块,可以读文件,也可以写文件
fs.readFile(); //读取文件内容 fs.readDir(); //读取文件夹名 fs.appendFile(); //追加文件 fs.writeFile(); //写入文件(覆盖原有的) fs.rename(); //修改文件名自定义模块
每一个js文件中可以看成是一个小小的模块
require()谁,就会执行谁。就相当于调用一个函数。A require B, 先执行B全部语句,然后执行A的剩余语句。
require("./test/a.js");
每个js文件就是一个闭包,声明的函数、变量只在这个js文件内部有定义。
A require了 B , 那么B里面的所有路径都要按照A的路径写。
如果需要使用到其它文件中的变量,使用exports暴露出去。
exports.*** = ***; testA .js var a = 100; exports.a = a;
主文件
var testA = requrie("./testA.js"); console.log( testA.a );
暴露唯一的接口,module.exports ,一般使用到构造函数。
如果只有写文件载入,会去默认文件夹下:node_modules 寻找是否有当前需要载入的文件
require("test.js");
也可以直接省略路径、省略文件名,只写文件夹名
require("aa");
实际上引用的是node_moduels文件夹里面的aa文件夹里面的index.js文件。
一般第三方模块,都放入node_modules文件夹中。
配置信息:
{ "name": "my_package", //项目名字 "version": "1.0.0", //版本号 "main": "index.js", //入口文件 "keywords": [], //关键词,就是搜索什么npm上能够显示你 "author": "ag_dubs", //作者 "license": "ISC", //版权协议 "repository": { //代码托管仓库,这个会自动生成一个连接 "type": "git", "url": "https://github.com/ashleygwilliams/my_package.git" }, "bugs": { //如果发现bug应该交给谁 "url": "https://github.com/ashleygwilliams/my_package/issues" }, "dependencies": { "underscore": "*", "date-format" : "0.0.2" }, "homepage": "https://github.com/ashleygwilliams/my_package" //个人网站 }
最重要的信息是:依赖
{ "dependencies": { "underscore": "*", "date-format" : "^0.0.2" } }formidable
处理POST请求
// formidable 语法 var form = new formidable.IncomingForm(); // 设置上传路径 form.uploadDir = "./uploads"; form.parse(req, function(err, fields, files) { // fields是普通域,就是普通的文本框、单选按钮、复选按钮、textarea都存在这个对象里面 // files是上传的文件信息 var newname = df("yyyyMMddhhmmssSSS", new Date()); fs.rename(files.touxiang.path , "./uploads/" + newname + ".jpg",function(err){ if(err){ res.end("error"); return ; } }); res.end("ok"); });爬虫初级
需要的npm包:
express
request (后端发送请求的模块)
cheerio (像前端一样操作拉取回来的数据)
爬虫以及Robots协议介绍:
爬虫,是中自动获取网页内容的程序。是搜索引擎的重要组成部分,因此搜索引擎优化很大程度上就是针对爬虫而做出的优化。
robots.txt是一个文本文件,robots.txt是一个协议,不是一个命令。robots.txt是爬虫要查看的第一个文件。robots.txt文件告诉爬虫在服务器上什么文件是可以被查看的,搜索机器人就会按照该文件中的内容来确定访问的范围。
var express = require("express"); var app = express(); var cheerio = require("cheerio"); app.get("/", function(req, res){ var request = require("request"); request("https://linxingzhang.com", function(err, response, body) { if (!err && response.statusCode == 200) { $ = cheerio.load(body); // 和jquery的$("body") 一样 res.json({ panel: $("#link-panel li").length }); } }); }); app.listen(3000);
使用supervisor启动
> supervisor start app.js常用npm包
模块名 | 链接地址 | 简介 |
---|---|---|
async | async | 异步操作管理 |
bl | bl | 二进制数据解析 |
bluebird | bluebird | 异步操作管理 |
browserify | browserify | 发布浏览器可用的包 |
bunyan | bunyan | 日志(logging)管理 |
chai | chai | 断言 |
chalk | chalk | 命令行彩色输出 |
co | co | 异步流程管理 |
colors | colors | 命令行彩色输出 |
commander | commander | 命令行工具 |
debug | debug | Debug输出器 |
dockerode | dockerode | Docker管理 |
duplexify | duplexify | Stream流操作工具 |
event-stream | event-stream | Stream流操作工具 |
express | express | Server服务器框架 |
hapi | hapi | Server服务器框架 |
koa | koa | Server服务器框架 |
glob | glob | 文件名匹配 |
grunt | grunt | 构建工具 |
gulp | gulp | 构建工具 |
hyperquest | hyperquest | 轻量级HTTP客户端 |
istanbul | istanbul | 测试用例覆盖率分析 |
JSONStream | JSONStream | Stream流管理工具 |
levelup | levelup | LevelDB |
lodash | lodash | 函数式编程工具 |
log4js | log4js | 日志(logging)管理工具 |
minimatch | minimatch | 文件名匹配 |
minimist | minimist | 命令行操作 |
mocha | mocha | 单元测试 |
moment | moment | 日期时间输出 |
mongodb | mongodb | MongoDB |
mysql | mysql | MySQL |
nconf | nconf | 配置工具 |
needle | needle | 轻量级HTTP客户端 |
node-fetch | node-fetch | Fetch API |
nodemailer | nodemailer | Email客户端 |
passport | passport | 登录和认证 |
pg | pg | Postgres |
pump | pump | Stream流管理工具 |
redis | redis | Redis |
request | request | HTTP客户端 |
restify | restify | REST API搭建 |
socket.io | socket.io | WebSocket实时通信 |
split2 | split2 | Stream流管理工具 |
tape | tape | 单元测试 |
through2 | through2 | Stream流管理工具 |
underscore | underscore | 函数式编程工具 |
ws | ws | Websockets |
xml2js | xml2js | XML转换为JavaScript |
http-server | http-server | 命令行的HTTP服务器 |
nrm | nrm | 更改NPM下载源 |
node-inspector | node-inspector | Node调试 |
supervisor | supervisor | 检测Node进程的服务 |
nodemon | nodemon | 在文件有变化之后会自动重启服务 |
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/86303.html
摘要:例如指定一些依赖到模块中实现规范的模块化,感兴趣的可以查看的文档。 CommonJS 定义了 module、exports 和 require 模块规范,Node.js 为了实现这个简单的标准,从底层 C/C++ 内建模块到 JavaScript 核心模块,从路径分析、文件定位到编译执行,经历了一系列复杂的过程。简单的了解 Node 模块的原理,有利于我们重新认识基于 Node 搭建的...
摘要:环境变量法通过上一节的源码分析,我们知道了的作用,那么如何使用或者优雅的使用来解决依赖加载问题呢尝试一最为直接的是,修改系统的环境变量。 模块加载痛点 大家也或多或少的了解node模块的加载机制,最为粗浅的表述就是依次从当前目录向上级查询node_modules目录,若发现依赖则加载。但是随着应用规模的加大,目录层级越来越深,若是在某个模块中想要通过require方式以依赖名称或相对路...
摘要:先天就缺乏一项功能模块通过标签引入代码的方式显得杂乱无章,语言自身毫无组织和约束能力。与文件模块区别地方在于它从内存中加载缓存执行结果的位置核心模块在对象上,文件模块在对象上未完待续 javascript先天就缺乏一项功能:模块 javasciprt 通过script标签引入代码的方式显得杂乱无章,语言自身毫无组织和约束能力。人们不得不用命名空间等方式人为地约束代码,以求达到安全和易用的...
摘要:主要区别是需要在声明模块时指定所有的依赖,通过形参传递依赖到模块内容中。 前言 昨天,公司同事问了我如下一个问题: showImg(https://segmentfault.com/img/bVWXYP?w=548&h=346); 说他在看一个插件时,看到了源码结构如截图所示,他知道(function(){})()是一种立即执行函数,但是在截图中,最后的那个圆括号里又写了一个函数fun...
摘要:模块载入策略的模块分为两类,一类为原生核心模块,一类为文件模块。最后传入对象的,方法,,文件名,目录名作为实参并执行。在这个主文件中,可以通过方法去引入其余的模块。以上所描述的模块载入机制均定义在中。 CommonJS规范 早在Netscape诞生不久后,JavaScript就一直在探索本地编程的路,Rhino是其代表产物。无奈那时服务端JavaScript走的路均是参考众多服务器端...
阅读 2171·2020-06-12 14:26
阅读 2477·2019-08-29 16:41
阅读 1884·2019-08-29 15:28
阅读 2447·2019-08-26 13:43
阅读 752·2019-08-26 13:37
阅读 2771·2019-08-23 18:13
阅读 2791·2019-08-23 15:31
阅读 1013·2019-08-23 14:10