├── .gitignore ├── 404.html ├── LICENSE ├── README.md ├── _config.yml ├── app.js ├── count.js ├── handler.js ├── hello-world-web.js ├── index.html ├── p11.js ├── p2.js ├── p3.js ├── p4.js ├── p5.js ├── p6.js ├── p7.js ├── p8.js ├── p9.js ├── package.json ├── readMe.txt ├── review.html ├── router.js ├── server.js ├── stuff └── writeMe.txt └── writeMe.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | -------------------------------------------------------------------------------- /404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 404 11 | 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 able8 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hello-nodejs 2 | 3 | 轻松学 Node.js 基础篇 入门 4 | 5 | 视频地址 6 | 7 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 8 | - [b站](https://www.bilibili.com/video/av21010015) 9 | 10 | 常用链接 11 | 12 | - [Node.js 官网](https://nodejs.org/zh-cn/) 13 | - [Node.js 中文网](http://nodejs.cn) 14 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 15 | 16 | 看视频整理要点笔记: 17 | 18 | --- 19 | 20 | - [目录](#hello-nodejs) 21 | - [1.介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 22 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 23 | - [3.回调函数](#3%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0) 24 | - [4.模块](#4%E6%A8%A1%E5%9D%97) 25 | - [5.事件 events](#5%E4%BA%8B%E4%BB%B6-events) 26 | - [6.读写文件(同步和异步)](#6%E8%AF%BB%E5%86%99%E6%96%87%E4%BB%B6%E5%90%8C%E6%AD%A5%E5%92%8C%E5%BC%82%E6%AD%A5) 27 | - [7.创建和删除目录](#7%E5%88%9B%E5%BB%BA%E5%92%8C%E5%88%A0%E9%99%A4%E7%9B%AE%E5%BD%95) 28 | - [8.流和管道](#8%E6%B5%81%E5%92%8C%E7%AE%A1%E9%81%93) 29 | - [9.web 服务器 part1 介绍](#9web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part1-%E4%BB%8B%E7%BB%8D) 30 | - [10.web 服务器 part2 响应JSON](#10web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part2-%E5%93%8D%E5%BA%94json) 31 | - [11.web 服务器 part3 响应HTML页面](#11web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part3-%E5%93%8D%E5%BA%94html%E9%A1%B5%E9%9D%A2) 32 | - [12.web 服务器 part4 用模块化思想组织代码](#12web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part4-%E7%94%A8%E6%A8%A1%E5%9D%97%E5%8C%96%E6%80%9D%E6%83%B3%E7%BB%84%E7%BB%87%E4%BB%A3%E7%A0%81) 33 | - [13.web 服务器 part5 路由](#13web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part5-%E8%B7%AF%E7%94%B1) 34 | - [14.web 服务器 part6 重构路由代码](#14web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part6-%E9%87%8D%E6%9E%84%E8%B7%AF%E7%94%B1%E4%BB%A3%E7%A0%81) 35 | - [15.web 服务器 part7 使用 GET或 POST 请求 发送数据](#15web-%E6%9C%8D%E5%8A%A1%E5%99%A8-part7-%E4%BD%BF%E7%94%A8-get%E6%88%96-post-%E8%AF%B7%E6%B1%82-%E5%8F%91%E9%80%81%E6%95%B0%E6%8D%AE) 36 | - [16.包管理器 npm](#16%E5%8C%85%E7%AE%A1%E7%90%86%E5%99%A8-npm) 37 | - [17.package.json 文件](#17packagejson-%E6%96%87%E4%BB%B6) 38 | - [18.nodemon监控文件并重启服务](#18nodemon%E7%9B%91%E6%8E%A7%E6%96%87%E4%BB%B6%E5%B9%B6%E9%87%8D%E5%90%AF%E6%9C%8D%E5%8A%A1) 39 | 40 | --- 41 | 42 | ## 1.课程介绍与开发环境搭建 43 | 44 | - 主要包括 45 | - nodejs 基础知识 46 | - web 服务器 47 | - 异步 同步 阻塞 非阻塞 48 | 49 | - 课程基础 50 | - javascript 基础 51 | - html 基础 52 | - 命令行基础 53 | 54 | - Node.js 介绍 55 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 56 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 57 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 58 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 59 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 60 | - V8 引擎是开源的,由 C++ 语言编写,性能高 61 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 62 | 63 | - Node.js 安装 64 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 65 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 66 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 67 | - macOS 安装完提示如下 68 | 69 | ```sh 70 | This package has installed: 71 | • Node.js v8.11.4 to /usr/local/bin/node 72 | • npm v5.6.0 to /usr/local/bin/npm 73 | Make sure that /usr/local/bin is in your $PATH. 74 | ``` 75 | 76 | - Node.js 用途 77 | - javascript 运行环境 78 | - 操作文件(grunt gulp webpack) 79 | - 操作数据库 80 | - 写后端 api 81 | - 命令行工具 82 | - web 开发 83 | - 聊天室 84 | 85 | - JavaScript 语句后应该加分号么? 86 | - [知乎讨论](https://www.zhihu.com/question/20298345) 87 | - 代码风格而已,没有定论 88 | - 少分号更易读,不累 89 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 90 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 91 | 92 | ## 2.全局对象 93 | 94 | - 全局对象 95 | - 不用导入,直接使用的对象 96 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 97 | - Buffer 类,用于处理二进制数据 98 | - console,用于打印 stdout 和 stderr 99 | - global, 全局的命名空间对象 100 | - process,进程对象 101 | - setTimeout(callback, delay[, ...args]) 102 | - setInterval(callback, delay[, ...args]) 103 | - setImmediate(callback[, ...args]) 104 | - clearTimeout(timeoutObject) 105 | - clearInterval(intervalObject) 106 | - clearImmediate(immediateObject) 107 | 108 | - 以下变量虽然看起来像全局变量,但实际上不是 109 | - 全局变量在所有模块中均可使用 110 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 111 | - __dirname 112 | - __filename 113 | - exports 114 | - module 115 | - require() 116 | 117 | - 运行 `.js` 脚本文件 118 | - `node app` 或者 `node app.js` 119 | 120 | - 实践代码 121 | 122 | ```js 123 | console.log('hello world'); 124 | 125 | setTimeout(function () { 126 | console.log("3 seconds have passed 2"); 127 | }, 3000); 128 | 129 | // 箭头函数,es6的写法 130 | setTimeout(() => { 131 | console.log("3 seconds have passed 1"); 132 | }, 3000); 133 | 134 | // 每间隔2秒不断执行 135 | setInterval(function () { 136 | console.log("2 seconds have passed"); 137 | }, 2000); 138 | 139 | 140 | var time = 0 141 | var timer = setInterval(function () { 142 | time += 2; 143 | console.log(time + " seconds have passed"); 144 | if (time > 6) { 145 | clearInterval(timer); 146 | console.log("clearInterval") 147 | } 148 | }, 2000) 149 | 150 | // 输出当前目录 和 带绝对路径的文件名 151 | console.log(__dirname) 152 | console.log(__filename) 153 | 154 | console.log('end') 155 | console.dir(global) 156 | ``` 157 | 158 | ## 3.回调函数 159 | 160 | ```js 161 | function sayHi() { 162 | console.log('Hi') 163 | } 164 | 165 | sayHi() // 调用函数 166 | 167 | // 将匿名函数赋给变量 168 | var sayBye = function (name) { 169 | console.log(name + ' Bye') 170 | } 171 | 172 | sayBye() 173 | 174 | // 第一个参数是函数 175 | function callFunction(fun, name) { 176 | fun(name) 177 | } 178 | 179 | callFunction(sayBye, 'able') 180 | // 或者 181 | callFunction(function (name) { 182 | console.log(name + ' Bye') 183 | }, 'able') 184 | ``` 185 | 186 | ## 4.模块 187 | 188 | - module 对象 189 | - 每个文件都被视为独立的模块 190 | - 每个模块中,module 指向表示当前模块的对象的引用 191 | - module 实际上不是全局的,而是每个模块本地的 192 | - module.exports 导出模块内的对象,方便其他对象引用 193 | - require() 引入模块 194 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 195 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 196 | - module 提供了一个 filename 属性(通常等同于 __filename) 197 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 198 | 199 | ```js 200 | // counter.js 201 | var counter = function (arr) { 202 | return "There are " + arr.length + " elements in array" 203 | } 204 | 205 | var adder = function (a, b) { 206 | return `the sum of the 2 numbers is ${a+b}` 207 | } 208 | 209 | var pi = 3.14 210 | 211 | // 只有一个时可以这样导入 212 | // module.exports = counter 213 | 214 | /* 215 | module.exports.counter = counter 216 | module.exports.adder = adder 217 | module.exports.pi = pi 218 | */ 219 | 220 | module.exports = { 221 | counter: counter, 222 | adder: adder, 223 | pi: pi, 224 | } 225 | /* 对象可以简写 226 | module.exports = { 227 | counter, 228 | adder, 229 | pi, 230 | } 231 | */ 232 | 233 | //p4.js 234 | var stuff = require('./count') 235 | 236 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 237 | console.log(stuff.adder(3, 2)) 238 | console.log(stuff.pi) 239 | ``` 240 | 241 | ## 5.事件 events 242 | 243 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 244 | - 所有能触发事件的对象都是 EventEmitter 类的实例 245 | - 事件名称通常是驼峰式的字符串 246 | 247 | - 实践代码 248 | 249 | ```js 250 | var events = require('events') 251 | var util = require('util') 252 | 253 | // 事件 对象 254 | var myEmitter = new events.EventEmitter() 255 | 256 | // 绑定 事件名称 和 回调函数 257 | myEmitter.on('someEvent', function (message) { 258 | console.log(message) 259 | }) 260 | 261 | // 触发实践,使用事件名称 262 | myEmitter.emit('someEvent', 'The event was emitted') 263 | 264 | // 创建对象 265 | var Person = function (name) { 266 | this.name = name 267 | } 268 | 269 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 270 | util.inherits(Person, events.EventEmitter) 271 | // 新建对象 272 | var xiaoming = new Person('xiaoming') 273 | var lili = new Person('lili') 274 | 275 | var person = [xiaoming, lili] 276 | 277 | // 循环person数组,绑定事件 278 | person.forEach(function (person) { 279 | person.on('speak', function (message) { 280 | console.log(person.name + ' said: ' + message) 281 | }) 282 | }) 283 | 284 | // 触发事件 285 | xiaoming.emit('speak', 'hi') 286 | lili.emit('speak', 'I want a curry') 287 | ``` 288 | 289 | ## 6.读写文件(同步和异步) 290 | 291 | ```js 292 | var fs = require('fs') 293 | 294 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 295 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 296 | fs.writeFileSync('writeMe.txt', readMe) 297 | 298 | console.log(readMe) 299 | console.log('finished sync') 300 | 301 | // 异步读写文件 302 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 303 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 304 | 305 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 306 | fs.writeFile('writeMe.txt', data, function () { 307 | console.log('writeMe has finished') 308 | }) 309 | }) 310 | 311 | console.log('end') 312 | ``` 313 | 314 | ## 7.创建和删除目录 315 | 316 | - [fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 317 | 318 | ```js 319 | var fs = require('fs') 320 | 321 | // 异步删除文件 322 | fs.unlink('writeMe.txt', function () { 323 | console.log('delete writeMe.txt file') 324 | }) 325 | 326 | // 同步创建和删除目录 327 | fs.mkdirSync('stuff') 328 | fs.rmdirSync('stuff') 329 | 330 | // 异步 331 | fs.mkdir('stuff', function () { 332 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 333 | fs.writeFile('./stuff/writeMe.txt', data, function () { 334 | console.log('copy successfully') 335 | }) 336 | }) 337 | }) 338 | ``` 339 | 340 | ## 8.流和管道 341 | 342 | - 流(stream) 343 | - 处理流式数据的抽象接口 344 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 345 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 346 | - 流处理数据通过缓存可以提高性能 347 | 348 | - 管道 349 | - 使用管道,代码量更少 350 | - myReadStream.pipe(myWriteStream) 351 | 352 | ```js 353 | var fs = require('fs') 354 | 355 | var myReadStream = fs.createReadStream(__dirname + '/readMe.txt') 356 | myReadStream.setEncoding('utf8') 357 | var myWriteStream = fs.createWriteStream(__dirname + '/writeMe.txt') 358 | var data = '' 359 | 360 | myReadStream.on('data', function (chunk) { 361 | console.log('new chunk received') 362 | // console.log(chunk) 363 | myWriteStream.write(chunk) 364 | }) 365 | 366 | myReadStream.on('end', function () { 367 | console.log(data) 368 | }) 369 | 370 | var writeData = 'hello world' 371 | myWriteStream.write(writeData) 372 | myWriteStream.end() 373 | myWriteStream.on('finish', function () { 374 | console.log('finished') 375 | }) 376 | 377 | // 使用管道,代码量更少 378 | myReadStream.pipe(myWriteStream) 379 | ``` 380 | 381 | ## 9.web 服务器 part1 介绍 382 | 383 | ```js 384 | var http = require('http') 385 | 386 | var server = http.createServer(function (req, res) { 387 | console.log('request received') 388 | res.writeHead(200, { 'Content-Type': 'text/plain' }) 389 | // res.write('Hello from out application') 390 | // res.end() 391 | // 或 392 | res.end('Hello from out application') 393 | }) 394 | 395 | server.listen(3000, '127.0.0.1') 396 | console.log('server started on http://127.0.0.1:3000') 397 | ``` 398 | 399 | ## 10.web 服务器 part2 响应JSON 400 | 401 | - 响应JSON 402 | 403 | ```js 404 | var myObj = { 405 | name: 'able', 406 | job: 'programmer', 407 | age: 27 408 | } 409 | res.end(JSON.stringify(myObj)) 410 | ``` 411 | 412 | - [JSON 对象](https://wangdoc.com/javascript/stdlib/json.html) 413 | - 字符串必须使用双引号表示,不能使用单引号 414 | - 对象的键名必须放在双引号里面 415 | - 数组或对象最后一个成员的后面,不能加逗号 416 | - JSON对象是 JavaScript 的原生对象,用来处理 JSON 格式数据 417 | - JSON.stringify方法用于将一个值转为 JSON 字符串 418 | - JSON.parse方法用于将 JSON 字符串转换成对应的值 419 | 420 | ## 11.web 服务器 part3 响应HTML页面 421 | 422 | ```js 423 | var http = require('http') 424 | var fs = require('fs') 425 | 426 | var onRequest = function (req, res) { 427 | console.log('request received') 428 | res.writeHead(200, { 'Content-Type': 'text/html' }) 429 | // res.writeHead(200, { 'Content-Type': 'text/plain' }) 430 | var myReadStream = fs.createReadStream(__dirname + '/index.html', 'utf8') 431 | myReadStream.pipe(res) 432 | } 433 | 434 | var server = http.createServer(onRequest) 435 | server.listen(3000) 436 | console.log('server started on http://127.0.0.1:3000') 437 | ``` 438 | 439 | ## 12.web 服务器 part4 用模块化思想组织代码 440 | 441 | - 代码封装成模块,方便统一管理和调用 442 | 443 | ```js 444 | // server.js 445 | var http = require('http') 446 | var fs = require('fs') 447 | 448 | function startServer() { 449 | var onRequest = function (req, res) { 450 | console.log('request received') 451 | res.writeHead(200, { 'Content-Type': 'text/html' }) 452 | 453 | var myReadStream = fs.createReadStream(__dirname + '/index.html', 'utf8') 454 | myReadStream.pipe(res) 455 | } 456 | var server = http.createServer(onRequest) 457 | server.listen(3000) 458 | console.log('server started on http://127.0.0.1:3000') 459 | } 460 | 461 | module.exports.startServer = startServer 462 | 463 | // 调用 464 | var server = require('./server') 465 | 466 | server.startServer() 467 | ``` 468 | 469 | ## 13.web 服务器 part5 路由 470 | 471 | - `console.dir(xx)` 查看对象的所有属性和方法 472 | - `req.url` 请求中包含url等属性 473 | 474 | ```js 475 | unction startServer() { 476 | var onRequest = function (req, res) { 477 | console.log('request received ' + req.url) 478 | 479 | if (req.url === '/' || req.url === '/home') { 480 | res.writeHead(200, { 'Content-Type': 'text/html' }) 481 | fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(res) 482 | } else if (req.url === '/review') { 483 | res.writeHead(200, { 'Content-Type': 'text/html' }) 484 | fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(res) 485 | } else if (req.url === '/api/v1/records') { 486 | res.writeHead(200, { 'Content-Type': 'application/json' }) 487 | var jsonObj = { 488 | name: 'able' 489 | } 490 | res.end(JSON.stringify(jsonObj)) 491 | } else { 492 | res.writeHead(200, { 'Content-Type': 'text/html' }) 493 | fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(res) 494 | } 495 | } 496 | var server = http.createServer(onRequest) 497 | server.listen(3000) 498 | console.log('server started on http://127.0.0.1:3000') 499 | } 500 | ``` 501 | 502 | ## 14.web 服务器 part6 重构路由代码 503 | 504 | - 将路由、处理函数和主程序分离,单独存放 505 | - 分工明确,各司其职,方便管理 506 | 507 | ## 15.web 服务器 part7 使用 GET或 POST 请求 发送数据 508 | 509 | - [querystring - 查询字符串](http://nodejs.cn/api/querystring.html) 510 | - `var querystring = require('querystring')` 511 | - `querystring.parse(data)` 把一个 URL 查询字符串 str 解析成一个键值对的集合 512 | 513 | ```js 514 | // 接收请求数据,然后处理,查看request 类型 515 | var data = "" 516 | req.on("error", function (err) { 517 | console.error(err) 518 | }).on("data", function (chunk) { 519 | data += chunk 520 | }).on("end", function () { 521 | if (req.mothod === "POST") { 522 | if (data.length > 1e6) { 523 | req.connection.destroy() // 如果数据很大,就断开 524 | } 525 | route(handle, pathname, res, querystring.parse(data)) 526 | } else { 527 | var params = url.parse(req.url, true).query 528 | route(handle, pathname, res, params) 529 | } 530 | }) 531 | // 或者 532 | // var data = [] 533 | // data.push(chunk) 534 | // data = Buffer.concat(data).toString() 535 | ``` 536 | 537 | ## 16.包管理器 npm 538 | 539 | - [npm 官网](https://www.npmjs.com) 540 | - [搜索查看 express](https://www.npmjs.com/package/express) 541 | 542 | - `npm install -g xxx` 全局安装可执行文件,当作命令行工具 543 | - 使用国内源,解决慢的问题 544 | 545 | ```sh 546 | # Or alias it in .bashrc or .zshrc 547 | echo '\n#alias for npm\nalias npm="npm --registry=https://registry.npm.taobao.org \ 548 | --cache=$HOME/.npm/.cache/npm \ 549 | --disturl=https://npm.taobao.org/dist \ 550 | --userconfig=$HOME/.npmrc"' >> ~/.zshrc && source ~/.zshrc 551 | ``` 552 | 553 | - yarn 也是包管理器,更快下载速度 554 | 555 | ## 17.package.json 文件 556 | 557 | - 记录项目中使用的包名,发布时不用包内容了,只要名称就行 558 | - `npm init` 提问式初始化项目信息,生成`package.json`文件,-y 全部默认 559 | - `npm install --save xxx`安装的同时,将信息写入package.json 560 | - `npm install --save-dev xxx`安装的同时,将信息写入package.json中的dev开发依赖 561 | - `npm view moduleNames` 查看node模块的package.json文件夹 562 | - `npm run start` 启动包,执行 package.json scripts 中的 start 命令,还有 stop restart test 563 | - `npm install` 安装 package.json 中记录的包 564 | 565 | ## 18.nodemon监控文件并重启服务 566 | 567 | - nodemon 用来监视应用中的任何文件更改并自动重启服务 568 | - 非常适合用在开发环境中,方便啊,不用手动操作了 569 | - 全局安装 `npm install -g nodemon` 570 | - 本地安装 `npm install --save-dev nodemon` 571 | - 启动应用 `nodemon [your node app]` 572 | - 获取修改 package.json 中的启动脚本,添加`nodemon app.js`, 用 npm start 直接启动,方便 573 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var server = require('./server') 2 | var router = require('./router') 3 | var handler = require('./handler') 4 | 5 | var handle = {} 6 | // key是路径,值是处理函数 7 | handle['/'] = handler.home 8 | handle['/home'] = handler.home 9 | handle['/review'] = handler.review 10 | handle['/api/v1/records'] = handler.api_records 11 | 12 | server.startServer(router.route, handle) -------------------------------------------------------------------------------- /count.js: -------------------------------------------------------------------------------- 1 | var counter = function (arr) { 2 | return "There are " + arr.length + " elements in array" 3 | } 4 | 5 | var adder = function (a, b) { 6 | return `the sum of the 2 numbers is ${a+b}` 7 | } 8 | 9 | var pi = 3.14 10 | 11 | // 只有一个时可以这样导入 12 | // module.exports = counter 13 | 14 | /* 15 | module.exports.counter = counter 16 | module.exports.adder = adder 17 | module.exports.pi = pi 18 | */ 19 | 20 | module.exports = { 21 | counter: counter, 22 | adder: adder, 23 | pi: pi, 24 | } 25 | /* 对象可以简写 26 | module.exports = { 27 | counter, 28 | adder, 29 | pi, 30 | } 31 | */ 32 | 33 | 34 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | function home(res) { 4 | console.log('home') 5 | res.writeHead(200, { 'Content-Type': 'text/html' }) 6 | fs.createReadStream(__dirname + '/index.html', 'utf8').pipe(res) 7 | } 8 | 9 | function review(res) { 10 | console.log('review') 11 | res.writeHead(200, { 'Content-Type': 'text/html' }) 12 | fs.createReadStream(__dirname + '/review.html', 'utf8').pipe(res) 13 | } 14 | 15 | function api_records(res, params) { 16 | console.log('api_records') 17 | res.writeHead(200, { 'Content-Type': 'application/json' }) 18 | res.end(JSON.stringify(params)) 19 | } 20 | 21 | module.exports = { 22 | home: home, 23 | review: review, 24 | api_records: api_records 25 | } -------------------------------------------------------------------------------- /hello-world-web.js: -------------------------------------------------------------------------------- 1 | const http = require('http') 2 | 3 | const hostname = '127.0.0.1' 4 | const port = 3000 5 | 6 | const server = http.createServer((req, res) => { 7 | res.statusCode = 200 8 | res.setHeader('Content-Type', 'text/plain') 9 | res.end('Hello World!') 10 | }) 11 | 12 | server.listen(port, hostname, () => { 13 | console.log(`服务器运行在 http://${hostname}:${port}/`) 14 | }) -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | hello world 11 |
12 | name1: 13 | age: 14 | 15 |
16 | 17 | -------------------------------------------------------------------------------- /p11.js: -------------------------------------------------------------------------------- 1 | var http = require('http') 2 | var fs = require('fs') 3 | 4 | var onRequest = function (req, res) { 5 | console.log('request received') 6 | res.writeHead(200, { 'Content-Type': 'text/html' }) 7 | // res.writeHead(200, { 'Content-Type': 'text/plain' }) 8 | var myReadStream = fs.createReadStream(__dirname + '/index.html', 'utf8') 9 | myReadStream.pipe(res) 10 | } 11 | 12 | var server = http.createServer(onReque st) 13 | server.listen(3000) 14 | console.log('server started on http://127.0.0.1:3000') 15 | 16 | -------------------------------------------------------------------------------- /p2.js: -------------------------------------------------------------------------------- 1 | console.log('hello world'); 2 | 3 | setTimeout(function () { 4 | console.log("3 seconds have passed 2"); 5 | }, 3000); 6 | 7 | // 箭头函数,es6的写法 8 | setTimeout(() => { 9 | console.log("3 seconds have passed 1"); 10 | }, 3000); 11 | 12 | // 每间隔2秒不断执行 13 | setInterval(function () { 14 | console.log("2 seconds have passed"); 15 | }, 2000); 16 | 17 | var time = 0 18 | var timer = setInterval(function () { 19 | time += 2; 20 | console.log(time + " seconds have passed"); 21 | if (time > 6) { 22 | clearInterval(timer); 23 | console.log("clearInterval") 24 | } 25 | }, 2000) 26 | 27 | // 输出当前目录 和 带绝对路径的文件名 28 | console.log(__dirname) 29 | console.log(__filename) 30 | 31 | console.log('end') 32 | console.dir(global) 33 | -------------------------------------------------------------------------------- /p3.js: -------------------------------------------------------------------------------- 1 | function sayHi() { 2 | console.log('Hi') 3 | } 4 | 5 | sayHi() // 调用函数 6 | 7 | // 将匿名函数赋给变量 8 | var sayBye = function (name) { 9 | console.log(name + ' Bye') 10 | } 11 | 12 | sayBye() 13 | 14 | // 第一个参数是函数 15 | function callFunction(fun, name) { 16 | fun(name) 17 | } 18 | 19 | callFunction(sayBye, 'able') 20 | // 或者 21 | callFunction(function (name) { 22 | console.log(name + ' Bye') 23 | }, 'able') -------------------------------------------------------------------------------- /p4.js: -------------------------------------------------------------------------------- 1 | var stuff = require('./count') 2 | 3 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 4 | console.log(stuff.adder(3, 2)) 5 | console.log(stuff.pi) 6 | -------------------------------------------------------------------------------- /p5.js: -------------------------------------------------------------------------------- 1 | var events = require('events') 2 | var util = require('util') 3 | 4 | // 事件 对象 5 | var myEmitter = new events.EventEmitter() 6 | 7 | // 绑定 事件名称 和 回调函数 8 | myEmitter.on('someEvent', function (message) { 9 | console.log(message) 10 | }) 11 | 12 | // 触发实践,使用事件名称 13 | myEmitter.emit('someEvent', 'The event was emitted') 14 | 15 | var Person = function (name) { 16 | this.name = name 17 | } 18 | 19 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 20 | util.inherits(Person, events.EventEmitter) 21 | // 新建对象 22 | var xiaoming = new Person('xiaoming') 23 | var lili = new Person('lili') 24 | 25 | var person = [xiaoming, lili] 26 | 27 | // 循环person数组,绑定事件 28 | person.forEach(function (person) { 29 | person.on('speak', function (message) { 30 | console.log(person.name + ' said: ' + message) 31 | }) 32 | }) 33 | 34 | // 触发事件 35 | xiaoming.emit('speak', 'hi') 36 | lili.emit('speak', 'I want a curry') -------------------------------------------------------------------------------- /p6.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 4 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 5 | fs.writeFileSync('writeMe.txt', readMe) 6 | 7 | console.log(readMe) 8 | console.log('finished sync') 9 | 10 | // 异步读写文件 11 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 12 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 13 | 14 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 15 | fs.writeFile('writeMe.txt', data, function () { 16 | console.log('writeMe has finished') 17 | }) 18 | }) 19 | 20 | console.log('end') 21 | -------------------------------------------------------------------------------- /p7.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | // 异步删除文件 4 | fs.unlink('writeMe.txt', function () { 5 | console.log('delete writeMe.txt file') 6 | }) 7 | 8 | // 同步创建和删除目录 9 | fs.mkdirSync('stuff') 10 | fs.rmdirSync('stuff') 11 | 12 | // 异步 13 | fs.mkdir('stuff', function () { 14 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 15 | fs.writeFile('./stuff/writeMe.txt', data, function () { 16 | console.log('copy successfully') 17 | }) 18 | }) 19 | }) 20 | -------------------------------------------------------------------------------- /p8.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs') 2 | 3 | var myReadStream = fs.createReadStream(__dirname + '/readMe.txt') 4 | myReadStream.setEncoding('utf8') 5 | var myWriteStream = fs.createWriteStream(__dirname + '/writeMe.txt') 6 | var data = '' 7 | 8 | myReadStream.on('data', function (chunk) { 9 | console.log('new chunk received') 10 | // console.log(chunk) 11 | myWriteStream.write(chunk) 12 | }) 13 | 14 | myReadStream.on('end', function () { 15 | console.log(data) 16 | }) 17 | 18 | var writeData = 'hello world' 19 | myWriteStream.write(writeData) 20 | myWriteStream.end() 21 | myWriteStream.on('finish', function () { 22 | console.log('finished') 23 | }) 24 | 25 | 26 | // 使用管道,代码量更少 27 | myReadStream.pipe(myWriteStream) -------------------------------------------------------------------------------- /p9.js: -------------------------------------------------------------------------------- 1 | var http = require('http') 2 | 3 | var server = http.createServer(function (req, res) { 4 | console.log('request received') 5 | res.writeHead(200, { 'Content-Type': 'application/json' }) 6 | var myObj = { 7 | name: 'able', 8 | job: 'programmer', 9 | age: 27 10 | } 11 | res.end(JSON.stringify(myObj)) 12 | }) 13 | 14 | server.listen(3000) 15 | console.log('server started on http://127.0.0.1:3000') 16 | 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-nodejs", 3 | "version": "1.0.0", 4 | "description": "轻松学 Node.js 基础篇 入门", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon app.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/able8/hello-nodejs.git" 13 | }, 14 | "author": "", 15 | "license": "ISC", 16 | "bugs": { 17 | "url": "https://github.com/able8/hello-nodejs/issues" 18 | }, 19 | "homepage": "https://github.com/able8/hello-nodejs#readme" 20 | } 21 | -------------------------------------------------------------------------------- /readMe.txt: -------------------------------------------------------------------------------- 1 | you read me! 2 | 3 | # hello-nodejs 4 | 5 | 轻松学 Node.js 基础篇 入门 6 | 7 | 视频地址 8 | 9 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 10 | - [b站](https://www.bilibili.com/video/av21010015) 11 | 12 | 常用链接 13 | 14 | - [Node.js 官网](https://nodejs.org/zh-cn/) 15 | - [Node.js 中文网](http://nodejs.cn) 16 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 17 | 18 | 看视频整理要点笔记: 19 | 20 | --- 21 | 22 | - [hello-nodejs](#hello-nodejs) 23 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 24 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 25 | 26 | --- 27 | 28 | ## 1.课程介绍与开发环境搭建 29 | 30 | - 主要包括 31 | - nodejs 基础知识 32 | - web 服务器 33 | - 异步 同步 阻塞 非阻塞 34 | 35 | - 课程基础 36 | - javascript 基础 37 | - html 基础 38 | - 命令行基础 39 | 40 | - Node.js 介绍 41 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 42 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 43 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 44 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 45 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 46 | - V8 引擎是开源的,由 C++ 语言编写,性能高 47 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 48 | 49 | - Node.js 安装 50 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 51 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 52 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 53 | - macOS 安装完提示如下 54 | 55 | ```sh 56 | This package has installed: 57 | • Node.js v8.11.4 to /usr/local/bin/node 58 | • npm v5.6.0 to /usr/local/bin/npm 59 | Make sure that /usr/local/bin is in your $PATH. 60 | ``` 61 | 62 | - Node.js 用途 63 | 64 | - javascript 运行环境 65 | - 操作文件(grunt gulp webpack) 66 | - 操作数据库 67 | - 写后端 api 68 | - 命令行工具 69 | - web 开发 70 | - 聊天室 71 | 72 | - JavaScript 语句后应该加分号么? 73 | - [知乎讨论](https://www.zhihu.com/question/20298345) 74 | - 代码风格而已,没有定论 75 | - 少分号更易读,不累 76 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 77 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 78 | 79 | ## 2.全局对象 80 | 81 | - 全局对象 82 | - 不用导入,直接使用的对象 83 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 84 | - Buffer 类,用于处理二进制数据 85 | - console,用于打印 stdout 和 stderr 86 | - global, 全局的命名空间对象 87 | - process,进程对象 88 | - setTimeout(callback, delay[, ...args]) 89 | - setInterval(callback, delay[, ...args]) 90 | - setImmediate(callback[, ...args]) 91 | - clearTimeout(timeoutObject) 92 | - clearInterval(intervalObject) 93 | - clearImmediate(immediateObject) 94 | 95 | - 以下变量虽然看起来像全局变量,但实际上不是 96 | - 全局变量在所有模块中均可使用 97 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 98 | - __dirname 99 | - __filename 100 | - exports 101 | - module 102 | - require() 103 | 104 | - 运行 `.js` 脚本文件 105 | - `node app` 或者 `node app.js` 106 | 107 | - 实践代码 108 | 109 | ```js 110 | console.log('hello world'); 111 | 112 | setTimeout(function () { 113 | console.log("3 seconds have passed 2"); 114 | }, 3000); 115 | 116 | // 箭头函数,es6的写法 117 | setTimeout(() => { 118 | console.log("3 seconds have passed 1"); 119 | }, 3000); 120 | 121 | // 每间隔2秒不断执行 122 | setInterval(function () { 123 | console.log("2 seconds have passed"); 124 | }, 2000); 125 | 126 | 127 | var time = 0 128 | var timer = setInterval(function () { 129 | time += 2; 130 | console.log(time + " seconds have passed"); 131 | if (time > 6) { 132 | clearInterval(timer); 133 | console.log("clearInterval") 134 | } 135 | }, 2000) 136 | 137 | // 输出当前目录 和 带绝对路径的文件名 138 | console.log(__dirname) 139 | console.log(__filename) 140 | 141 | console.log('end') 142 | console.dir(global) 143 | ``` 144 | 145 | ## 3.回调函数 146 | 147 | ```js 148 | function sayHi() { 149 | console.log('Hi') 150 | } 151 | 152 | sayHi() // 调用函数 153 | 154 | // 将匿名函数赋给变量 155 | var sayBye = function (name) { 156 | console.log(name + ' Bye') 157 | } 158 | 159 | sayBye() 160 | 161 | // 第一个参数是函数 162 | function callFunction(fun, name) { 163 | fun(name) 164 | } 165 | 166 | callFunction(sayBye, 'able') 167 | // 或者 168 | callFunction(function (name) { 169 | console.log(name + ' Bye') 170 | }, 'able') 171 | ``` 172 | 173 | ## 4.模块 174 | 175 | - module 对象 176 | - 每个文件都被视为独立的模块 177 | - 每个模块中,module 指向表示当前模块的对象的引用 178 | - module 实际上不是全局的,而是每个模块本地的 179 | - module.exports 导出模块内的对象,方便其他对象引用 180 | - require() 引入模块 181 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 182 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 183 | - module 提供了一个 filename 属性(通常等同于 __filename) 184 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 185 | 186 | ```js 187 | // counter.js 188 | var counter = function (arr) { 189 | return "There are " + arr.length + " elements in array" 190 | } 191 | 192 | var adder = function (a, b) { 193 | return `the sum of the 2 numbers is ${a+b}` 194 | } 195 | 196 | var pi = 3.14 197 | 198 | // 只有一个时可以这样导入 199 | // module.exports = counter 200 | 201 | /* 202 | module.exports.counter = counter 203 | module.exports.adder = adder 204 | module.exports.pi = pi 205 | */ 206 | 207 | module.exports = { 208 | counter: counter, 209 | adder: adder, 210 | pi: pi, 211 | } 212 | /* 对象可以简写 213 | module.exports = { 214 | counter, 215 | adder, 216 | pi, 217 | } 218 | */ 219 | 220 | //p4.js 221 | var stuff = require('./count') 222 | 223 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 224 | console.log(stuff.adder(3, 2)) 225 | console.log(stuff.pi) 226 | ``` 227 | 228 | ## 5.事件 events 229 | 230 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 231 | - 所有能触发事件的对象都是 EventEmitter 类的实例 232 | - 事件名称通常是驼峰式的字符串 233 | 234 | - 实践代码 235 | 236 | ```js 237 | var events = require('events') 238 | var util = require('util') 239 | 240 | // 事件 对象 241 | var myEmitter = new events.EventEmitter() 242 | 243 | // 绑定 事件名称 和 回调函数 244 | myEmitter.on('someEvent', function (message) { 245 | console.log(message) 246 | }) 247 | 248 | // 触发实践,使用事件名称 249 | myEmitter.emit('someEvent', 'The event was emitted') 250 | 251 | // 创建对象 252 | var Person = function (name) { 253 | this.name = name 254 | } 255 | 256 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 257 | util.inherits(Person, events.EventEmitter) 258 | // 新建对象 259 | var xiaoming = new Person('xiaoming') 260 | var lili = new Person('lili') 261 | 262 | var person = [xiaoming, lili] 263 | 264 | // 循环person数组,绑定事件 265 | person.forEach(function (person) { 266 | person.on('speak', function (message) { 267 | console.log(person.name + ' said: ' + message) 268 | }) 269 | }) 270 | 271 | // 触发事件 272 | xiaoming.emit('speak', 'hi') 273 | lili.emit('speak', 'I want a curry') 274 | ``` 275 | 276 | ## 6.读写文件(同步和异步) 277 | 278 | ```js 279 | var fs = require('fs') 280 | 281 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 282 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 283 | fs.writeFileSync('writeMe.txt', readMe) 284 | 285 | console.log(readMe) 286 | console.log('finished sync') 287 | 288 | // 异步读写文件 289 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 290 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 291 | 292 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 293 | fs.writeFile('writeMe.txt', data, function () { 294 | console.log('writeMe has finished') 295 | }) 296 | }) 297 | 298 | console.log('end') 299 | ``` 300 | 301 | ## 7.创建和删除目录 302 | 303 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 304 | 305 | ```js 306 | var fs = require('fs') 307 | 308 | // 异步删除文件 309 | fs.unlink('writeMe.txt', function () { 310 | console.log('delete writeMe.txt file') 311 | }) 312 | 313 | // 同步创建和删除目录 314 | fs.mkdirSync('stuff') 315 | fs.rmdirSync('stuff') 316 | 317 | // 异步 318 | fs.mkdir('stuff', function () { 319 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 320 | fs.writeFile('./stuff/writeMe.txt', data, function () { 321 | console.log('copy successfully') 322 | }) 323 | }) 324 | }) 325 | ``` 326 | 327 | ## 8.流和管道 328 | 329 | - 流(stream) 330 | - 处理流式数据的抽象接口 331 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 332 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 333 | - 流处理数据通过缓存可以提高性能 334 | 335 | # hello-nodejs 336 | 337 | 轻松学 Node.js 基础篇 入门 338 | 339 | 视频地址 340 | 341 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 342 | - [b站](https://www.bilibili.com/video/av21010015) 343 | 344 | 常用链接 345 | 346 | - [Node.js 官网](https://nodejs.org/zh-cn/) 347 | - [Node.js 中文网](http://nodejs.cn) 348 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 349 | 350 | 看视频整理要点笔记: 351 | 352 | --- 353 | 354 | - [hello-nodejs](#hello-nodejs) 355 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 356 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 357 | 358 | --- 359 | 360 | ## 1.课程介绍与开发环境搭建 361 | 362 | - 主要包括 363 | - nodejs 基础知识 364 | - web 服务器 365 | - 异步 同步 阻塞 非阻塞 366 | 367 | - 课程基础 368 | - javascript 基础 369 | - html 基础 370 | - 命令行基础 371 | 372 | - Node.js 介绍 373 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 374 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 375 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 376 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 377 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 378 | - V8 引擎是开源的,由 C++ 语言编写,性能高 379 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 380 | 381 | - Node.js 安装 382 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 383 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 384 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 385 | - macOS 安装完提示如下 386 | 387 | ```sh 388 | This package has installed: 389 | • Node.js v8.11.4 to /usr/local/bin/node 390 | • npm v5.6.0 to /usr/local/bin/npm 391 | Make sure that /usr/local/bin is in your $PATH. 392 | ``` 393 | 394 | - Node.js 用途 395 | 396 | - javascript 运行环境 397 | - 操作文件(grunt gulp webpack) 398 | - 操作数据库 399 | - 写后端 api 400 | - 命令行工具 401 | - web 开发 402 | - 聊天室 403 | 404 | - JavaScript 语句后应该加分号么? 405 | - [知乎讨论](https://www.zhihu.com/question/20298345) 406 | - 代码风格而已,没有定论 407 | - 少分号更易读,不累 408 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 409 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 410 | 411 | ## 2.全局对象 412 | 413 | - 全局对象 414 | - 不用导入,直接使用的对象 415 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 416 | - Buffer 类,用于处理二进制数据 417 | - console,用于打印 stdout 和 stderr 418 | - global, 全局的命名空间对象 419 | - process,进程对象 420 | - setTimeout(callback, delay[, ...args]) 421 | - setInterval(callback, delay[, ...args]) 422 | - setImmediate(callback[, ...args]) 423 | - clearTimeout(timeoutObject) 424 | - clearInterval(intervalObject) 425 | - clearImmediate(immediateObject) 426 | 427 | - 以下变量虽然看起来像全局变量,但实际上不是 428 | - 全局变量在所有模块中均可使用 429 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 430 | - __dirname 431 | - __filename 432 | - exports 433 | - module 434 | - require() 435 | 436 | - 运行 `.js` 脚本文件 437 | - `node app` 或者 `node app.js` 438 | 439 | - 实践代码 440 | 441 | ```js 442 | console.log('hello world'); 443 | 444 | setTimeout(function () { 445 | console.log("3 seconds have passed 2"); 446 | }, 3000); 447 | 448 | // 箭头函数,es6的写法 449 | setTimeout(() => { 450 | console.log("3 seconds have passed 1"); 451 | }, 3000); 452 | 453 | // 每间隔2秒不断执行 454 | setInterval(function () { 455 | console.log("2 seconds have passed"); 456 | }, 2000); 457 | 458 | 459 | var time = 0 460 | var timer = setInterval(function () { 461 | time += 2; 462 | console.log(time + " seconds have passed"); 463 | if (time > 6) { 464 | clearInterval(timer); 465 | console.log("clearInterval") 466 | } 467 | }, 2000) 468 | 469 | // 输出当前目录 和 带绝对路径的文件名 470 | console.log(__dirname) 471 | console.log(__filename) 472 | 473 | console.log('end') 474 | console.dir(global) 475 | ``` 476 | 477 | ## 3.回调函数 478 | 479 | ```js 480 | function sayHi() { 481 | console.log('Hi') 482 | } 483 | 484 | sayHi() // 调用函数 485 | 486 | // 将匿名函数赋给变量 487 | var sayBye = function (name) { 488 | console.log(name + ' Bye') 489 | } 490 | 491 | sayBye() 492 | 493 | // 第一个参数是函数 494 | function callFunction(fun, name) { 495 | fun(name) 496 | } 497 | 498 | callFunction(sayBye, 'able') 499 | // 或者 500 | callFunction(function (name) { 501 | console.log(name + ' Bye') 502 | }, 'able') 503 | ``` 504 | 505 | ## 4.模块 506 | 507 | - module 对象 508 | - 每个文件都被视为独立的模块 509 | - 每个模块中,module 指向表示当前模块的对象的引用 510 | - module 实际上不是全局的,而是每个模块本地的 511 | - module.exports 导出模块内的对象,方便其他对象引用 512 | - require() 引入模块 513 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 514 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 515 | - module 提供了一个 filename 属性(通常等同于 __filename) 516 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 517 | 518 | ```js 519 | // counter.js 520 | var counter = function (arr) { 521 | return "There are " + arr.length + " elements in array" 522 | } 523 | 524 | var adder = function (a, b) { 525 | return `the sum of the 2 numbers is ${a+b}` 526 | } 527 | 528 | var pi = 3.14 529 | 530 | // 只有一个时可以这样导入 531 | // module.exports = counter 532 | 533 | /* 534 | module.exports.counter = counter 535 | module.exports.adder = adder 536 | module.exports.pi = pi 537 | */ 538 | 539 | module.exports = { 540 | counter: counter, 541 | adder: adder, 542 | pi: pi, 543 | } 544 | /* 对象可以简写 545 | module.exports = { 546 | counter, 547 | adder, 548 | pi, 549 | } 550 | */ 551 | 552 | //p4.js 553 | var stuff = require('./count') 554 | 555 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 556 | console.log(stuff.adder(3, 2)) 557 | console.log(stuff.pi) 558 | ``` 559 | 560 | ## 5.事件 events 561 | 562 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 563 | - 所有能触发事件的对象都是 EventEmitter 类的实例 564 | - 事件名称通常是驼峰式的字符串 565 | 566 | - 实践代码 567 | 568 | ```js 569 | var events = require('events') 570 | var util = require('util') 571 | 572 | // 事件 对象 573 | var myEmitter = new events.EventEmitter() 574 | 575 | // 绑定 事件名称 和 回调函数 576 | myEmitter.on('someEvent', function (message) { 577 | console.log(message) 578 | }) 579 | 580 | // 触发实践,使用事件名称 581 | myEmitter.emit('someEvent', 'The event was emitted') 582 | 583 | // 创建对象 584 | var Person = function (name) { 585 | this.name = name 586 | } 587 | 588 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 589 | util.inherits(Person, events.EventEmitter) 590 | // 新建对象 591 | var xiaoming = new Person('xiaoming') 592 | var lili = new Person('lili') 593 | 594 | var person = [xiaoming, lili] 595 | 596 | // 循环person数组,绑定事件 597 | person.forEach(function (person) { 598 | person.on('speak', function (message) { 599 | console.log(person.name + ' said: ' + message) 600 | }) 601 | }) 602 | 603 | // 触发事件 604 | xiaoming.emit('speak', 'hi') 605 | lili.emit('speak', 'I want a curry') 606 | ``` 607 | 608 | ## 6.读写文件(同步和异步) 609 | 610 | ```js 611 | var fs = require('fs') 612 | 613 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 614 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 615 | fs.writeFileSync('writeMe.txt', readMe) 616 | 617 | console.log(readMe) 618 | console.log('finished sync') 619 | 620 | // 异步读写文件 621 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 622 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 623 | 624 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 625 | fs.writeFile('writeMe.txt', data, function () { 626 | console.log('writeMe has finished') 627 | }) 628 | }) 629 | 630 | console.log('end') 631 | ``` 632 | 633 | ## 7.创建和删除目录 634 | 635 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 636 | 637 | ```js 638 | var fs = require('fs') 639 | 640 | // 异步删除文件 641 | fs.unlink('writeMe.txt', function () { 642 | console.log('delete writeMe.txt file') 643 | }) 644 | 645 | // 同步创建和删除目录 646 | fs.mkdirSync('stuff') 647 | fs.rmdirSync('stuff') 648 | 649 | // 异步 650 | fs.mkdir('stuff', function () { 651 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 652 | fs.writeFile('./stuff/writeMe.txt', data, function () { 653 | console.log('copy successfully') 654 | }) 655 | }) 656 | }) 657 | ``` 658 | 659 | ## 8.流和管道 660 | 661 | - 流(stream) 662 | - 处理流式数据的抽象接口 663 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 664 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 665 | - 流处理数据通过缓存可以提高性能 666 | # hello-nodejs 667 | 668 | 轻松学 Node.js 基础篇 入门 669 | 670 | 视频地址 671 | 672 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 673 | - [b站](https://www.bilibili.com/video/av21010015) 674 | 675 | 常用链接 676 | 677 | - [Node.js 官网](https://nodejs.org/zh-cn/) 678 | - [Node.js 中文网](http://nodejs.cn) 679 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 680 | 681 | 看视频整理要点笔记: 682 | 683 | --- 684 | 685 | - [hello-nodejs](#hello-nodejs) 686 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 687 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 688 | 689 | --- 690 | 691 | ## 1.课程介绍与开发环境搭建 692 | 693 | - 主要包括 694 | - nodejs 基础知识 695 | - web 服务器 696 | - 异步 同步 阻塞 非阻塞 697 | 698 | - 课程基础 699 | - javascript 基础 700 | - html 基础 701 | - 命令行基础 702 | 703 | - Node.js 介绍 704 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 705 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 706 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 707 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 708 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 709 | - V8 引擎是开源的,由 C++ 语言编写,性能高 710 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 711 | 712 | - Node.js 安装 713 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 714 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 715 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 716 | - macOS 安装完提示如下 717 | 718 | ```sh 719 | This package has installed: 720 | • Node.js v8.11.4 to /usr/local/bin/node 721 | • npm v5.6.0 to /usr/local/bin/npm 722 | Make sure that /usr/local/bin is in your $PATH. 723 | ``` 724 | 725 | - Node.js 用途 726 | 727 | - javascript 运行环境 728 | - 操作文件(grunt gulp webpack) 729 | - 操作数据库 730 | - 写后端 api 731 | - 命令行工具 732 | - web 开发 733 | - 聊天室 734 | 735 | - JavaScript 语句后应该加分号么? 736 | - [知乎讨论](https://www.zhihu.com/question/20298345) 737 | - 代码风格而已,没有定论 738 | - 少分号更易读,不累 739 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 740 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 741 | 742 | ## 2.全局对象 743 | 744 | - 全局对象 745 | - 不用导入,直接使用的对象 746 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 747 | - Buffer 类,用于处理二进制数据 748 | - console,用于打印 stdout 和 stderr 749 | - global, 全局的命名空间对象 750 | - process,进程对象 751 | - setTimeout(callback, delay[, ...args]) 752 | - setInterval(callback, delay[, ...args]) 753 | - setImmediate(callback[, ...args]) 754 | - clearTimeout(timeoutObject) 755 | - clearInterval(intervalObject) 756 | - clearImmediate(immediateObject) 757 | 758 | - 以下变量虽然看起来像全局变量,但实际上不是 759 | - 全局变量在所有模块中均可使用 760 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 761 | - __dirname 762 | - __filename 763 | - exports 764 | - module 765 | - require() 766 | 767 | - 运行 `.js` 脚本文件 768 | - `node app` 或者 `node app.js` 769 | 770 | - 实践代码 771 | 772 | ```js 773 | console.log('hello world'); 774 | 775 | setTimeout(function () { 776 | console.log("3 seconds have passed 2"); 777 | }, 3000); 778 | 779 | // 箭头函数,es6的写法 780 | setTimeout(() => { 781 | console.log("3 seconds have passed 1"); 782 | }, 3000); 783 | 784 | // 每间隔2秒不断执行 785 | setInterval(function () { 786 | console.log("2 seconds have passed"); 787 | }, 2000); 788 | 789 | 790 | var time = 0 791 | var timer = setInterval(function () { 792 | time += 2; 793 | console.log(time + " seconds have passed"); 794 | if (time > 6) { 795 | clearInterval(timer); 796 | console.log("clearInterval") 797 | } 798 | }, 2000) 799 | 800 | // 输出当前目录 和 带绝对路径的文件名 801 | console.log(__dirname) 802 | console.log(__filename) 803 | 804 | console.log('end') 805 | console.dir(global) 806 | ``` 807 | 808 | ## 3.回调函数 809 | 810 | ```js 811 | function sayHi() { 812 | console.log('Hi') 813 | } 814 | 815 | sayHi() // 调用函数 816 | 817 | // 将匿名函数赋给变量 818 | var sayBye = function (name) { 819 | console.log(name + ' Bye') 820 | } 821 | 822 | sayBye() 823 | 824 | // 第一个参数是函数 825 | function callFunction(fun, name) { 826 | fun(name) 827 | } 828 | 829 | callFunction(sayBye, 'able') 830 | // 或者 831 | callFunction(function (name) { 832 | console.log(name + ' Bye') 833 | }, 'able') 834 | ``` 835 | 836 | ## 4.模块 837 | 838 | - module 对象 839 | - 每个文件都被视为独立的模块 840 | - 每个模块中,module 指向表示当前模块的对象的引用 841 | - module 实际上不是全局的,而是每个模块本地的 842 | - module.exports 导出模块内的对象,方便其他对象引用 843 | - require() 引入模块 844 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 845 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 846 | - module 提供了一个 filename 属性(通常等同于 __filename) 847 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 848 | 849 | ```js 850 | // counter.js 851 | var counter = function (arr) { 852 | return "There are " + arr.length + " elements in array" 853 | } 854 | 855 | var adder = function (a, b) { 856 | return `the sum of the 2 numbers is ${a+b}` 857 | } 858 | 859 | var pi = 3.14 860 | 861 | // 只有一个时可以这样导入 862 | // module.exports = counter 863 | 864 | /* 865 | module.exports.counter = counter 866 | module.exports.adder = adder 867 | module.exports.pi = pi 868 | */ 869 | 870 | module.exports = { 871 | counter: counter, 872 | adder: adder, 873 | pi: pi, 874 | } 875 | /* 对象可以简写 876 | module.exports = { 877 | counter, 878 | adder, 879 | pi, 880 | } 881 | */ 882 | 883 | //p4.js 884 | var stuff = require('./count') 885 | 886 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 887 | console.log(stuff.adder(3, 2)) 888 | console.log(stuff.pi) 889 | ``` 890 | 891 | ## 5.事件 events 892 | 893 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 894 | - 所有能触发事件的对象都是 EventEmitter 类的实例 895 | - 事件名称通常是驼峰式的字符串 896 | 897 | - 实践代码 898 | 899 | ```js 900 | var events = require('events') 901 | var util = require('util') 902 | 903 | // 事件 对象 904 | var myEmitter = new events.EventEmitter() 905 | 906 | // 绑定 事件名称 和 回调函数 907 | myEmitter.on('someEvent', function (message) { 908 | console.log(message) 909 | }) 910 | 911 | // 触发实践,使用事件名称 912 | myEmitter.emit('someEvent', 'The event was emitted') 913 | 914 | // 创建对象 915 | var Person = function (name) { 916 | this.name = name 917 | } 918 | 919 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 920 | util.inherits(Person, events.EventEmitter) 921 | // 新建对象 922 | var xiaoming = new Person('xiaoming') 923 | var lili = new Person('lili') 924 | 925 | var person = [xiaoming, lili] 926 | 927 | // 循环person数组,绑定事件 928 | person.forEach(function (person) { 929 | person.on('speak', function (message) { 930 | console.log(person.name + ' said: ' + message) 931 | }) 932 | }) 933 | 934 | // 触发事件 935 | xiaoming.emit('speak', 'hi') 936 | lili.emit('speak', 'I want a curry') 937 | ``` 938 | 939 | ## 6.读写文件(同步和异步) 940 | 941 | ```js 942 | var fs = require('fs') 943 | 944 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 945 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 946 | fs.writeFileSync('writeMe.txt', readMe) 947 | 948 | console.log(readMe) 949 | console.log('finished sync') 950 | 951 | // 异步读写文件 952 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 953 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 954 | 955 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 956 | fs.writeFile('writeMe.txt', data, function () { 957 | console.log('writeMe has finished') 958 | }) 959 | }) 960 | 961 | console.log('end') 962 | ``` 963 | 964 | ## 7.创建和删除目录 965 | 966 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 967 | 968 | ```js 969 | var fs = require('fs') 970 | 971 | // 异步删除文件 972 | fs.unlink('writeMe.txt', function () { 973 | console.log('delete writeMe.txt file') 974 | }) 975 | 976 | // 同步创建和删除目录 977 | fs.mkdirSync('stuff') 978 | fs.rmdirSync('stuff') 979 | 980 | // 异步 981 | fs.mkdir('stuff', function () { 982 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 983 | fs.writeFile('./stuff/writeMe.txt', data, function () { 984 | console.log('copy successfully') 985 | }) 986 | }) 987 | }) 988 | ``` 989 | 990 | ## 8.流和管道 991 | 992 | - 流(stream) 993 | - 处理流式数据的抽象接口 994 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 995 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 996 | - 流处理数据通过缓存可以提高性能 997 | # hello-nodejs 998 | 999 | 轻松学 Node.js 基础篇 入门 1000 | 1001 | 视频地址 1002 | 1003 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 1004 | - [b站](https://www.bilibili.com/video/av21010015) 1005 | 1006 | 常用链接 1007 | 1008 | - [Node.js 官网](https://nodejs.org/zh-cn/) 1009 | - [Node.js 中文网](http://nodejs.cn) 1010 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 1011 | 1012 | 看视频整理要点笔记: 1013 | 1014 | --- 1015 | 1016 | - [hello-nodejs](#hello-nodejs) 1017 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 1018 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 1019 | 1020 | --- 1021 | 1022 | ## 1.课程介绍与开发环境搭建 1023 | 1024 | - 主要包括 1025 | - nodejs 基础知识 1026 | - web 服务器 1027 | - 异步 同步 阻塞 非阻塞 1028 | 1029 | - 课程基础 1030 | - javascript 基础 1031 | - html 基础 1032 | - 命令行基础 1033 | 1034 | - Node.js 介绍 1035 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 1036 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 1037 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 1038 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 1039 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 1040 | - V8 引擎是开源的,由 C++ 语言编写,性能高 1041 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 1042 | 1043 | - Node.js 安装 1044 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 1045 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 1046 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 1047 | - macOS 安装完提示如下 1048 | 1049 | ```sh 1050 | This package has installed: 1051 | • Node.js v8.11.4 to /usr/local/bin/node 1052 | • npm v5.6.0 to /usr/local/bin/npm 1053 | Make sure that /usr/local/bin is in your $PATH. 1054 | ``` 1055 | 1056 | - Node.js 用途 1057 | 1058 | - javascript 运行环境 1059 | - 操作文件(grunt gulp webpack) 1060 | - 操作数据库 1061 | - 写后端 api 1062 | - 命令行工具 1063 | - web 开发 1064 | - 聊天室 1065 | 1066 | - JavaScript 语句后应该加分号么? 1067 | - [知乎讨论](https://www.zhihu.com/question/20298345) 1068 | - 代码风格而已,没有定论 1069 | - 少分号更易读,不累 1070 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 1071 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 1072 | 1073 | ## 2.全局对象 1074 | 1075 | - 全局对象 1076 | - 不用导入,直接使用的对象 1077 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 1078 | - Buffer 类,用于处理二进制数据 1079 | - console,用于打印 stdout 和 stderr 1080 | - global, 全局的命名空间对象 1081 | - process,进程对象 1082 | - setTimeout(callback, delay[, ...args]) 1083 | - setInterval(callback, delay[, ...args]) 1084 | - setImmediate(callback[, ...args]) 1085 | - clearTimeout(timeoutObject) 1086 | - clearInterval(intervalObject) 1087 | - clearImmediate(immediateObject) 1088 | 1089 | - 以下变量虽然看起来像全局变量,但实际上不是 1090 | - 全局变量在所有模块中均可使用 1091 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 1092 | - __dirname 1093 | - __filename 1094 | - exports 1095 | - module 1096 | - require() 1097 | 1098 | - 运行 `.js` 脚本文件 1099 | - `node app` 或者 `node app.js` 1100 | 1101 | - 实践代码 1102 | 1103 | ```js 1104 | console.log('hello world'); 1105 | 1106 | setTimeout(function () { 1107 | console.log("3 seconds have passed 2"); 1108 | }, 3000); 1109 | 1110 | // 箭头函数,es6的写法 1111 | setTimeout(() => { 1112 | console.log("3 seconds have passed 1"); 1113 | }, 3000); 1114 | 1115 | // 每间隔2秒不断执行 1116 | setInterval(function () { 1117 | console.log("2 seconds have passed"); 1118 | }, 2000); 1119 | 1120 | 1121 | var time = 0 1122 | var timer = setInterval(function () { 1123 | time += 2; 1124 | console.log(time + " seconds have passed"); 1125 | if (time > 6) { 1126 | clearInterval(timer); 1127 | console.log("clearInterval") 1128 | } 1129 | }, 2000) 1130 | 1131 | // 输出当前目录 和 带绝对路径的文件名 1132 | console.log(__dirname) 1133 | console.log(__filename) 1134 | 1135 | console.log('end') 1136 | console.dir(global) 1137 | ``` 1138 | 1139 | ## 3.回调函数 1140 | 1141 | ```js 1142 | function sayHi() { 1143 | console.log('Hi') 1144 | } 1145 | 1146 | sayHi() // 调用函数 1147 | 1148 | // 将匿名函数赋给变量 1149 | var sayBye = function (name) { 1150 | console.log(name + ' Bye') 1151 | } 1152 | 1153 | sayBye() 1154 | 1155 | // 第一个参数是函数 1156 | function callFunction(fun, name) { 1157 | fun(name) 1158 | } 1159 | 1160 | callFunction(sayBye, 'able') 1161 | // 或者 1162 | callFunction(function (name) { 1163 | console.log(name + ' Bye') 1164 | }, 'able') 1165 | ``` 1166 | 1167 | ## 4.模块 1168 | 1169 | - module 对象 1170 | - 每个文件都被视为独立的模块 1171 | - 每个模块中,module 指向表示当前模块的对象的引用 1172 | - module 实际上不是全局的,而是每个模块本地的 1173 | - module.exports 导出模块内的对象,方便其他对象引用 1174 | - require() 引入模块 1175 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 1176 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 1177 | - module 提供了一个 filename 属性(通常等同于 __filename) 1178 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 1179 | 1180 | ```js 1181 | // counter.js 1182 | var counter = function (arr) { 1183 | return "There are " + arr.length + " elements in array" 1184 | } 1185 | 1186 | var adder = function (a, b) { 1187 | return `the sum of the 2 numbers is ${a+b}` 1188 | } 1189 | 1190 | var pi = 3.14 1191 | 1192 | // 只有一个时可以这样导入 1193 | // module.exports = counter 1194 | 1195 | /* 1196 | module.exports.counter = counter 1197 | module.exports.adder = adder 1198 | module.exports.pi = pi 1199 | */ 1200 | 1201 | module.exports = { 1202 | counter: counter, 1203 | adder: adder, 1204 | pi: pi, 1205 | } 1206 | /* 对象可以简写 1207 | module.exports = { 1208 | counter, 1209 | adder, 1210 | pi, 1211 | } 1212 | */ 1213 | 1214 | //p4.js 1215 | var stuff = require('./count') 1216 | 1217 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 1218 | console.log(stuff.adder(3, 2)) 1219 | console.log(stuff.pi) 1220 | ``` 1221 | 1222 | ## 5.事件 events 1223 | 1224 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 1225 | - 所有能触发事件的对象都是 EventEmitter 类的实例 1226 | - 事件名称通常是驼峰式的字符串 1227 | 1228 | - 实践代码 1229 | 1230 | ```js 1231 | var events = require('events') 1232 | var util = require('util') 1233 | 1234 | // 事件 对象 1235 | var myEmitter = new events.EventEmitter() 1236 | 1237 | // 绑定 事件名称 和 回调函数 1238 | myEmitter.on('someEvent', function (message) { 1239 | console.log(message) 1240 | }) 1241 | 1242 | // 触发实践,使用事件名称 1243 | myEmitter.emit('someEvent', 'The event was emitted') 1244 | 1245 | // 创建对象 1246 | var Person = function (name) { 1247 | this.name = name 1248 | } 1249 | 1250 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 1251 | util.inherits(Person, events.EventEmitter) 1252 | // 新建对象 1253 | var xiaoming = new Person('xiaoming') 1254 | var lili = new Person('lili') 1255 | 1256 | var person = [xiaoming, lili] 1257 | 1258 | // 循环person数组,绑定事件 1259 | person.forEach(function (person) { 1260 | person.on('speak', function (message) { 1261 | console.log(person.name + ' said: ' + message) 1262 | }) 1263 | }) 1264 | 1265 | // 触发事件 1266 | xiaoming.emit('speak', 'hi') 1267 | lili.emit('speak', 'I want a curry') 1268 | ``` 1269 | 1270 | ## 6.读写文件(同步和异步) 1271 | 1272 | ```js 1273 | var fs = require('fs') 1274 | 1275 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 1276 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 1277 | fs.writeFileSync('writeMe.txt', readMe) 1278 | 1279 | console.log(readMe) 1280 | console.log('finished sync') 1281 | 1282 | // 异步读写文件 1283 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 1284 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 1285 | 1286 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 1287 | fs.writeFile('writeMe.txt', data, function () { 1288 | console.log('writeMe has finished') 1289 | }) 1290 | }) 1291 | 1292 | console.log('end') 1293 | ``` 1294 | 1295 | ## 7.创建和删除目录 1296 | 1297 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 1298 | 1299 | ```js 1300 | var fs = require('fs') 1301 | 1302 | // 异步删除文件 1303 | fs.unlink('writeMe.txt', function () { 1304 | console.log('delete writeMe.txt file') 1305 | }) 1306 | 1307 | // 同步创建和删除目录 1308 | fs.mkdirSync('stuff') 1309 | fs.rmdirSync('stuff') 1310 | 1311 | // 异步 1312 | fs.mkdir('stuff', function () { 1313 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 1314 | fs.writeFile('./stuff/writeMe.txt', data, function () { 1315 | console.log('copy successfully') 1316 | }) 1317 | }) 1318 | }) 1319 | ``` 1320 | 1321 | ## 8.流和管道 1322 | 1323 | - 流(stream) 1324 | - 处理流式数据的抽象接口 1325 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 1326 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 1327 | - 流处理数据通过缓存可以提高性能 1328 | # hello-nodejs 1329 | 1330 | 轻松学 Node.js 基础篇 入门 1331 | 1332 | 视频地址 1333 | 1334 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 1335 | - [b站](https://www.bilibili.com/video/av21010015) 1336 | 1337 | 常用链接 1338 | 1339 | - [Node.js 官网](https://nodejs.org/zh-cn/) 1340 | - [Node.js 中文网](http://nodejs.cn) 1341 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 1342 | 1343 | 看视频整理要点笔记: 1344 | 1345 | --- 1346 | 1347 | - [hello-nodejs](#hello-nodejs) 1348 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 1349 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 1350 | 1351 | --- 1352 | 1353 | ## 1.课程介绍与开发环境搭建 1354 | 1355 | - 主要包括 1356 | - nodejs 基础知识 1357 | - web 服务器 1358 | - 异步 同步 阻塞 非阻塞 1359 | 1360 | - 课程基础 1361 | - javascript 基础 1362 | - html 基础 1363 | - 命令行基础 1364 | 1365 | - Node.js 介绍 1366 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 1367 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 1368 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 1369 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 1370 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 1371 | - V8 引擎是开源的,由 C++ 语言编写,性能高 1372 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 1373 | 1374 | - Node.js 安装 1375 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 1376 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 1377 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 1378 | - macOS 安装完提示如下 1379 | 1380 | ```sh 1381 | This package has installed: 1382 | • Node.js v8.11.4 to /usr/local/bin/node 1383 | • npm v5.6.0 to /usr/local/bin/npm 1384 | Make sure that /usr/local/bin is in your $PATH. 1385 | ``` 1386 | 1387 | - Node.js 用途 1388 | 1389 | - javascript 运行环境 1390 | - 操作文件(grunt gulp webpack) 1391 | - 操作数据库 1392 | - 写后端 api 1393 | - 命令行工具 1394 | - web 开发 1395 | - 聊天室 1396 | 1397 | - JavaScript 语句后应该加分号么? 1398 | - [知乎讨论](https://www.zhihu.com/question/20298345) 1399 | - 代码风格而已,没有定论 1400 | - 少分号更易读,不累 1401 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 1402 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 1403 | 1404 | ## 2.全局对象 1405 | 1406 | - 全局对象 1407 | - 不用导入,直接使用的对象 1408 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 1409 | - Buffer 类,用于处理二进制数据 1410 | - console,用于打印 stdout 和 stderr 1411 | - global, 全局的命名空间对象 1412 | - process,进程对象 1413 | - setTimeout(callback, delay[, ...args]) 1414 | - setInterval(callback, delay[, ...args]) 1415 | - setImmediate(callback[, ...args]) 1416 | - clearTimeout(timeoutObject) 1417 | - clearInterval(intervalObject) 1418 | - clearImmediate(immediateObject) 1419 | 1420 | - 以下变量虽然看起来像全局变量,但实际上不是 1421 | - 全局变量在所有模块中均可使用 1422 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 1423 | - __dirname 1424 | - __filename 1425 | - exports 1426 | - module 1427 | - require() 1428 | 1429 | - 运行 `.js` 脚本文件 1430 | - `node app` 或者 `node app.js` 1431 | 1432 | - 实践代码 1433 | 1434 | ```js 1435 | console.log('hello world'); 1436 | 1437 | setTimeout(function () { 1438 | console.log("3 seconds have passed 2"); 1439 | }, 3000); 1440 | 1441 | // 箭头函数,es6的写法 1442 | setTimeout(() => { 1443 | console.log("3 seconds have passed 1"); 1444 | }, 3000); 1445 | 1446 | // 每间隔2秒不断执行 1447 | setInterval(function () { 1448 | console.log("2 seconds have passed"); 1449 | }, 2000); 1450 | 1451 | 1452 | var time = 0 1453 | var timer = setInterval(function () { 1454 | time += 2; 1455 | console.log(time + " seconds have passed"); 1456 | if (time > 6) { 1457 | clearInterval(timer); 1458 | console.log("clearInterval") 1459 | } 1460 | }, 2000) 1461 | 1462 | // 输出当前目录 和 带绝对路径的文件名 1463 | console.log(__dirname) 1464 | console.log(__filename) 1465 | 1466 | console.log('end') 1467 | console.dir(global) 1468 | ``` 1469 | 1470 | ## 3.回调函数 1471 | 1472 | ```js 1473 | function sayHi() { 1474 | console.log('Hi') 1475 | } 1476 | 1477 | sayHi() // 调用函数 1478 | 1479 | // 将匿名函数赋给变量 1480 | var sayBye = function (name) { 1481 | console.log(name + ' Bye') 1482 | } 1483 | 1484 | sayBye() 1485 | 1486 | // 第一个参数是函数 1487 | function callFunction(fun, name) { 1488 | fun(name) 1489 | } 1490 | 1491 | callFunction(sayBye, 'able') 1492 | // 或者 1493 | callFunction(function (name) { 1494 | console.log(name + ' Bye') 1495 | }, 'able') 1496 | ``` 1497 | 1498 | ## 4.模块 1499 | 1500 | - module 对象 1501 | - 每个文件都被视为独立的模块 1502 | - 每个模块中,module 指向表示当前模块的对象的引用 1503 | - module 实际上不是全局的,而是每个模块本地的 1504 | - module.exports 导出模块内的对象,方便其他对象引用 1505 | - require() 引入模块 1506 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 1507 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 1508 | - module 提供了一个 filename 属性(通常等同于 __filename) 1509 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 1510 | 1511 | ```js 1512 | // counter.js 1513 | var counter = function (arr) { 1514 | return "There are " + arr.length + " elements in array" 1515 | } 1516 | 1517 | var adder = function (a, b) { 1518 | return `the sum of the 2 numbers is ${a+b}` 1519 | } 1520 | 1521 | var pi = 3.14 1522 | 1523 | // 只有一个时可以这样导入 1524 | // module.exports = counter 1525 | 1526 | /* 1527 | module.exports.counter = counter 1528 | module.exports.adder = adder 1529 | module.exports.pi = pi 1530 | */ 1531 | 1532 | module.exports = { 1533 | counter: counter, 1534 | adder: adder, 1535 | pi: pi, 1536 | } 1537 | /* 对象可以简写 1538 | module.exports = { 1539 | counter, 1540 | adder, 1541 | pi, 1542 | } 1543 | */ 1544 | 1545 | //p4.js 1546 | var stuff = require('./count') 1547 | 1548 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 1549 | console.log(stuff.adder(3, 2)) 1550 | console.log(stuff.pi) 1551 | ``` 1552 | 1553 | ## 5.事件 events 1554 | 1555 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 1556 | - 所有能触发事件的对象都是 EventEmitter 类的实例 1557 | - 事件名称通常是驼峰式的字符串 1558 | 1559 | - 实践代码 1560 | 1561 | ```js 1562 | var events = require('events') 1563 | var util = require('util') 1564 | 1565 | // 事件 对象 1566 | var myEmitter = new events.EventEmitter() 1567 | 1568 | // 绑定 事件名称 和 回调函数 1569 | myEmitter.on('someEvent', function (message) { 1570 | console.log(message) 1571 | }) 1572 | 1573 | // 触发实践,使用事件名称 1574 | myEmitter.emit('someEvent', 'The event was emitted') 1575 | 1576 | // 创建对象 1577 | var Person = function (name) { 1578 | this.name = name 1579 | } 1580 | 1581 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 1582 | util.inherits(Person, events.EventEmitter) 1583 | // 新建对象 1584 | var xiaoming = new Person('xiaoming') 1585 | var lili = new Person('lili') 1586 | 1587 | var person = [xiaoming, lili] 1588 | 1589 | // 循环person数组,绑定事件 1590 | person.forEach(function (person) { 1591 | person.on('speak', function (message) { 1592 | console.log(person.name + ' said: ' + message) 1593 | }) 1594 | }) 1595 | 1596 | // 触发事件 1597 | xiaoming.emit('speak', 'hi') 1598 | lili.emit('speak', 'I want a curry') 1599 | ``` 1600 | 1601 | ## 6.读写文件(同步和异步) 1602 | 1603 | ```js 1604 | var fs = require('fs') 1605 | 1606 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 1607 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 1608 | fs.writeFileSync('writeMe.txt', readMe) 1609 | 1610 | console.log(readMe) 1611 | console.log('finished sync') 1612 | 1613 | // 异步读写文件 1614 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 1615 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 1616 | 1617 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 1618 | fs.writeFile('writeMe.txt', data, function () { 1619 | console.log('writeMe has finished') 1620 | }) 1621 | }) 1622 | 1623 | console.log('end') 1624 | ``` 1625 | 1626 | ## 7.创建和删除目录 1627 | 1628 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 1629 | 1630 | ```js 1631 | var fs = require('fs') 1632 | 1633 | // 异步删除文件 1634 | fs.unlink('writeMe.txt', function () { 1635 | console.log('delete writeMe.txt file') 1636 | }) 1637 | 1638 | // 同步创建和删除目录 1639 | fs.mkdirSync('stuff') 1640 | fs.rmdirSync('stuff') 1641 | 1642 | // 异步 1643 | fs.mkdir('stuff', function () { 1644 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 1645 | fs.writeFile('./stuff/writeMe.txt', data, function () { 1646 | console.log('copy successfully') 1647 | }) 1648 | }) 1649 | }) 1650 | ``` 1651 | 1652 | ## 8.流和管道 1653 | 1654 | - 流(stream) 1655 | - 处理流式数据的抽象接口 1656 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 1657 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 1658 | - 流处理数据通过缓存可以提高性能 1659 | 1660 | -------------------------------------------------------------------------------- /review.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | review page 11 | 12 | -------------------------------------------------------------------------------- /router.js: -------------------------------------------------------------------------------- 1 | fs = require('fs') 2 | 3 | function route(handle, pathname, res, params) { 4 | console.log('Routing a request for ' + pathname) 5 | if (typeof handle[pathname] === 'function') { 6 | handle[pathname](res, params) 7 | } else { 8 | console.log('No handle for ' + pathname) 9 | res.writeHead(200, { 'Content-Type': 'text/html' }) 10 | fs.createReadStream(__dirname + '/404.html', 'utf8').pipe(res) 11 | } 12 | } 13 | 14 | module.exports.route = route -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var http = require('http') 2 | var url = require('url') 3 | var querystring = require('querystring') 4 | 5 | function startServer(route, handle) { 6 | var onRequest = function (req, res) { 7 | console.log('request received ' + req.url) 8 | var pathname = url.parse(req.url).pathname 9 | 10 | var data = "" 11 | req.on("error", function (err) { 12 | console.error(err) 13 | }).on("data", function (chunk) { 14 | data += chunk 15 | }).on("end", function () { 16 | if (req.mothod === "POST") { 17 | if (data.length > 1e6) { 18 | req.connection.destroy() // 如果数据很大,就断开 19 | } 20 | route(handle, pathname, res, querystring.parse(data)) 21 | } else { 22 | var params = url.parse(req.url, true).query 23 | route(handle, pathname, res, params) 24 | } 25 | }) 26 | // 或者 27 | // var data = [] 28 | // data.push(chunk) 29 | // data = Buffer.concat(data).toString() 30 | 31 | } 32 | var server = http.createServer(onRequest) 33 | server.listen(3000) 34 | console.log('server started on http://127.0.0.1:3000') 35 | } 36 | 37 | module.exports.startServer = startServer -------------------------------------------------------------------------------- /stuff/writeMe.txt: -------------------------------------------------------------------------------- 1 | you read me! 2 | -------------------------------------------------------------------------------- /writeMe.txt: -------------------------------------------------------------------------------- 1 | you read me! 2 | 3 | # hello-nodejs 4 | 5 | 轻松学 Node.js 基础篇 入门 6 | 7 | 视频地址 8 | 9 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 10 | - [b站](https://www.bilibili.com/video/av21010015) 11 | 12 | 常用链接 13 | 14 | - [Node.js 官网](https://nodejs.org/zh-cn/) 15 | - [Node.js 中文网](http://nodejs.cn) 16 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 17 | 18 | 看视频整理要点笔记: 19 | 20 | --- 21 | 22 | - [hello-nodejs](#hello-nodejs) 23 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 24 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 25 | 26 | --- 27 | 28 | ## 1.课程介绍与开发环境搭建 29 | 30 | - 主要包括 31 | - nodejs 基础知识 32 | - web 服务器 33 | - 异步 同步 阻塞 非阻塞 34 | 35 | - 课程基础 36 | - javascript 基础 37 | - html 基础 38 | - 命令行基础 39 | 40 | - Node.js 介绍 41 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 42 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 43 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 44 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 45 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 46 | - V8 引擎是开源的,由 C++ 语言编写,性能高 47 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 48 | 49 | - Node.js 安装 50 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 51 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 52 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 53 | - macOS 安装完提示如下 54 | 55 | ```sh 56 | This package has installed: 57 | • Node.js v8.11.4 to /usr/local/bin/node 58 | • npm v5.6.0 to /usr/local/bin/npm 59 | Make sure that /usr/local/bin is in your $PATH. 60 | ``` 61 | 62 | - Node.js 用途 63 | 64 | - javascript 运行环境 65 | - 操作文件(grunt gulp webpack) 66 | - 操作数据库 67 | - 写后端 api 68 | - 命令行工具 69 | - web 开发 70 | - 聊天室 71 | 72 | - JavaScript 语句后应该加分号么? 73 | - [知乎讨论](https://www.zhihu.com/question/20298345) 74 | - 代码风格而已,没有定论 75 | - 少分号更易读,不累 76 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 77 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 78 | 79 | ## 2.全局对象 80 | 81 | - 全局对象 82 | - 不用导入,直接使用的对象 83 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 84 | - Buffer 类,用于处理二进制数据 85 | - console,用于打印 stdout 和 stderr 86 | - global, 全局的命名空间对象 87 | - process,进程对象 88 | - setTimeout(callback, delay[, ...args]) 89 | - setInterval(callback, delay[, ...args]) 90 | - setImmediate(callback[, ...args]) 91 | - clearTimeout(timeoutObject) 92 | - clearInterval(intervalObject) 93 | - clearImmediate(immediateObject) 94 | 95 | - 以下变量虽然看起来像全局变量,但实际上不是 96 | - 全局变量在所有模块中均可使用 97 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 98 | - __dirname 99 | - __filename 100 | - exports 101 | - module 102 | - require() 103 | 104 | - 运行 `.js` 脚本文件 105 | - `node app` 或者 `node app.js` 106 | 107 | - 实践代码 108 | 109 | ```js 110 | console.log('hello world'); 111 | 112 | setTimeout(function () { 113 | console.log("3 seconds have passed 2"); 114 | }, 3000); 115 | 116 | // 箭头函数,es6的写法 117 | setTimeout(() => { 118 | console.log("3 seconds have passed 1"); 119 | }, 3000); 120 | 121 | // 每间隔2秒不断执行 122 | setInterval(function () { 123 | console.log("2 seconds have passed"); 124 | }, 2000); 125 | 126 | 127 | var time = 0 128 | var timer = setInterval(function () { 129 | time += 2; 130 | console.log(time + " seconds have passed"); 131 | if (time > 6) { 132 | clearInterval(timer); 133 | console.log("clearInterval") 134 | } 135 | }, 2000) 136 | 137 | // 输出当前目录 和 带绝对路径的文件名 138 | console.log(__dirname) 139 | console.log(__filename) 140 | 141 | console.log('end') 142 | console.dir(global) 143 | ``` 144 | 145 | ## 3.回调函数 146 | 147 | ```js 148 | function sayHi() { 149 | console.log('Hi') 150 | } 151 | 152 | sayHi() // 调用函数 153 | 154 | // 将匿名函数赋给变量 155 | var sayBye = function (name) { 156 | console.log(name + ' Bye') 157 | } 158 | 159 | sayBye() 160 | 161 | // 第一个参数是函数 162 | function callFunction(fun, name) { 163 | fun(name) 164 | } 165 | 166 | callFunction(sayBye, 'able') 167 | // 或者 168 | callFunction(function (name) { 169 | console.log(name + ' Bye') 170 | }, 'able') 171 | ``` 172 | 173 | ## 4.模块 174 | 175 | - module 对象 176 | - 每个文件都被视为独立的模块 177 | - 每个模块中,module 指向表示当前模块的对象的引用 178 | - module 实际上不是全局的,而是每个模块本地的 179 | - module.exports 导出模块内的对象,方便其他对象引用 180 | - require() 引入模块 181 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 182 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 183 | - module 提供了一个 filename 属性(通常等同于 __filename) 184 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 185 | 186 | ```js 187 | // counter.js 188 | var counter = function (arr) { 189 | return "There are " + arr.length + " elements in array" 190 | } 191 | 192 | var adder = function (a, b) { 193 | return `the sum of the 2 numbers is ${a+b}` 194 | } 195 | 196 | var pi = 3.14 197 | 198 | // 只有一个时可以这样导入 199 | // module.exports = counter 200 | 201 | /* 202 | module.exports.counter = counter 203 | module.exports.adder = adder 204 | module.exports.pi = pi 205 | */ 206 | 207 | module.exports = { 208 | counter: counter, 209 | adder: adder, 210 | pi: pi, 211 | } 212 | /* 对象可以简写 213 | module.exports = { 214 | counter, 215 | adder, 216 | pi, 217 | } 218 | */ 219 | 220 | //p4.js 221 | var stuff = require('./count') 222 | 223 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 224 | console.log(stuff.adder(3, 2)) 225 | console.log(stuff.pi) 226 | ``` 227 | 228 | ## 5.事件 events 229 | 230 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 231 | - 所有能触发事件的对象都是 EventEmitter 类的实例 232 | - 事件名称通常是驼峰式的字符串 233 | 234 | - 实践代码 235 | 236 | ```js 237 | var events = require('events') 238 | var util = require('util') 239 | 240 | // 事件 对象 241 | var myEmitter = new events.EventEmitter() 242 | 243 | // 绑定 事件名称 和 回调函数 244 | myEmitter.on('someEvent', function (message) { 245 | console.log(message) 246 | }) 247 | 248 | // 触发实践,使用事件名称 249 | myEmitter.emit('someEvent', 'The event was emitted') 250 | 251 | // 创建对象 252 | var Person = function (name) { 253 | this.name = name 254 | } 255 | 256 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 257 | util.inherits(Person, events.EventEmitter) 258 | // 新建对象 259 | var xiaoming = new Person('xiaoming') 260 | var lili = new Person('lili') 261 | 262 | var person = [xiaoming, lili] 263 | 264 | // 循环person数组,绑定事件 265 | person.forEach(function (person) { 266 | person.on('speak', function (message) { 267 | console.log(person.name + ' said: ' + message) 268 | }) 269 | }) 270 | 271 | // 触发事件 272 | xiaoming.emit('speak', 'hi') 273 | lili.emit('speak', 'I want a curry') 274 | ``` 275 | 276 | ## 6.读写文件(同步和异步) 277 | 278 | ```js 279 | var fs = require('fs') 280 | 281 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 282 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 283 | fs.writeFileSync('writeMe.txt', readMe) 284 | 285 | console.log(readMe) 286 | console.log('finished sync') 287 | 288 | // 异步读写文件 289 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 290 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 291 | 292 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 293 | fs.writeFile('writeMe.txt', data, function () { 294 | console.log('writeMe has finished') 295 | }) 296 | }) 297 | 298 | console.log('end') 299 | ``` 300 | 301 | ## 7.创建和删除目录 302 | 303 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 304 | 305 | ```js 306 | var fs = require('fs') 307 | 308 | // 异步删除文件 309 | fs.unlink('writeMe.txt', function () { 310 | console.log('delete writeMe.txt file') 311 | }) 312 | 313 | // 同步创建和删除目录 314 | fs.mkdirSync('stuff') 315 | fs.rmdirSync('stuff') 316 | 317 | // 异步 318 | fs.mkdir('stuff', function () { 319 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 320 | fs.writeFile('./stuff/writeMe.txt', data, function () { 321 | console.log('copy successfully') 322 | }) 323 | }) 324 | }) 325 | ``` 326 | 327 | ## 8.流和管道 328 | 329 | - 流(stream) 330 | - 处理流式数据的抽象接口 331 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 332 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 333 | - 流处理数据通过缓存可以提高性能 334 | 335 | # hello-nodejs 336 | 337 | 轻松学 Node.js 基础篇 入门 338 | 339 | 视频地址 340 | 341 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 342 | - [b站](https://www.bilibili.com/video/av21010015) 343 | 344 | 常用链接 345 | 346 | - [Node.js 官网](https://nodejs.org/zh-cn/) 347 | - [Node.js 中文网](http://nodejs.cn) 348 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 349 | 350 | 看视频整理要点笔记: 351 | 352 | --- 353 | 354 | - [hello-nodejs](#hello-nodejs) 355 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 356 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 357 | 358 | --- 359 | 360 | ## 1.课程介绍与开发环境搭建 361 | 362 | - 主要包括 363 | - nodejs 基础知识 364 | - web 服务器 365 | - 异步 同步 阻塞 非阻塞 366 | 367 | - 课程基础 368 | - javascript 基础 369 | - html 基础 370 | - 命令行基础 371 | 372 | - Node.js 介绍 373 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 374 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 375 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 376 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 377 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 378 | - V8 引擎是开源的,由 C++ 语言编写,性能高 379 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 380 | 381 | - Node.js 安装 382 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 383 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 384 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 385 | - macOS 安装完提示如下 386 | 387 | ```sh 388 | This package has installed: 389 | • Node.js v8.11.4 to /usr/local/bin/node 390 | • npm v5.6.0 to /usr/local/bin/npm 391 | Make sure that /usr/local/bin is in your $PATH. 392 | ``` 393 | 394 | - Node.js 用途 395 | 396 | - javascript 运行环境 397 | - 操作文件(grunt gulp webpack) 398 | - 操作数据库 399 | - 写后端 api 400 | - 命令行工具 401 | - web 开发 402 | - 聊天室 403 | 404 | - JavaScript 语句后应该加分号么? 405 | - [知乎讨论](https://www.zhihu.com/question/20298345) 406 | - 代码风格而已,没有定论 407 | - 少分号更易读,不累 408 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 409 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 410 | 411 | ## 2.全局对象 412 | 413 | - 全局对象 414 | - 不用导入,直接使用的对象 415 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 416 | - Buffer 类,用于处理二进制数据 417 | - console,用于打印 stdout 和 stderr 418 | - global, 全局的命名空间对象 419 | - process,进程对象 420 | - setTimeout(callback, delay[, ...args]) 421 | - setInterval(callback, delay[, ...args]) 422 | - setImmediate(callback[, ...args]) 423 | - clearTimeout(timeoutObject) 424 | - clearInterval(intervalObject) 425 | - clearImmediate(immediateObject) 426 | 427 | - 以下变量虽然看起来像全局变量,但实际上不是 428 | - 全局变量在所有模块中均可使用 429 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 430 | - __dirname 431 | - __filename 432 | - exports 433 | - module 434 | - require() 435 | 436 | - 运行 `.js` 脚本文件 437 | - `node app` 或者 `node app.js` 438 | 439 | - 实践代码 440 | 441 | ```js 442 | console.log('hello world'); 443 | 444 | setTimeout(function () { 445 | console.log("3 seconds have passed 2"); 446 | }, 3000); 447 | 448 | // 箭头函数,es6的写法 449 | setTimeout(() => { 450 | console.log("3 seconds have passed 1"); 451 | }, 3000); 452 | 453 | // 每间隔2秒不断执行 454 | setInterval(function () { 455 | console.log("2 seconds have passed"); 456 | }, 2000); 457 | 458 | 459 | var time = 0 460 | var timer = setInterval(function () { 461 | time += 2; 462 | console.log(time + " seconds have passed"); 463 | if (time > 6) { 464 | clearInterval(timer); 465 | console.log("clearInterval") 466 | } 467 | }, 2000) 468 | 469 | // 输出当前目录 和 带绝对路径的文件名 470 | console.log(__dirname) 471 | console.log(__filename) 472 | 473 | console.log('end') 474 | console.dir(global) 475 | ``` 476 | 477 | ## 3.回调函数 478 | 479 | ```js 480 | function sayHi() { 481 | console.log('Hi') 482 | } 483 | 484 | sayHi() // 调用函数 485 | 486 | // 将匿名函数赋给变量 487 | var sayBye = function (name) { 488 | console.log(name + ' Bye') 489 | } 490 | 491 | sayBye() 492 | 493 | // 第一个参数是函数 494 | function callFunction(fun, name) { 495 | fun(name) 496 | } 497 | 498 | callFunction(sayBye, 'able') 499 | // 或者 500 | callFunction(function (name) { 501 | console.log(name + ' Bye') 502 | }, 'able') 503 | ``` 504 | 505 | ## 4.模块 506 | 507 | - module 对象 508 | - 每个文件都被视为独立的模块 509 | - 每个模块中,module 指向表示当前模块的对象的引用 510 | - module 实际上不是全局的,而是每个模块本地的 511 | - module.exports 导出模块内的对象,方便其他对象引用 512 | - require() 引入模块 513 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 514 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 515 | - module 提供了一个 filename 属性(通常等同于 __filename) 516 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 517 | 518 | ```js 519 | // counter.js 520 | var counter = function (arr) { 521 | return "There are " + arr.length + " elements in array" 522 | } 523 | 524 | var adder = function (a, b) { 525 | return `the sum of the 2 numbers is ${a+b}` 526 | } 527 | 528 | var pi = 3.14 529 | 530 | // 只有一个时可以这样导入 531 | // module.exports = counter 532 | 533 | /* 534 | module.exports.counter = counter 535 | module.exports.adder = adder 536 | module.exports.pi = pi 537 | */ 538 | 539 | module.exports = { 540 | counter: counter, 541 | adder: adder, 542 | pi: pi, 543 | } 544 | /* 对象可以简写 545 | module.exports = { 546 | counter, 547 | adder, 548 | pi, 549 | } 550 | */ 551 | 552 | //p4.js 553 | var stuff = require('./count') 554 | 555 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 556 | console.log(stuff.adder(3, 2)) 557 | console.log(stuff.pi) 558 | ``` 559 | 560 | ## 5.事件 events 561 | 562 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 563 | - 所有能触发事件的对象都是 EventEmitter 类的实例 564 | - 事件名称通常是驼峰式的字符串 565 | 566 | - 实践代码 567 | 568 | ```js 569 | var events = require('events') 570 | var util = require('util') 571 | 572 | // 事件 对象 573 | var myEmitter = new events.EventEmitter() 574 | 575 | // 绑定 事件名称 和 回调函数 576 | myEmitter.on('someEvent', function (message) { 577 | console.log(message) 578 | }) 579 | 580 | // 触发实践,使用事件名称 581 | myEmitter.emit('someEvent', 'The event was emitted') 582 | 583 | // 创建对象 584 | var Person = function (name) { 585 | this.name = name 586 | } 587 | 588 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 589 | util.inherits(Person, events.EventEmitter) 590 | // 新建对象 591 | var xiaoming = new Person('xiaoming') 592 | var lili = new Person('lili') 593 | 594 | var person = [xiaoming, lili] 595 | 596 | // 循环person数组,绑定事件 597 | person.forEach(function (person) { 598 | person.on('speak', function (message) { 599 | console.log(person.name + ' said: ' + message) 600 | }) 601 | }) 602 | 603 | // 触发事件 604 | xiaoming.emit('speak', 'hi') 605 | lili.emit('speak', 'I want a curry') 606 | ``` 607 | 608 | ## 6.读写文件(同步和异步) 609 | 610 | ```js 611 | var fs = require('fs') 612 | 613 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 614 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 615 | fs.writeFileSync('writeMe.txt', readMe) 616 | 617 | console.log(readMe) 618 | console.log('finished sync') 619 | 620 | // 异步读写文件 621 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 622 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 623 | 624 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 625 | fs.writeFile('writeMe.txt', data, function () { 626 | console.log('writeMe has finished') 627 | }) 628 | }) 629 | 630 | console.log('end') 631 | ``` 632 | 633 | ## 7.创建和删除目录 634 | 635 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 636 | 637 | ```js 638 | var fs = require('fs') 639 | 640 | // 异步删除文件 641 | fs.unlink('writeMe.txt', function () { 642 | console.log('delete writeMe.txt file') 643 | }) 644 | 645 | // 同步创建和删除目录 646 | fs.mkdirSync('stuff') 647 | fs.rmdirSync('stuff') 648 | 649 | // 异步 650 | fs.mkdir('stuff', function () { 651 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 652 | fs.writeFile('./stuff/writeMe.txt', data, function () { 653 | console.log('copy successfully') 654 | }) 655 | }) 656 | }) 657 | ``` 658 | 659 | ## 8.流和管道 660 | 661 | - 流(stream) 662 | - 处理流式数据的抽象接口 663 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 664 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 665 | - 流处理数据通过缓存可以提高性能 666 | # hello-nodejs 667 | 668 | 轻松学 Node.js 基础篇 入门 669 | 670 | 视频地址 671 | 672 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 673 | - [b站](https://www.bilibili.com/video/av21010015) 674 | 675 | 常用链接 676 | 677 | - [Node.js 官网](https://nodejs.org/zh-cn/) 678 | - [Node.js 中文网](http://nodejs.cn) 679 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 680 | 681 | 看视频整理要点笔记: 682 | 683 | --- 684 | 685 | - [hello-nodejs](#hello-nodejs) 686 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 687 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 688 | 689 | --- 690 | 691 | ## 1.课程介绍与开发环境搭建 692 | 693 | - 主要包括 694 | - nodejs 基础知识 695 | - web 服务器 696 | - 异步 同步 阻塞 非阻塞 697 | 698 | - 课程基础 699 | - javascript 基础 700 | - html 基础 701 | - 命令行基础 702 | 703 | - Node.js 介绍 704 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 705 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 706 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 707 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 708 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 709 | - V8 引擎是开源的,由 C++ 语言编写,性能高 710 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 711 | 712 | - Node.js 安装 713 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 714 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 715 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 716 | - macOS 安装完提示如下 717 | 718 | ```sh 719 | This package has installed: 720 | • Node.js v8.11.4 to /usr/local/bin/node 721 | • npm v5.6.0 to /usr/local/bin/npm 722 | Make sure that /usr/local/bin is in your $PATH. 723 | ``` 724 | 725 | - Node.js 用途 726 | 727 | - javascript 运行环境 728 | - 操作文件(grunt gulp webpack) 729 | - 操作数据库 730 | - 写后端 api 731 | - 命令行工具 732 | - web 开发 733 | - 聊天室 734 | 735 | - JavaScript 语句后应该加分号么? 736 | - [知乎讨论](https://www.zhihu.com/question/20298345) 737 | - 代码风格而已,没有定论 738 | - 少分号更易读,不累 739 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 740 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 741 | 742 | ## 2.全局对象 743 | 744 | - 全局对象 745 | - 不用导入,直接使用的对象 746 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 747 | - Buffer 类,用于处理二进制数据 748 | - console,用于打印 stdout 和 stderr 749 | - global, 全局的命名空间对象 750 | - process,进程对象 751 | - setTimeout(callback, delay[, ...args]) 752 | - setInterval(callback, delay[, ...args]) 753 | - setImmediate(callback[, ...args]) 754 | - clearTimeout(timeoutObject) 755 | - clearInterval(intervalObject) 756 | - clearImmediate(immediateObject) 757 | 758 | - 以下变量虽然看起来像全局变量,但实际上不是 759 | - 全局变量在所有模块中均可使用 760 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 761 | - __dirname 762 | - __filename 763 | - exports 764 | - module 765 | - require() 766 | 767 | - 运行 `.js` 脚本文件 768 | - `node app` 或者 `node app.js` 769 | 770 | - 实践代码 771 | 772 | ```js 773 | console.log('hello world'); 774 | 775 | setTimeout(function () { 776 | console.log("3 seconds have passed 2"); 777 | }, 3000); 778 | 779 | // 箭头函数,es6的写法 780 | setTimeout(() => { 781 | console.log("3 seconds have passed 1"); 782 | }, 3000); 783 | 784 | // 每间隔2秒不断执行 785 | setInterval(function () { 786 | console.log("2 seconds have passed"); 787 | }, 2000); 788 | 789 | 790 | var time = 0 791 | var timer = setInterval(function () { 792 | time += 2; 793 | console.log(time + " seconds have passed"); 794 | if (time > 6) { 795 | clearInterval(timer); 796 | console.log("clearInterval") 797 | } 798 | }, 2000) 799 | 800 | // 输出当前目录 和 带绝对路径的文件名 801 | console.log(__dirname) 802 | console.log(__filename) 803 | 804 | console.log('end') 805 | console.dir(global) 806 | ``` 807 | 808 | ## 3.回调函数 809 | 810 | ```js 811 | function sayHi() { 812 | console.log('Hi') 813 | } 814 | 815 | sayHi() // 调用函数 816 | 817 | // 将匿名函数赋给变量 818 | var sayBye = function (name) { 819 | console.log(name + ' Bye') 820 | } 821 | 822 | sayBye() 823 | 824 | // 第一个参数是函数 825 | function callFunction(fun, name) { 826 | fun(name) 827 | } 828 | 829 | callFunction(sayBye, 'able') 830 | // 或者 831 | callFunction(function (name) { 832 | console.log(name + ' Bye') 833 | }, 'able') 834 | ``` 835 | 836 | ## 4.模块 837 | 838 | - module 对象 839 | - 每个文件都被视为独立的模块 840 | - 每个模块中,module 指向表示当前模块的对象的引用 841 | - module 实际上不是全局的,而是每个模块本地的 842 | - module.exports 导出模块内的对象,方便其他对象引用 843 | - require() 引入模块 844 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 845 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 846 | - module 提供了一个 filename 属性(通常等同于 __filename) 847 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 848 | 849 | ```js 850 | // counter.js 851 | var counter = function (arr) { 852 | return "There are " + arr.length + " elements in array" 853 | } 854 | 855 | var adder = function (a, b) { 856 | return `the sum of the 2 numbers is ${a+b}` 857 | } 858 | 859 | var pi = 3.14 860 | 861 | // 只有一个时可以这样导入 862 | // module.exports = counter 863 | 864 | /* 865 | module.exports.counter = counter 866 | module.exports.adder = adder 867 | module.exports.pi = pi 868 | */ 869 | 870 | module.exports = { 871 | counter: counter, 872 | adder: adder, 873 | pi: pi, 874 | } 875 | /* 对象可以简写 876 | module.exports = { 877 | counter, 878 | adder, 879 | pi, 880 | } 881 | */ 882 | 883 | //p4.js 884 | var stuff = require('./count') 885 | 886 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 887 | console.log(stuff.adder(3, 2)) 888 | console.log(stuff.pi) 889 | ``` 890 | 891 | ## 5.事件 events 892 | 893 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 894 | - 所有能触发事件的对象都是 EventEmitter 类的实例 895 | - 事件名称通常是驼峰式的字符串 896 | 897 | - 实践代码 898 | 899 | ```js 900 | var events = require('events') 901 | var util = require('util') 902 | 903 | // 事件 对象 904 | var myEmitter = new events.EventEmitter() 905 | 906 | // 绑定 事件名称 和 回调函数 907 | myEmitter.on('someEvent', function (message) { 908 | console.log(message) 909 | }) 910 | 911 | // 触发实践,使用事件名称 912 | myEmitter.emit('someEvent', 'The event was emitted') 913 | 914 | // 创建对象 915 | var Person = function (name) { 916 | this.name = name 917 | } 918 | 919 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 920 | util.inherits(Person, events.EventEmitter) 921 | // 新建对象 922 | var xiaoming = new Person('xiaoming') 923 | var lili = new Person('lili') 924 | 925 | var person = [xiaoming, lili] 926 | 927 | // 循环person数组,绑定事件 928 | person.forEach(function (person) { 929 | person.on('speak', function (message) { 930 | console.log(person.name + ' said: ' + message) 931 | }) 932 | }) 933 | 934 | // 触发事件 935 | xiaoming.emit('speak', 'hi') 936 | lili.emit('speak', 'I want a curry') 937 | ``` 938 | 939 | ## 6.读写文件(同步和异步) 940 | 941 | ```js 942 | var fs = require('fs') 943 | 944 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 945 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 946 | fs.writeFileSync('writeMe.txt', readMe) 947 | 948 | console.log(readMe) 949 | console.log('finished sync') 950 | 951 | // 异步读写文件 952 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 953 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 954 | 955 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 956 | fs.writeFile('writeMe.txt', data, function () { 957 | console.log('writeMe has finished') 958 | }) 959 | }) 960 | 961 | console.log('end') 962 | ``` 963 | 964 | ## 7.创建和删除目录 965 | 966 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 967 | 968 | ```js 969 | var fs = require('fs') 970 | 971 | // 异步删除文件 972 | fs.unlink('writeMe.txt', function () { 973 | console.log('delete writeMe.txt file') 974 | }) 975 | 976 | // 同步创建和删除目录 977 | fs.mkdirSync('stuff') 978 | fs.rmdirSync('stuff') 979 | 980 | // 异步 981 | fs.mkdir('stuff', function () { 982 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 983 | fs.writeFile('./stuff/writeMe.txt', data, function () { 984 | console.log('copy successfully') 985 | }) 986 | }) 987 | }) 988 | ``` 989 | 990 | ## 8.流和管道 991 | 992 | - 流(stream) 993 | - 处理流式数据的抽象接口 994 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 995 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 996 | - 流处理数据通过缓存可以提高性能 997 | # hello-nodejs 998 | 999 | 轻松学 Node.js 基础篇 入门 1000 | 1001 | 视频地址 1002 | 1003 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 1004 | - [b站](https://www.bilibili.com/video/av21010015) 1005 | 1006 | 常用链接 1007 | 1008 | - [Node.js 官网](https://nodejs.org/zh-cn/) 1009 | - [Node.js 中文网](http://nodejs.cn) 1010 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 1011 | 1012 | 看视频整理要点笔记: 1013 | 1014 | --- 1015 | 1016 | - [hello-nodejs](#hello-nodejs) 1017 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 1018 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 1019 | 1020 | --- 1021 | 1022 | ## 1.课程介绍与开发环境搭建 1023 | 1024 | - 主要包括 1025 | - nodejs 基础知识 1026 | - web 服务器 1027 | - 异步 同步 阻塞 非阻塞 1028 | 1029 | - 课程基础 1030 | - javascript 基础 1031 | - html 基础 1032 | - 命令行基础 1033 | 1034 | - Node.js 介绍 1035 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 1036 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 1037 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 1038 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 1039 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 1040 | - V8 引擎是开源的,由 C++ 语言编写,性能高 1041 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 1042 | 1043 | - Node.js 安装 1044 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 1045 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 1046 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 1047 | - macOS 安装完提示如下 1048 | 1049 | ```sh 1050 | This package has installed: 1051 | • Node.js v8.11.4 to /usr/local/bin/node 1052 | • npm v5.6.0 to /usr/local/bin/npm 1053 | Make sure that /usr/local/bin is in your $PATH. 1054 | ``` 1055 | 1056 | - Node.js 用途 1057 | 1058 | - javascript 运行环境 1059 | - 操作文件(grunt gulp webpack) 1060 | - 操作数据库 1061 | - 写后端 api 1062 | - 命令行工具 1063 | - web 开发 1064 | - 聊天室 1065 | 1066 | - JavaScript 语句后应该加分号么? 1067 | - [知乎讨论](https://www.zhihu.com/question/20298345) 1068 | - 代码风格而已,没有定论 1069 | - 少分号更易读,不累 1070 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 1071 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 1072 | 1073 | ## 2.全局对象 1074 | 1075 | - 全局对象 1076 | - 不用导入,直接使用的对象 1077 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 1078 | - Buffer 类,用于处理二进制数据 1079 | - console,用于打印 stdout 和 stderr 1080 | - global, 全局的命名空间对象 1081 | - process,进程对象 1082 | - setTimeout(callback, delay[, ...args]) 1083 | - setInterval(callback, delay[, ...args]) 1084 | - setImmediate(callback[, ...args]) 1085 | - clearTimeout(timeoutObject) 1086 | - clearInterval(intervalObject) 1087 | - clearImmediate(immediateObject) 1088 | 1089 | - 以下变量虽然看起来像全局变量,但实际上不是 1090 | - 全局变量在所有模块中均可使用 1091 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 1092 | - __dirname 1093 | - __filename 1094 | - exports 1095 | - module 1096 | - require() 1097 | 1098 | - 运行 `.js` 脚本文件 1099 | - `node app` 或者 `node app.js` 1100 | 1101 | - 实践代码 1102 | 1103 | ```js 1104 | console.log('hello world'); 1105 | 1106 | setTimeout(function () { 1107 | console.log("3 seconds have passed 2"); 1108 | }, 3000); 1109 | 1110 | // 箭头函数,es6的写法 1111 | setTimeout(() => { 1112 | console.log("3 seconds have passed 1"); 1113 | }, 3000); 1114 | 1115 | // 每间隔2秒不断执行 1116 | setInterval(function () { 1117 | console.log("2 seconds have passed"); 1118 | }, 2000); 1119 | 1120 | 1121 | var time = 0 1122 | var timer = setInterval(function () { 1123 | time += 2; 1124 | console.log(time + " seconds have passed"); 1125 | if (time > 6) { 1126 | clearInterval(timer); 1127 | console.log("clearInterval") 1128 | } 1129 | }, 2000) 1130 | 1131 | // 输出当前目录 和 带绝对路径的文件名 1132 | console.log(__dirname) 1133 | console.log(__filename) 1134 | 1135 | console.log('end') 1136 | console.dir(global) 1137 | ``` 1138 | 1139 | ## 3.回调函数 1140 | 1141 | ```js 1142 | function sayHi() { 1143 | console.log('Hi') 1144 | } 1145 | 1146 | sayHi() // 调用函数 1147 | 1148 | // 将匿名函数赋给变量 1149 | var sayBye = function (name) { 1150 | console.log(name + ' Bye') 1151 | } 1152 | 1153 | sayBye() 1154 | 1155 | // 第一个参数是函数 1156 | function callFunction(fun, name) { 1157 | fun(name) 1158 | } 1159 | 1160 | callFunction(sayBye, 'able') 1161 | // 或者 1162 | callFunction(function (name) { 1163 | console.log(name + ' Bye') 1164 | }, 'able') 1165 | ``` 1166 | 1167 | ## 4.模块 1168 | 1169 | - module 对象 1170 | - 每个文件都被视为独立的模块 1171 | - 每个模块中,module 指向表示当前模块的对象的引用 1172 | - module 实际上不是全局的,而是每个模块本地的 1173 | - module.exports 导出模块内的对象,方便其他对象引用 1174 | - require() 引入模块 1175 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 1176 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 1177 | - module 提供了一个 filename 属性(通常等同于 __filename) 1178 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 1179 | 1180 | ```js 1181 | // counter.js 1182 | var counter = function (arr) { 1183 | return "There are " + arr.length + " elements in array" 1184 | } 1185 | 1186 | var adder = function (a, b) { 1187 | return `the sum of the 2 numbers is ${a+b}` 1188 | } 1189 | 1190 | var pi = 3.14 1191 | 1192 | // 只有一个时可以这样导入 1193 | // module.exports = counter 1194 | 1195 | /* 1196 | module.exports.counter = counter 1197 | module.exports.adder = adder 1198 | module.exports.pi = pi 1199 | */ 1200 | 1201 | module.exports = { 1202 | counter: counter, 1203 | adder: adder, 1204 | pi: pi, 1205 | } 1206 | /* 对象可以简写 1207 | module.exports = { 1208 | counter, 1209 | adder, 1210 | pi, 1211 | } 1212 | */ 1213 | 1214 | //p4.js 1215 | var stuff = require('./count') 1216 | 1217 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 1218 | console.log(stuff.adder(3, 2)) 1219 | console.log(stuff.pi) 1220 | ``` 1221 | 1222 | ## 5.事件 events 1223 | 1224 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 1225 | - 所有能触发事件的对象都是 EventEmitter 类的实例 1226 | - 事件名称通常是驼峰式的字符串 1227 | 1228 | - 实践代码 1229 | 1230 | ```js 1231 | var events = require('events') 1232 | var util = require('util') 1233 | 1234 | // 事件 对象 1235 | var myEmitter = new events.EventEmitter() 1236 | 1237 | // 绑定 事件名称 和 回调函数 1238 | myEmitter.on('someEvent', function (message) { 1239 | console.log(message) 1240 | }) 1241 | 1242 | // 触发实践,使用事件名称 1243 | myEmitter.emit('someEvent', 'The event was emitted') 1244 | 1245 | // 创建对象 1246 | var Person = function (name) { 1247 | this.name = name 1248 | } 1249 | 1250 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 1251 | util.inherits(Person, events.EventEmitter) 1252 | // 新建对象 1253 | var xiaoming = new Person('xiaoming') 1254 | var lili = new Person('lili') 1255 | 1256 | var person = [xiaoming, lili] 1257 | 1258 | // 循环person数组,绑定事件 1259 | person.forEach(function (person) { 1260 | person.on('speak', function (message) { 1261 | console.log(person.name + ' said: ' + message) 1262 | }) 1263 | }) 1264 | 1265 | // 触发事件 1266 | xiaoming.emit('speak', 'hi') 1267 | lili.emit('speak', 'I want a curry') 1268 | ``` 1269 | 1270 | ## 6.读写文件(同步和异步) 1271 | 1272 | ```js 1273 | var fs = require('fs') 1274 | 1275 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 1276 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 1277 | fs.writeFileSync('writeMe.txt', readMe) 1278 | 1279 | console.log(readMe) 1280 | console.log('finished sync') 1281 | 1282 | // 异步读写文件 1283 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 1284 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 1285 | 1286 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 1287 | fs.writeFile('writeMe.txt', data, function () { 1288 | console.log('writeMe has finished') 1289 | }) 1290 | }) 1291 | 1292 | console.log('end') 1293 | ``` 1294 | 1295 | ## 7.创建和删除目录 1296 | 1297 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 1298 | 1299 | ```js 1300 | var fs = require('fs') 1301 | 1302 | // 异步删除文件 1303 | fs.unlink('writeMe.txt', function () { 1304 | console.log('delete writeMe.txt file') 1305 | }) 1306 | 1307 | // 同步创建和删除目录 1308 | fs.mkdirSync('stuff') 1309 | fs.rmdirSync('stuff') 1310 | 1311 | // 异步 1312 | fs.mkdir('stuff', function () { 1313 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 1314 | fs.writeFile('./stuff/writeMe.txt', data, function () { 1315 | console.log('copy successfully') 1316 | }) 1317 | }) 1318 | }) 1319 | ``` 1320 | 1321 | ## 8.流和管道 1322 | 1323 | - 流(stream) 1324 | - 处理流式数据的抽象接口 1325 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 1326 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 1327 | - 流处理数据通过缓存可以提高性能 1328 | # hello-nodejs 1329 | 1330 | 轻松学 Node.js 基础篇 入门 1331 | 1332 | 视频地址 1333 | 1334 | - [https://www.rails365.net](https://www.rails365.net/movies/qing-song-xue-nodejs-ji-chu-pian-1-ke-cheng-jie-shao-yu-kai-fa-huan-jing-da-jian) 1335 | - [b站](https://www.bilibili.com/video/av21010015) 1336 | 1337 | 常用链接 1338 | 1339 | - [Node.js 官网](https://nodejs.org/zh-cn/) 1340 | - [Node.js 中文网](http://nodejs.cn) 1341 | - [CNode:Node.js专业中文社区](https://cnodejs.org) 1342 | 1343 | 看视频整理要点笔记: 1344 | 1345 | --- 1346 | 1347 | - [hello-nodejs](#hello-nodejs) 1348 | - [1.课程介绍与开发环境搭建](#1%E8%AF%BE%E7%A8%8B%E4%BB%8B%E7%BB%8D%E4%B8%8E%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA) 1349 | - [2.全局对象](#2%E5%85%A8%E5%B1%80%E5%AF%B9%E8%B1%A1) 1350 | 1351 | --- 1352 | 1353 | ## 1.课程介绍与开发环境搭建 1354 | 1355 | - 主要包括 1356 | - nodejs 基础知识 1357 | - web 服务器 1358 | - 异步 同步 阻塞 非阻塞 1359 | 1360 | - 课程基础 1361 | - javascript 基础 1362 | - html 基础 1363 | - 命令行基础 1364 | 1365 | - Node.js 介绍 1366 | - Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境 1367 | - Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效 1368 | - Node.js 的包管理器 npm,是全球最大的开源库生态系统 1369 | - javascript 是脚本语言,需要解析器才能执行,浏览器就充当了解析器 1370 | - 在Chrome中,解析器就是 V8 引擎,将 javascript 转换成 机器码 1371 | - V8 引擎是开源的,由 C++ 语言编写,性能高 1372 | - Node.js 高性能,事件驱动,非阻塞,生态圈很好 1373 | 1374 | - Node.js 安装 1375 | - [官网](https://nodejs.org/zh-cn/) 下载安装即可,很小不到20M! 1376 | - 验证是否成功,命令行输入 `node -v` 显示版本号如 `v8.11.4` 1377 | - 按提示升级 npm,Update available 5.6.0 → 6.4.1, `npm i -g npm` 1378 | - macOS 安装完提示如下 1379 | 1380 | ```sh 1381 | This package has installed: 1382 | • Node.js v8.11.4 to /usr/local/bin/node 1383 | • npm v5.6.0 to /usr/local/bin/npm 1384 | Make sure that /usr/local/bin is in your $PATH. 1385 | ``` 1386 | 1387 | - Node.js 用途 1388 | 1389 | - javascript 运行环境 1390 | - 操作文件(grunt gulp webpack) 1391 | - 操作数据库 1392 | - 写后端 api 1393 | - 命令行工具 1394 | - web 开发 1395 | - 聊天室 1396 | 1397 | - JavaScript 语句后应该加分号么? 1398 | - [知乎讨论](https://www.zhihu.com/question/20298345) 1399 | - 代码风格而已,没有定论 1400 | - 少分号更易读,不累 1401 | - 必须加分号情况很少见:一行开头是括号`(`或者方括号`[`的时候加上分号就可以了,其他时候都不要 1402 | - 如果下一行的行首是`( [ / + -`之一的话,js不会自动在上一行句尾加上分号 1403 | 1404 | ## 2.全局对象 1405 | 1406 | - 全局对象 1407 | - 不用导入,直接使用的对象 1408 | - [官方文档](http://nodejs.cn/api/globals.html#globals_global_objects) 1409 | - Buffer 类,用于处理二进制数据 1410 | - console,用于打印 stdout 和 stderr 1411 | - global, 全局的命名空间对象 1412 | - process,进程对象 1413 | - setTimeout(callback, delay[, ...args]) 1414 | - setInterval(callback, delay[, ...args]) 1415 | - setImmediate(callback[, ...args]) 1416 | - clearTimeout(timeoutObject) 1417 | - clearInterval(intervalObject) 1418 | - clearImmediate(immediateObject) 1419 | 1420 | - 以下变量虽然看起来像全局变量,但实际上不是 1421 | - 全局变量在所有模块中均可使用 1422 | - 以下对象作用域只在模块内,详见 [module文档](http://nodejs.cn/api/modules.html): 1423 | - __dirname 1424 | - __filename 1425 | - exports 1426 | - module 1427 | - require() 1428 | 1429 | - 运行 `.js` 脚本文件 1430 | - `node app` 或者 `node app.js` 1431 | 1432 | - 实践代码 1433 | 1434 | ```js 1435 | console.log('hello world'); 1436 | 1437 | setTimeout(function () { 1438 | console.log("3 seconds have passed 2"); 1439 | }, 3000); 1440 | 1441 | // 箭头函数,es6的写法 1442 | setTimeout(() => { 1443 | console.log("3 seconds have passed 1"); 1444 | }, 3000); 1445 | 1446 | // 每间隔2秒不断执行 1447 | setInterval(function () { 1448 | console.log("2 seconds have passed"); 1449 | }, 2000); 1450 | 1451 | 1452 | var time = 0 1453 | var timer = setInterval(function () { 1454 | time += 2; 1455 | console.log(time + " seconds have passed"); 1456 | if (time > 6) { 1457 | clearInterval(timer); 1458 | console.log("clearInterval") 1459 | } 1460 | }, 2000) 1461 | 1462 | // 输出当前目录 和 带绝对路径的文件名 1463 | console.log(__dirname) 1464 | console.log(__filename) 1465 | 1466 | console.log('end') 1467 | console.dir(global) 1468 | ``` 1469 | 1470 | ## 3.回调函数 1471 | 1472 | ```js 1473 | function sayHi() { 1474 | console.log('Hi') 1475 | } 1476 | 1477 | sayHi() // 调用函数 1478 | 1479 | // 将匿名函数赋给变量 1480 | var sayBye = function (name) { 1481 | console.log(name + ' Bye') 1482 | } 1483 | 1484 | sayBye() 1485 | 1486 | // 第一个参数是函数 1487 | function callFunction(fun, name) { 1488 | fun(name) 1489 | } 1490 | 1491 | callFunction(sayBye, 'able') 1492 | // 或者 1493 | callFunction(function (name) { 1494 | console.log(name + ' Bye') 1495 | }, 'able') 1496 | ``` 1497 | 1498 | ## 4.模块 1499 | 1500 | - module 对象 1501 | - 每个文件都被视为独立的模块 1502 | - 每个模块中,module 指向表示当前模块的对象的引用 1503 | - module 实际上不是全局的,而是每个模块本地的 1504 | - module.exports 导出模块内的对象,方便其他对象引用 1505 | - require() 引入模块 1506 | - 当 Node.js 直接运行一个文件时,require.main 会被设为它的 module 1507 | - 可以通过 require.main === module 来判断一个文件是否被直接运行 1508 | - module 提供了一个 filename 属性(通常等同于 __filename) 1509 | - 可以通过检查 require.main.filename 来获取当前应用程序的入口点 1510 | 1511 | ```js 1512 | // counter.js 1513 | var counter = function (arr) { 1514 | return "There are " + arr.length + " elements in array" 1515 | } 1516 | 1517 | var adder = function (a, b) { 1518 | return `the sum of the 2 numbers is ${a+b}` 1519 | } 1520 | 1521 | var pi = 3.14 1522 | 1523 | // 只有一个时可以这样导入 1524 | // module.exports = counter 1525 | 1526 | /* 1527 | module.exports.counter = counter 1528 | module.exports.adder = adder 1529 | module.exports.pi = pi 1530 | */ 1531 | 1532 | module.exports = { 1533 | counter: counter, 1534 | adder: adder, 1535 | pi: pi, 1536 | } 1537 | /* 对象可以简写 1538 | module.exports = { 1539 | counter, 1540 | adder, 1541 | pi, 1542 | } 1543 | */ 1544 | 1545 | //p4.js 1546 | var stuff = require('./count') 1547 | 1548 | console.log(stuff.counter(['ruby', 'nodejs', 'react'])) 1549 | console.log(stuff.adder(3, 2)) 1550 | console.log(stuff.pi) 1551 | ``` 1552 | 1553 | ## 5.事件 events 1554 | 1555 | - 多数 Node.js 核心 API 都采用异步事件驱动架构 1556 | - 所有能触发事件的对象都是 EventEmitter 类的实例 1557 | - 事件名称通常是驼峰式的字符串 1558 | 1559 | - 实践代码 1560 | 1561 | ```js 1562 | var events = require('events') 1563 | var util = require('util') 1564 | 1565 | // 事件 对象 1566 | var myEmitter = new events.EventEmitter() 1567 | 1568 | // 绑定 事件名称 和 回调函数 1569 | myEmitter.on('someEvent', function (message) { 1570 | console.log(message) 1571 | }) 1572 | 1573 | // 触发实践,使用事件名称 1574 | myEmitter.emit('someEvent', 'The event was emitted') 1575 | 1576 | // 创建对象 1577 | var Person = function (name) { 1578 | this.name = name 1579 | } 1580 | 1581 | // 继承,让Person类具有事件对象的特性,绑定和触发事件 1582 | util.inherits(Person, events.EventEmitter) 1583 | // 新建对象 1584 | var xiaoming = new Person('xiaoming') 1585 | var lili = new Person('lili') 1586 | 1587 | var person = [xiaoming, lili] 1588 | 1589 | // 循环person数组,绑定事件 1590 | person.forEach(function (person) { 1591 | person.on('speak', function (message) { 1592 | console.log(person.name + ' said: ' + message) 1593 | }) 1594 | }) 1595 | 1596 | // 触发事件 1597 | xiaoming.emit('speak', 'hi') 1598 | lili.emit('speak', 'I want a curry') 1599 | ``` 1600 | 1601 | ## 6.读写文件(同步和异步) 1602 | 1603 | ```js 1604 | var fs = require('fs') 1605 | 1606 | // 同步读写文件,顺序执行,如果读取时间很长,会阻塞进程 1607 | var readMe = fs.readFileSync('readMe.txt', 'utf8') 1608 | fs.writeFileSync('writeMe.txt', readMe) 1609 | 1610 | console.log(readMe) 1611 | console.log('finished sync') 1612 | 1613 | // 异步读写文件 1614 | // 异步事件,Nodejs 维护一个事件队列,注册事件,完成后执行主线程 1615 | // 当主线程空闲时,取出执行事件,从线程池中发起线程执行事件, 当事件执行完成后通知主线程。这就是异步高效的原因。 1616 | 1617 | var readMe = fs.readFile('readMe.txt', 'utf8', function (err, data) { 1618 | fs.writeFile('writeMe.txt', data, function () { 1619 | console.log('writeMe has finished') 1620 | }) 1621 | }) 1622 | 1623 | console.log('end') 1624 | ``` 1625 | 1626 | ## 7.创建和删除目录 1627 | 1628 | - [ fs - 文件系统 API 文档](http://nodejs.cn/api/fs.html#fs_fs_unlink_path_callback) 1629 | 1630 | ```js 1631 | var fs = require('fs') 1632 | 1633 | // 异步删除文件 1634 | fs.unlink('writeMe.txt', function () { 1635 | console.log('delete writeMe.txt file') 1636 | }) 1637 | 1638 | // 同步创建和删除目录 1639 | fs.mkdirSync('stuff') 1640 | fs.rmdirSync('stuff') 1641 | 1642 | // 异步 1643 | fs.mkdir('stuff', function () { 1644 | fs.readFile('readMe.txt', 'utf8', function (err, data) { 1645 | fs.writeFile('./stuff/writeMe.txt', data, function () { 1646 | console.log('copy successfully') 1647 | }) 1648 | }) 1649 | }) 1650 | ``` 1651 | 1652 | ## 8.流和管道 1653 | 1654 | - 流(stream) 1655 | - 处理流式数据的抽象接口 1656 | - stream 模块提供了一些基础的 API,用于构建实现了流接口的对象 1657 | - 流可以是可读的、可写的、或是可读写的,所有的流都是 EventEmitter 的实例 1658 | - 流处理数据通过缓存可以提高性能 1659 | 1660 | --------------------------------------------------------------------------------