阅读完您能够知道什么:前端
对于异步、在作前端开发、发送请求后咱们并非立马能过拿到数据、而是和服务器进行一系列操做(域名解析、三次握手、服务器通讯/响应)当服务器给到咱们数据会触发咱们的异步回调方法、并走咱们的方法逻辑、这个部分称为异步!在node中绝大多数的操做都是以异步的方式进行调用、这样作的好处是咱们能够很天然的进行并行I/O操做、而无需等待前面的I/O结束、在编程模型上能够极大的提高效率。node
咱们在启动一个serve服务的时候、编写服务事件监听、而且把监听的结果用回调函数接收、事件编程具备轻量级、松耦合、只关注事物点等优点!可是也有别的问题就是事件与事件之间各自独立、如何协做是一个问题。git
Node保持了Javascript在浏览器中单线程的特色,单线程最大的好处就是不用像多线程编程那样到处在乎状态的同步问题、这里没有死锁的存在、也没有线程上下文交换所带来的性能开销!es6
单线程的弱点(三方面)github
在Node中、长时间的CPU占用也会致使后续的异步I/O发不出调用、已完成的异步I/O的回调函数也不会获得及时的执行!Node为了解决这个问题采用了Web Workers相同的思路解决单线程大计算量的问题
child_process
、这样咱们能够把大量的计算所有分解出去、而后经过进程间的事件消息来传递结果、我在编写Chrome插件也使用过这种方式去拆分计算逻辑下降运算形成的堵塞。编程
起初Node只能在Linux平台运行、后面Node使用libuv实现跨平台操做!json
graph TD Node.js --> libuv libuv --> *nix libuv --> Windows
进行技术选型前、咱们想要了解技术具体适合什么样的场景、这样咱们才能作到在合适的场景使用合适的技术达到一个比较好的效果!关于Node探讨较多的是I/O密集型和CPU密集型;后端
Node处理I/O的能力是值得称赞的、Node面向网络而且擅长并行I/O、可以有效的组织起更多的硬件资源!I/O密集的最大好处在于Node利用事件循环的处理能力、而不是为了每个请求而去独立启动一个线程、资源占用极少!api
event loop在处理全部的任务/事件时,都是沿着事件队列顺序执行的,因此在其中任何一个任务/事件自己没有完成以前,其它的回调、监听器、超时、nextTick()的函数都得不到运行的机会,由于被阻塞的event loop根本没机会处理它们,此时程序最好的状况是变慢,最糟的状况是停滞不动,像死掉同样。因此当Node.js遇到高CPU占用率的任务时,event loop会被阻塞住,有解决方案吗?答案是有,Node虽然没有提供多线程用于计算支持、可是仍是有如下两个方式来充分利用CPU。浏览器
Node能够经过编写C/C++扩展的方式更高效的利用CPU,将一些V8不能作到的性能极致的地方提供C/C++来实现
若是单线程的Node不能知足需求、甚至用了C/C++扩展后还以为不够、那么能够选择经过子进程的方式、将一部分Node进程看成常驻服务进程用于计算、利用进程间的消息来传递结果、将计算与I/O分离
随着Javascript被普遍重视起来后、也暴露出一个问题,先天就缺少的一项功能:模块、随着Node的诞生、后面社区也为其制定了相应的规范
CommonJs规范
、固然在此以前也有不少的模块化技术、以往也有经过闭包或者一些命名空间还有AMD和RequireJS、今天咱们只讲如今服务端Node所使用的模块CommonJs规范!
每一个文件就是一个模块,有本身的做用域。在一个文件里面定义的变量、函数、类,都是私有的,对其余文件不可见隔离开了、使得用户彻底没必要考虑变量被污染。经过
require('xxx/地址') 引入模块
和经过module.exports.xxx = xxx
导出当前模块的方法或者变量
//mode.js
function add(a,b){
return a + b;
}
module.exports.add = add; //导出模块方法
//index.js
const mode = require('./mode.js') //引入模块
console.log(mode) //{ add: [Function: add]
let sum = mode.add(1,2);
console.log(sum) //3
复制代码
在模块中,上下文提供了require()方法来引入外部模块。对应导出的模块来讲,上下文提供了module对象、而exports是module的一个属性、而且它是惟一导出的入口、将想要导出的模块挂载到exports对象就可暴露给外部模块引入使用!
Node引入模块须要经历三个步骤 1:路径分析 2:文件定位 3:编译执行
Node中模块分为两类:一类是Node提供的模块,称为
核心模块
,另一种是用户编写的模块称之为文件模块
,核心模块
在Node源码编译中、就已经编译成二进制执行文件、在Node进程时、部分核心模块就已经被直接加载进内存中,文件模块
则是在运行时动态加载,须要完整的路径分析、文件定位、编译执行过程、速度比核心模块慢。
浏览器会缓存静态脚本文件已提升性能、node对引入过的文件也会作缓存、以减小二次引入时的开销,不一样的地方在于、浏览器仅仅缓存的文件、而Node缓存的事编译和执行以后的对象、不论是核心模块仍是文件模块都具备缓存、不一样的地方是核心模块缓存检查优先于文件模块的缓存检查。还有一种我称他为
特殊模块
也叫自定义模块、这种模块一般是第三方包、这类的模块查找是最费时间的、也是全部模块中最慢的一种!、他的查找过程有点相似原型链、在同层的node_moudles里找、找不到递归自父级、在找不到再往父级的父级、知道找到根节点 /
关于require文件扩展名分析:CommonJs容许你不写文件后缀、没有文件后缀的状况下Node会以 .js .json .node次序补齐扩展名、依次尝试,因此说若是是.json和.node文件咱们本身给他补齐会快一些、还能够同步配合缓存、能够大幅度缓解Node单线程中阻塞式调用的缺陷。
先后端的JavaScript分别搁置在
http的两端
、他们所扮演的角色各不相同、也正是由于如此前者依赖于带宽后者依赖CPU和内存资源、Node模块引入大部分都是同步的、若是前端也采用这种方式会形成体验感特别很差、鉴于网络缘由CommonJs发现并不适合前端、因此出现一个AMD规范(异步模块定义)
AMD文档地址
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});
//建立一个名为"alpha"的模块,使用了require,exports,和名为"beta"的模块:
复制代码
CMD规范是由国内玉伯提出、专门适用于浏览器、异步加载模块,只有模块被真正使用是才去执行加载、CMD规范整合了CommonJS和AMD规范的特色
define(function(require, exports, module){
var module2 = require('./module')
//也能够引入依赖模块(异步)
require.async('./module1', function (m3) {
...
})
//暴露模块
exports.xxx = value
})
复制代码
ES6模块化,也是如今用的最多的模块化技术,在ES6中每个模块便是一个文件,在文件中定义的变量,函数,对象在外部是没法获取的。您须要把它暴露出去才能够被使用!
import和require的区别
//【es6】
//index.js
import mode from "./mode.js"
console.log(mode(1,2))
//mode.js
function add(a,b){
return a + b
}
export default add;
//或者
//mode.js
export function add(a,b){
return a + b
}
//index
import { add } from "./mode.js"
复制代码
总结:ES6模块和CommonJs模块主要有如下两大区别
一、CommonJs模块输出的是一个值的拷贝,ES6模块输出的是值的引用。
二、CommonJs模块是运行时加载,ES6模块是编译时输出接口。