Node.js
#####################
nodejs是使用C++语言写的。nodejs是用C++开发的一种运行于服务器端的语言,node的底层是C++;且nodejs是一个基于Chrome V8引擎的JavaScript运行环境,而V8是使用C++开发的。
Node.js是用C ++编写、开发的。
Node.js底层是C++(V8也是C++写的)。node的源码在 GitHub网站上 , 项目根目录的src文件夹下很多以 .cc 后缀结尾的文件里有class字眼 ( C++有class而C没有 )。
nodejs是用C++开发的一种运行于服务器端的语言,可以写网站后台程序,可以做服务端应用开发,他的语法就是JAVASCRIPT,会JS,就是会NODEJS,区别于,普通JS是脚本运行客户端,而NODEJS中的JS是运行于服务器端,这么说吧,NODEJS的作用相当PHP,ASP等语言。
且Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。
而V8使用C++开发,并在谷歌浏览器中使用。在运行JavaScript之前,相比其它的JavaScript的引擎转换成字节码或解释执行,V8将其编译成原生机器码(IA-32, x86-64, ARM, or MIPS CPUs),并且使用了如内联缓存(inline caching)等方法来提高性能。有了这些功能,JavaScript程序在V8引擎下的运行速度媲美二进制程序。
V8中实现的ECMAScript中指定 ECMA - 262 ,第3版 运行在Windows XP和Vista,Mac OS X的10.5(雪豹和Linux系统使用IA - 32或ARM处理器。
V8可以独立运行,也可以 嵌入 到任何C++应用程序。项目托管在Google Code上,基于BSD协议,任何组织或个人可以将其源码用于自己的项目中。
Node.js适合用来开发什么样的应用程序呢?
善于I/O,不善于计算。因为Node.js最擅长的就是任务调度,如果你的业务有很多的CPU计算,实际上也相当于这个计算阻塞了这个单线程,就不适合Node开发。
当应用程序需要处理大量并发的I/O,而在向客户端发出响应之前,应用程序内部并不需要进行非常复杂的处理的时候,Node.js非常适合。Node.js也非常适合与web socket配合,开发长连接的实时交互应用程序。
-
Node.js不是一种独立的语言,与PHP、JSP、Python、Perl、Ruby的“既是语言,也是平台”不同,Node.js的使用JavaScript进行编程,运行在JavaScript引擎上(V8)
-
Node.js 是一个开源服务器环境。
-
Node.js 就是运行在服务端的 JavaScript。
-
Node.js 是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。
什么是 Node.js?
- Node.js 是一个开源服务器环境
- Node.js 是免费的
- Node.js 在各种平台 (Windows, Linux, Unix, Mac OS X 等)上运行
- Node.js 在服务器上使用JavaScript
为什么使用 Node.js?
Node.js 使用异步编程!
web 服务器的一项常见任务是在服务器上打开文件并将内容返回给客户端。
以下是PHP或ASP如何处理文件请求的流程:
- 将任务发送到计算机的文件系统。
- 等待文件系统打开并读取文件。
- 将内容返回给客户端。
- 准备好处理下一个请求。
下面是如何使用 Node.js 处理文件请求:
- 将任务发送到计算机的文件系统。
- 准备好处理下一个请求。
- 文件系统打开并读取文件后,服务器将内容返回给客户端。
Node.js 消除了等待,只是继续下一个请求。
Node.js 运行单线程、非阻塞、异步编程,这非常节省内存。
Node.js 能做什么?
- Node.js 可以生成动态页面内容
- Node.js 可以在服务器上创建、打开、读取、写入、删除和关闭文件
- Node.js 可以收集表单数据
- Node.js 可以添加、删除、修改数据库中的数据
什么是 Node.js 文件?
- Node.js 文件包含将在某些事件上执行的任务
- 一个典型的事件是试图访问服务器上的端口
- Node.js 文件必须在服务器上启动才能生效
- Node.js 文件的扩展名为 ".js"
下载 Node.js
官方 Node.js 网站上有 Node.js 的安装说明: https://nodejs.org
入门
在你的电脑上下载并安装 Node.js ,让我们尝试在网络浏览器中显示 "Hello World" 。
创建一个名为 "myfirst.js" 的 Node.js 文件,并添加以下代码:
myfirst.js
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('Hello World!');
}).listen(8080);
将文件保存在计算机上: C:\Users\Your Name\myfirst.js
如果有人(如网络浏览器)试图通过8080端口访问您的计算机,代码将告诉计算机输出 "Hello World!" 。
目前您不必理解代码。这将在后面解释。
命令行界面
Node.js 文件必须在计算机的 "命令行界面" 程序中启动。
如何在计算机上打开命令行界面取决于操作系统。对于 Windows 用户,在搜索框中输入 "cmd" 。
切换到包含文件 "myfirst.js" 的文件夹,命令行界面窗口应该如下所示:
C:\Users\Your Name>_
初始化 Node.js 文件
您刚刚创建的文件执行任何操作前必须由 Node.js 初始化。
启动命令行界面,首先写入 node myfirst.js
然后点击回车键:
初始化 "myfirst.js":
C:\Users\Your Name>node myfirst.js
现在,你的电脑就像一台服务器!
如果有人试图通过8080端口访问你的计算机,他们会收到 "Hello World!" 的回信!
打开浏览器,然后输入地址: http://localhost:8080
什么是 Node.js 中的模块系统?
将模块系统视为与 JavaScript 库等同。
是要包含在应用程序中的一组函数。
内置模块
Node.js 有一套内置模块,无需进一步安装即可使用。
查看我们的 内置模块参考 ,了解完整的 Node.js 模块列表。
加载模块
要加载模块,请将 require()
方法与模块名称一起使用:
var http = require('http');
现在,您的应用程序可以访问 http 模块,并且能够创建一个 http 服务:
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('Hello World!');
}).listen(8080);
npm使用:
npm 在按照 Node.js 时会连带被安装。但有可能不是最新版本,需要 npm install npm@latest -g
升级到最新版本:
npm install npm@latest -g
# 查看 npm 命令列表
$ npm help
# 查看各个命令的简单用法
$ npm -l
# 查看 npm 的版本
$ npm -v
# 查看 npm 的配置
$ npm config list -l
一、npm install
Node
模块采用npm install
命令安装。
每个模块可以“全局安装”,也可以“本地安装”。“全局安装”指的是将一个模块安装到系统目录中,各个项目都可以调用。一般来说,全局安装只适用于工具模块,比如eslint
和gulp
。“本地安装”指的是将一个模块下载到当前项目的node_modules
子目录,然后只有在项目目录之中,才能调用这个模块
如果你希望,一个模块不管是否安装过都重新新安装一遍,可以用-f 或者—force参数
npm install <packageName> --force
# 本地安装
npm install <package name>
# 全局安装
sudo npm install -global <package name>
sudo npm install -g <package name>
# 也支持直接输入Github代码库地址
npm install git://github.com/package/path.git
npm install git://github.com/package/path.git#0.1.0
# 强制重新安装
npm install <packageName> --force
# 如果你希望,所有模块都要强制重新安装,那就删除node_modules目录,重新执行npm install
rm -rf node_modules
npm install
安装不同版本
install 命令总是安装模块的最新版本,如果要安装模块的特定版本,可以在模块名后面加上@和版本号。
$ npm install sax@latest $ npm install sax@0.1.1 $ npm install sax@">=0.1.0 <0.2.0" # 如果使用--save-exact参数,会在package.json文件指定安装模块的确切版本 $ npm install readable-stream --save --save-exact $ npm install sax --save $ npm install node-tap --save-dev # 或者 $ npm install sax -S $ npm install node-tap -D # 如果要安装beta版本的模块,需要使用下面的命令 # 安装最新的beta版 $ npm install <module-name>@beta (latest beta) # 安装指定的beta版 $ npm install <module-name>@1.3.1-beta.3 # npm install默认会安装dependencies字段和devDependencies字段中的所有模块,如果使用--production参数,可以只安装dependencies字段的模块 $ npm install --production # 或者 $ NODE_ENV=production npm install
二、npm update
npm update命令可以更新本地安装的模块
# 升级当前项目的指定模块
$ npm update [package name]
# 升级全局安装的模块
$ npm update -global [package name]
它会先到远程仓库查询最新版本,然后查询本地版本。如果本地版本不存在,或者远程版本较新,就会安装。
使用-S
或--save
参数,可以在安装的时候更新package.json
里面模块的版本号。
注意,从npm v2.6.1
开始,npm update只更新顶层模块,而不更新依赖的依赖,以前版本是递归更新的。如果想取到老版本的效果,要使用下面的命令。
$ npm --depth 9999 update
三、npm uninstall
npm uninstall命令,卸载已安装的模块
$ npm uninstall [package name]
# 卸载全局模块
$ npm uninstall [package name] -global
四、npm run
npm 不仅可以用于模块管理,还可以用于执行脚本。package.json 文件有一个 scripts 字段,可以用于指定脚本命令,供npm直接调用。
npm run 命令会自动在环境变量 $PATH 添加 node_modules/.bin 目录,所以 scripts 字段里面调用命令时不用加上路径,这就避免了全局安装 NPM 模块。
npm run 如果不加任何参数,直接运行,会列出 package.json 里面所有可以执行的脚本命令。
npm内置了两个命令简写,npm test 等同于执行 npm run test,npm start 等同于执行 npm run start。
$ npm i eslint --save-dev
npm run dev命令应该是我们工作当中最常使用的命令,但是具体是如何运行的相信很多小伙伴都没有深入了解过,下面就npm run dev的底层运行由浅入深地进行讲解。
理解
在npm run dev的时候,首先会去项目的package.json文件里找scripts 里找对应的 dev ,然后执行 dev 的命令。
例如启动vue项目 npm run serve的时候,实际上就是执行了vue-cli-service serve 这条命令。
package.json文件:
{ "name": "h5", "version": "1.0.7", "private": true, "scripts": { "dev": "vue-cli-service serve" }, }
复制代码
(1)灵魂第一问:
那可能有的小伙伴会问了,为什么不直接执行vue-cli-service serve
命令呢?
答:因为 直接执行vue-cli-service serve
,会报错,因为操作系统中没有存在vue-cli-service
这一条指令
(2)灵魂第二问:
那可能有的小伙伴又会问了,既然vue-cli-service serve
这条指令不存在操作系统中,为什么执行npm run dev
的时候,也就是相当于执行了vue-cli-service serve
,为什么这样它就能成功,而且不报指令不存在的错误?
答:
- 我们在安装依赖的时候,是通过npm install 来执行的,npm 在安装依赖的时候,会在
node_modules/.bin/
目录中创建好vue-cli-service
为名的几个可执行文件。 .bin
目录不是任何一个 npm 包。该目录下的文件,表示一个个软链接,打开文件可以看到文件顶部写着#!/bin/sh
,表示这是一个脚本。- 所以当使用
npm run dev
执行vue-cli-service serve
时,虽然没有安装vue-cli-service
的全局命令,但是 npm 会到./node_modules/.bin
中找到vue-cli-service
文件作为 脚本来执行,则相当于执行了./node_modules/.bin/vue-cli-service serve
。
(3)灵魂第三问:
那可能有的小伙伴又会较真的问了,既然.bin
目录下的文件表示软连接,那这个bin目录下的那些软连接文件是哪里来的呢?它又是怎么知道这条软连接是执行哪里的呢?
答:
- bin目录下的那些软连接存在于项目最外层的package-lock.json文件中。
- 从 package-lock.json 中可知,当我们
npm install
整个新建的vue项目的时候,npm 将 bin/vue-cli-service.js 作为 bin 声明了。 - 所以在
npm install
时,npm 读到该配置后,就将该文件软链接到 ./node_modules/.bin 目录下,而 npm 还会自动把node_modules/.bin加入$PATH,这样就可以直接作为命令运行依赖程序和开发依赖程序,不用全局安装了。 - 也就是说,npm install 的时候,npm 就帮我们把这种软连接配置好了,其实这种软连接相当于一种映射,执行npm run dev 的时候,就会到 node_modules/bin中找对应的映射文件,然后再找到相应的js文件来执行。
至此经过灵魂三问相信您对于npm run dev的底层运行已经有了一些理解。
pre- 和 post- 脚本
npm run 为每条命令提供了 pre- 和 post- 两个钩子(hook)。以 npm run lint 为例,执行这条命令之前,npm会先查看有没有定义 prelint 和 postlint 两个钩子,如果有的话,就会先执行 npm run prelint,然后执行 npm run lint,最后执行npm run postlint。
全局模块(在命令行的任何地方可以使用) 局部模块
- 为什么全局模块可以直接在任何地方使用
全局的模块
- 必须使用package.json 中配置bin参数
- ! /usr/bin/env node
使用 package.json
package.json 位于模块的目录下,用于定义包的属性。接下来让我们来看下 express 包的 package.json 文件,位于 node_modules/express/package.json 内容:
{ "name": "express", "description": "Fast, unopinionated, minimalist web framework", "version": "4.13.3", "author": { "name": "TJ Holowaychuk", "email": "tj@vision-media.ca" }, "contributors": [ { "name": "Aaron Heckmann", "email": "aaron.heckmann+github@gmail.com" }, { "name": "Ciaran Jessup", "email": "ciaranj@gmail.com" }, { "name": "Douglas Christopher Wilson", "email": "doug@somethingdoug.com" }, { "name": "Guillermo Rauch", "email": "rauchg@gmail.com" }, { "name": "Jonathan Ong", "email": "me@jongleberry.com" }, { "name": "Roman Shtylman", "email": "shtylman+expressjs@gmail.com" }, { "name": "Young Jae Sim", "email": "hanul@hanul.me" } ], "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/strongloop/express.git" }, "homepage": "http://expressjs.com/", "keywords": [ "express", "framework", "sinatra", "web", "rest", "restful", "router", "app", "api" ], "dependencies": { "accepts": "~1.2.12", "array-flatten": "1.1.1", "content-disposition": "0.5.0", "content-type": "~1.0.1", "cookie": "0.1.3", "cookie-signature": "1.0.6", "debug": "~2.2.0", "depd": "~1.0.1", "escape-html": "1.0.2", "etag": "~1.7.0", "finalhandler": "0.4.0", "fresh": "0.3.0", "merge-descriptors": "1.0.0", "methods": "~1.1.1", "on-finished": "~2.3.0", "parseurl": "~1.3.0", "path-to-regexp": "0.1.7", "proxy-addr": "~1.0.8", "qs": "4.0.0", "range-parser": "~1.0.2", "send": "0.13.0", "serve-static": "~1.10.0", "type-is": "~1.6.6", "utils-merge": "1.0.0", "vary": "~1.0.1" }, "devDependencies": { "after": "0.8.1", "ejs": "2.3.3", "istanbul": "0.3.17", "marked": "0.3.5", "mocha": "2.2.5", "should": "7.0.2", "supertest": "1.0.1", "body-parser": "~1.13.3", "connect-redis": "~2.4.1", "cookie-parser": "~1.3.5", "cookie-session": "~1.2.0", "express-session": "~1.11.3", "jade": "~1.11.0", "method-override": "~2.3.5", "morgan": "~1.6.1", "multiparty": "~4.1.2", "vhost": "~3.0.1" }, "engines": { "node": ">= 0.10.0" }, "files": [ "LICENSE", "History.md", "Readme.md", "index.js", "lib/" ], "scripts": { "test": "mocha --require test/support/env --reporter spec --bail --check-leaks test/ test/acceptance/", "test-ci": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --require test/support/env --reporter spec --check-leaks test/ test/acceptance/", "test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require test/support/env --reporter dot --check-leaks test/ test/acceptance/", "test-tap": "mocha --require test/support/env --reporter tap --check-leaks test/ test/acceptance/" }, "gitHead": "ef7ad681b245fba023843ce94f6bcb8e275bbb8e", "bugs": { "url": "https://github.com/strongloop/express/issues" }, "_id": "express@4.13.3", "_shasum": "ddb2f1fb4502bf33598d2b032b037960ca6c80a3", "_from": "express@*", "_npmVersion": "1.4.28", "_npmUser": { "name": "dougwilson", "email": "doug@somethingdoug.com" }, "maintainers": [ { "name": "tjholowaychuk", "email": "tj@vision-media.ca" }, { "name": "jongleberry", "email": "jonathanrichardong@gmail.com" }, { "name": "dougwilson", "email": "doug@somethingdoug.com" }, { "name": "rfeng", "email": "enjoyjava@gmail.com" }, { "name": "aredridel", "email": "aredridel@dinhe.net" }, { "name": "strongloop", "email": "callback@strongloop.com" }, { "name": "defunctzombie", "email": "shtylman@gmail.com" } ], "dist": { "shasum": "ddb2f1fb4502bf33598d2b032b037960ca6c80a3", "tarball": "http://registry.npmjs.org/express/-/express-4.13.3.tgz" }, "directories": {}, "_resolved": "https://registry.npmjs.org/express/-/express-4.13.3.tgz", "readme": "ERROR: No README data found!" }
Package.json 属性说明
- name - 包名。
- version - 包的版本号。
- description - 包的描述。
- homepage - 包的官网 url 。
- author - 包的作者姓名。
- contributors - 包的其他贡献者姓名。
- dependencies - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。
- repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。
- main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
- keywords - 关键字
##################