大神的node书,免费javascript
视频:https://node.university/courses/short-lectures/lectures/3949510css
另外一本书:全栈JavaScript,学习backbone.js node.js and MongoDB. html
1,2章: 前端
node没有window, 所以也就没有document对象模型,没有DOM,没有hierarchy of element。java
node有global object.(小写字母),能够在任何node环境,文件,app中使用。node
你能够在global object上建立property,同时它也有内建的properties。这些properties也是global的,所以能够用在anywhere。git
在browser,有内建的modules。github
可是node没有core modules,经过文件系统可使用各类modules。web
进入node控制台,直接在terminal输入node, 这是一个virtual 环境,一般称为read-eval-print-loopajax
能够直接执行Node.js/JavaScript代码。
⚠️:
require()方法,是node.js的modules功能,在chrome browser 控制台上会报告❌ReferenceError。
语法:
node filename node -e "直接输入javaScript代码" //如$ node -e "console.log(new Date())
参数e, 是evaluate script, -e, --eval=...
Node.js使用chrome v8引擎和ESCAScript,所以大多数语法和前端js相似。
大多数时候支持自动typecasing。primitives包括:String, Number, Boolean, Undefined, Null。
Everything else is an object。包括:Class, Function, Array, RegExp。
在Js,String, Number, Boolean对象有帮助方法:
//例子: 'a' === new String('a') //false, 由于使用new String会返回对象 //因此用toString() 'a' === new String('a').toString() // true //或者使用==,执行自动typecasing, ===加入了类型判断
Buffer是Node.js增长的数据类型。
它是一个有效的数据存储data store.
它功能上相似Js的ArrayBuffer。
⚠️:(具体内容,如何建立,使用未看。)
Node8之后的版本都支持ES6。
好比,箭头函数,使用class, 能够extend另外一个对象{...anotherObject}, 动态定义属性名,使用super()关键字,使用函数的短语法。
在Node.js,函数最重要,它们是对象!能够有属性。
使用function expression定义一个函数,能够anonymous。例子:
//outer 'this' const f = () => {
//still outer "this" console.log('Hi') return true }
JavaScript把函数当成对象,因此函数也能够做为参数传递给另外一个函数,嵌套函数会发生callbacks。
let arr4 = new Array(1,"Hi", {a:2}, () => {console.log('boo')}) arr4[3]() // boo
从Array.prototype,global object继承了一些方法。
JavaScript没有classes的概念,对象都是直接继承自其余对象,即prototypal inheritance!
在JS有几种继承模式的类型:
ES6,引用了class,但本质未变,只是写法上更方便。使用了new , class, extends关键字。
具体见以前博客:https://www.cnblogs.com/chentianwei/p/10197813.html
传统的是函数继承模式:
//函数user let user = function(ops) { return { firstName: ops.firstName || 'John', lastName: ops.lastName || 'Doe', email: ops.email || 'test@test.com', name: function() { return this.firstName + this.lastName} } } //继承函数user, let agency = function(ops) { ops = ops || {} var agency = user(ops) agency.customers = ops.customers || 0 agency.isAegncy = true return agency }
每一个Node.js script的运行,都是一个系统进程。
可使用process对象获得,当前进程的相关信息:
process.pid
process.cwd()
node -e "console.log(process.pid)"
浏览器中的window, document对象都不存在于Node.js.
global是全局对象,可使用大量方法。如console, setTimeout(), global.process, global.require(), global.module
例子: global.module
Module { id: '<repl>', exports: {}, parent: undefined, filename: null, loaded: false, children: [], paths: [ '/Users/chentianwei/repl/node_modules', '/Users/chentianwei/node_modules', '/Users/node_modules', '/node_modules', '/Users/chentianwei/.node_modules', '/Users/chentianwei/.node_libraries', '/Users/chentianwei/.nvm/versions/node/v11.0.0/lib/node' ] }
process对象有一系列的有用的信息和方法:
//退出当前进程,若是是在node环境编辑器,直接退出回到终端目录: process.exit()
⚠️在node环境,直接输入process,获得process对象的全部方法和信息。
module.exports = (app) => { // return app }
const messages = require('./routes/messages.js')
真实案例使用:
const messages = require(path.join(__dirname, 'routes', 'messages.js'))
解释:
_dirname得到绝对路径, 在加上routes/message.js,获得真实的路径。
核心/基本模块
Node.js不是一个沉重的标准库。核心模块很小,但足够创建任何网络应用。
Networking is at the core of Node.js!
主要但不是所有的core modules, classes, methods, and events include the following:
http
(http://nodejs.org/api/http.html#http_http): Allows to create HTTP clients and serversutil
(http://nodejs.org/api/util.html): Has a set of utilitiesquerystring
(http://nodejs.org/api/querystring.html): Parses query-string formatted dataurl
(http://nodejs.org/api/url.html): Parses URL datafs
(http://nodejs.org/api/fs.html): Works with a file system (write, read)
Buffer
and String
types
留意咱们须要package.json, node_modules文件夹来在本地安装modules:
$ npm install <name>
例子:
npm install superagent //而后在program.js,引进这个模块。 const superagent = require('superagent')
使用npm的一大优点,全部依赖都是本地的。
好比:
module A 使用modules B v1.3,
module C 使用modules B v2.0
A,C有它们各自的B的版本的本地拷贝。
这种策略比Ruby和其余一些默认使用全局安装的平台更好。
最好不要把node_modules文件夹放入Git repository,当这个程序是一个模块会被其余app使用的话。
固然,推荐把node_modules放入会部署的app中,这样能够防备因为依赖更新致使的意外损害。
callbacks让node.js异步。使用promise, event emitters,或者async library能够防止callback hell
Node.js主要用于创建networking app包括web apps。
由于自然的异步和内建的模块(net, http),Node.js在networks方面快速发展。
下面是一个例子:
建立一个server object, 定义请求handler, 传递数据回到recipient,而后开启server.js。
const http = require('http') const port = 3000 const server = http.createServer((req, res) => { res.writeHead(200, {'Content-Type': 'text/plain'}) res.end('Hello World\n') }).listen(port, () => { console.log(`Server running at http://localhost:${port}`) })
首先,须要用http module。并设置服务port.
而后,建立一个server, 它有一个回调函数,函数包括response的处理代码。
为了设置right header和status code:
res.writeHead(200, {'Content-Type': 'text/plain'})
再输出一个字符串,使用end symbol.
req和res参数是关于一个HTTP request和response data的信息。另外这2个参数可使用stream(这是一个模块)
再而后,为了让server接受请求requests,使用listen()方法
最后,再terminal输入:
node server.js
terminals上显示console.log的信息:
Server running at http://localhost:3000 //在浏览器打开链接,可看到'Hello World'字样。这是res.end()实现的。
现代软件开发者,可使用如Chrome Developer Tools, Firfox Firebug。
由于Node.js和浏览器 JavaScript环境相似,因此咱们可使用大量丰富的Debug工具:
最好的debugger是 console.log(), 😄。由于它不会打断interrupt the flow。
首先,把debugger关键字,放在代码内。
而后,使用开启一个js文件的检查:
node inspect program.js
使用:
next
, n
: step to the next statementcont
, c
: continue until the next debugger/break point更多的见the official web site(http://nodejs.org/api/debugger.html).
非GUI,不直观。
备注(原书提供的node-inspector安装不上,打开其git,提示我看这篇文章:
使用chrome自带的EevTools便可。
用法:
全部的chrome devtool功能均可以使用。
node官方的debug文档:
https://nodejs.org/en/docs/guides/debugging-getting-started/
缺点是:没法在原文件上断点。dubugger!
Visual Studio Code (https://code.visualstudio.com/nodejs
被推荐的一个免费的跨平台的Node.js编辑器,包括内建terminal, Node.js debugging。和大量扩展功能。
被高度推荐:使用方法见(廖雪峰)
atom能够在原文件断点可是功能弱,可使用chrome代替。
Node.js程序储存在内存,若是改变source code, 咱们须要重启进程process(i.e., node).
手动killing 进程并重开启一个新的. (Control + C on mac)
⚠️提示:使用Express.js,它会自动reload模版文件,为每次的新请求。因此server无需重启。
(摘录)
Node.js相比Ruby或Java是一个比较年轻的平台。Express是很流行的框架之一。
Express是web框架,基于core Node.js http和 Connect (http://www.senchalabs.org/connect) 组件。
组件被称为中间件middleware。它们是框架哲学的基石,配置大于约定。
所以,Express是高度配置的,在开发阶段是灵活的和高度客制的。
若是你写node web apps, 只使用core Node.js modules,你会发现你反复的一遍遍的造轮子:
Express.js提供了MVC-like的结构为你的web apps。
models可使用 Mongoose (http://mongoosejs.com) or Sequelize (http://sequelizejs.com) libraries 。
Express.js相似Ruby on Rails. 区别是rails是约定大于配置。
虽然Express是最流行的框架,但仍有不一样特点的新框架出现,如Meteor。
一个主文件,通常叫server.js, app.js, index.js。
通常这个文件是node命令的开始, 或者做为模块export这个文件 。
在这个文件内,咱们作:
当Express.js app运行,它监听请求。每一个进来的请求经过一个定义的中间件链条和路径被处理processed。
经过execution flow进行控制。
建立Express.js app使用,2种方法:
1. express-generator:一个全局的npm包,提供命令行工具来快速的建立程序手脚架--推荐快速的prototyping和服务端(thick server)渲染程序。
2. express: 一个本地的包模块在Node.js app's的node_modules文件夹内--推荐任何程序,须要import express(使用require()或import)
看看当前版本,而后安装:
npm view express npm i -g express-generator@latest
express --version
注意⚠️mac用户,可能须要安装权限。使用sudo。
创建一个文件夹,进入,而后建立package.json,
npm init
而后安装一个版本:
$ npm install express@4.15.4 --exact
{ "name": "hello-simple", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "express": "^4.15.4" } }
package-lock.json
,用于锁定版本。
若是想要改变版本:
npm install express@4.15.5 --save
server.js
fileconst express = require('express') let app = express() app.all('*', (req, res) => { res.send('Welcome to Practical node.js!') }) app.listen(3000, () => { return console.log('Open at localhost:3000') })
Then launch it with node server.js
to see "Welcome to Practical Node.js!" in a browser at http://localhost:3000.
Comparable with Ruby on Rails and many other web frameworks, Express.js comes with a CLI for jump-starting your development process
帮助命令:
$ express -h
//运行一个terminal命令,建立手脚架 express [options] [dir|appname]
-v
, --view <engine>
: Add view support (defaults to pug)-c <engine>
, --css <engine>
: Add stylesheet <engine>
support, such as LESS (http://lesscss.org), Stylus(http://learnboost.github.io/stylus) or Compass(http://compass-style.org) (by default, plain CSS is used)--git
: Add .gitignore-f
, --force
: Force app generation on a nonempty directory下面的步骤:
$ express -c styl express-styl //根据terminal上的提示:输入下面的代码,进入文件夹并安装相关依赖。 $ cd express-styl && npm install
//运行app $ DEBUG=express-styl:* npm start
建立了一个app,👍!
进入express-styl/app.js:
const express = require('express'); const path = require('path'); const favicon = require('serve-favicon'); const logger = require('morgan'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const stylus = require('stylus'); const index = require('./routes/index'); const users = require('./routes/users'); let app = express(); // view engine setup app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); // uncomment after placing your favicon in /public //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.use(cookieParser()); app.use(stylus.middleware(path.join(__dirname, 'public'))); app.use(express.static(path.join(__dirname, 'public'))); app.use('/', index); app.use('/users', users); // catch 404 and forward to error handler app.use(function(req, res, next) { var err = new Error('Not Found'); err.status = 404; next(err); }); // error handler app.use(function(err, req, res, next) { // set locals, only providing error in development res.locals.message = err.message; res.locals.error = req.app.get('env') === 'development' ? err : {}; // render the error page res.status(err.status || 500); res.render('error'); }); module.exports = app;
server文件有routes, 来自routes文件夹。
Express app 被输出:module.exports
被发射伴随listen(),在bin/www文件内。
下面看一下app.js内的代码:
能够在express-styl/app.js内看到自动生成的2个routes:
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
//...
app.use('/', indexRouter);
app.use('/users', usersRouter);
第一行app.use():处理全部到home page的请求。如:http://localhost:3000/
第二行app.use():处理到/users,如http://localhost:3000/users.
2个routes处理URLs是大小写字母敏感的。
默认, Express.js不容许开发者经过query string arguments 来导航routes
GET: www.webapplog.com/books/?id=10&ref=201
而是,使用middleware:
app.use((req, res, next) => {
next()
})
// next是一个回调函数。
开发者也能够完成response, 经过使用send(), end(), render()或其余Express method,
或者传递一个❌对象给next()来回调!
app.use((req, res, next) => { if (!req.session.loggedIN) { return next(new Error('Not enough permissions')) } if (req.session.credits === 0) { return res.render('not-enough-credits.pug') } next() })
下面是另外一个例子:
用条件逻辑来处理一个查询string, 使用req.query对象:
app.use((req, res, next) => { if (req.query.id) { //处理id,而后当完成后,调用next() } else if (req.query.author) { //和id相同的方式approach } else if (req.query.id && req.query.ref) { //当id and ref存在时,处理。 } else { next() } }) app.get('/about', (req, res, next) => { //这里的代码,在query string middleware以后执行。 })
只要request同样,每一个req或者res对象在随后的中间件函数或者request handler functions内,req或res对象仍是这个req or res对象。
req对象->中间件1函数->中间件2函数->请求处理函数->...->req对象(内部的key/value发生了变化)
这个特色,让开发者能够decorate a reference or a value。例如:
让第一个中间件的req对象获得数据库传入的数据,随后的第2个中间件中的req对象,就是第一个中间件执行完代码后的req对象, 这个req对象包含数据库数据。
(个人我的理解:相似Promise.then()链条传递的promise对象.)
app.use((req, res, next) => { req.db = const db = mongoskin.db('mongodb://@localhost:27017/test') }) //在上一个中间件执行后,req对象新增了db属性。这个req对象被传入下一个中间件 app.use((req, res, next) => { req.articles = req.db.collection('articles') }) //上个中间件执行完成后,req对象又新增了articles属性。这个req对象被传入下一个中间件: app.post('/users', (req, res, next) => {
// use req.db or req.articles req.db.collection('users').insert({}, {}, (error, results)=>{ req.articles.insert({}, {}, (error, results)=>{ res.send() }) }) })
回到app.js 文件。对root请求处理, 是"/",至关于routes/index.js。
来自HTTP request 的Everything 都在req对象内,而且把结果写入res对象。
在express-styl/routes文件夹,分别存在index.js和users.js,这2个文件导出后,会被app.js引入并使用。
var express = require('express') var router = express.Router() // 获得home , res对象使用render()方法。 router.get('/', function(req,res, next) { res.render('index', {title: 'Express'}) })
module.exports = router
//users.js var express = require('express'); var router = express.Router(); /* GET users listing. */ router.get('/', function(req, res, next) { res.send('respond with a resource'); }); module.exports = router;
中间件是Express.js框架的支柱,脊梁骨。
在express-styl/app.js,每行/每一个声明在routes上面,都是中间件。
这个中间件包括pass-through functions。当请求在中间件内旅行时,中间件会对请求request作有用或有帮助的事情。
const express = require('express'); const path = require('path'); const favicon = require('serve-favicon'); const logger = require('morgan'); const cookieParser = require('cookie-parser'); const bodyParser = require('body-parser'); const stylus = require('stylus'); //... app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); app.use(logger('dev')); app.use(bodyParser.json()); app.use(bodyParser.urlencoded()); app.use(cookieParser()); app.use(express.static(path.join(__dirname, 'public')));
例如:
bodyParser(), cookieParser()
add HTTP request payload (req.body
) 并 parsed cookie data(req.cookie)
app.use(logger('dev')),在terminal上打印每个请求。
在Express v3, 这些中间件是内建的module。
在v4之后,Express Generator 声明和包含了app.js 和 package.json, 咱们使用npm install来增长须要的modules。如:static-favicon
, morgan
, cookie-parser
and body-parser.
这是咱们在一个典型的Express.js中的app.js内,定义配置声明。使用app.set()
第一个参数是名字,第二个参数是值。
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
* Module dependencies. var app = require('../app'); var debug = require('debug')('express-styl:server'); var http = require('http');
//Get port from environment and store in Express. //定义port变量,并赋值。当server启动后,会被用到。 var port = normalizePort(process.env.PORT || '3000'); app.set('port', port);
建立http server
var server = http.createServer(app);
//监听提供的端口,并当error和listening事件,发生时执行onError, onListening回调函数。 server.listen(port); server.on('error', onError); server.on('listening', onListening);
onError和onListening回调函数,定义在这个www文件内。
Pug是一个模版引擎。相似Ruby on Rails的Haml。它使用whitespace和缩排列。
doctype html html head title= title link(rel='stylesheet', href='/stylesheets/style.css') body block content
第4章会讲解它。(相似RoR的slim)可用可不用,每感受效率提升多少,看开发团队是否用。
建立一个简单的blog页面,及相关功能。
从一个开发者的视角,app有如下元素:
这个程序包括全部的CRUD元素。另外使用两个方法发数据到server:
第一种是现代开发网页弃用的方式,速度太慢。
第2种是发送和接收数据,经过REST API/HTTP request和渲染客户端HTML。这些行为使用前端框架,例如React, Angular, Vue.js等等( many others (http://todomvc.com))。这些框架十分流行。
在hood罩子下面,事实上全部前端都使用jQuery's ajax()方法。
为了演示,本例子使用REST API经过$.ajax()。
同时,这个例子不使用CLI手脚架。逐步演示代码。若是建立一个Express.js。让你理解在这个框架下代码是如何组织在一块儿工做的。
开始把,建立咱们的程序文件夹。
一个例子,不使用generators, 额外的modules和middleware。包括如下部分:
Express.js是高度配置的,全部文件夹均可以重命名。不过,默认的文件夹不要更名:
这就够了。若是想要为以后的章节的其余案例建立新的文件夹,可建立:
mkdir hello-world cd hello-world mkdir {public,public/css,public/img,public/js,db,views,views/includes,routes}
上一步,没有使用Express.js Generator。
npm不只是一个注册器,也是一个依赖管理工具。它永久创建程序文件package.json。
npm init //建立package.json
$ npm install express //安装最新的稳定版本。
⚠️推荐使用明确的指定版本,使用@符号。
npm install express@4.15.4 --save
再安装
另外一个建立package.json文件的方法是拷贝粘贴代码到package.json, 而后运行npm install
对脚本进行修改:如⬇️所见:
{{ "name": "hello-advanced", "version": "0.0.1", "private": true, "scripts": { "start": "node app.js" }, "dependencies": { "express": "4.15.4", "pug": "2.0.0-rc.4" } }
main entry point,即设定一个主文件main file:
通常使用app.js或者index.js, 执行这个脚本文件使用如下随意的一个:
$ node app.js
$ node app
$ npm start
//由于在package.json内设定了"scripts": { "start": "node app.js"}
下一步,让咱们建立app.js
主文件的结构基本内容包括:
1到7的顺序很重要,由于请求从上到下的通过中间件的链条。
打开app.js,而后:
//引入模块。 // path module 用于处理文件和目录的路径。 const express = require('express') const http = require('http') const path = require('path') // Express使用一个函数模式,执行函数,获得一个实例。 let app = express();
// 使用express实例方法set('name', 'value')来进行配置 app.set('appName', 'hello-advanced')
还须要定义一些配置在app.js:
若是想要使用环境变量提供的port number,使用模块process的方法:
process.env.PORT
代码以下:
app.set('port', process.env.PORT || 3000) app.set('views', path.join(_dirname, 'views')) app.set('view engine', 'html')
__dirname
is an absolute path to the folder with the source code script (a file in which the global variable is called). 获得程序代码所在的文件夹。
本application是"/Users/chen/node_practice/hello-world"
//如何查询 node inspect app.js //而后在控制台输入__dirname,便可返回路径
path.join([...paths])是path模块的方法之一
// ..返回上一个文件夹 path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); // Returns: '/foo/bar/baz/asdf'
中间件是Express.js框架的backbone。
它包括:
Middleware用于组织和复用代码,本质就是带参数的函数。(第6章会作更多的讲解)
下一个组件是routes。Routes处理requests。定义路径使用帮助方法app.VERB(url, fn1, fn2, ...)
fn:request handlers
url:是URL pattern in RegExp
VERB:是get , post, put, patch, del, all, 用于捕捉不一样的请求。
Routes按它们被定义的顺序,被处理。通常routes被放在middleware后面,可是一些中间件放在routes后面。例如error handler。
下图展现一个请求的旅行:
在本app Hello World, 只使用一个route,来获得全部关于URLs的方法的请求(*通配符号wildcard百搭牌)
app.all('*', (req, res) => {
res.render('index', {msg: 'Welcome to Practical Note.js!'})
})
在这个请求内,使用res.render()函数渲染视图模版。res.render()的第一个参数是名字'index', 第二个参数是数据对象data object。
res.render(viewName, data, callback(error, html))
express的方法。
render()方法调用后,调用core http组件的end()方法,用于完成response。
换言之,中间件的链条不会在res.render()后继续执行代码。
(第4章,详细分析)
可是http.createServer(app).listen()也能够生效。这2个链接的方法都是核心模块http的方法。
监听链接。
http.createServer(app).listen(app.get('port'), () => { console.log(`Express server listening on port ${app.get('port')}`) })
你也可使用https.createServer(app).listen()
for the HTTPS support, 当你准备好部署你的server到产品。
在运行server以前,咱们须要建立views/index.html文件
Express默认使用jade模版,也能够自定义如Pug,
若是想使用原生html模版,须要安装ejs (点击查看原文解释)
npm install ejs //引入ejs var ejs = require('ejs') //设置html engine app.engine('html', ejs.__express) //设置视图引擎, 'view engine'表示没有指定文件模版格式时,默认使用的引擎插件。 app.set('view engine', 'html')
注:在express搭建的服务器中,html引擎没有被配置,直接添加便可;视图引擎已配置,修改配置便可。
index.html内的代码:
<h1>hello</h1> <p>You are welcome</p> // 插入传入模版的数据。 <p><%= msg %></p>
app.engine(ext, callback)
http://expressjs.com/en/4x/api.html#app.engine
Registers the given template engine callback
as ext
.
默认,Express将require()这个基于文件扩展的engine。
app.engine('pug', require('pug').__express);
app.engine('html', require('ejs').renderFile); //也能够用__express方法
$ node app
第2章,学习使用Express.js, 知道它是如何工做的。了解使用手脚架来生成apps。
经过Blog app案例,了解了建立这个程序的过程。
最后,咱们接触了一些主题:settings, request process, routes, Ajax server side, ejs模块产生模版。
下一章,谈谈驱动测试开发。另外会增长一个数据库到Blog routes。展现如何把数据转入到HTML pages!