目录

 

 

 

一、什么是npm

二、命令行程序

三、commander.js

四、npm包管理

五、node提供一个链接可以下载图片

六、使用node原生http模块写接口

七、使用node原生http模块实现购物车所有接口(不需要装包,不需要中间件)

八、node原生写接口,搭建静态web服务器,处理前端history路由

九、安装FileZilla服务端

十、安装FileZilla客户端

十一、阿里云配置支持FTP

十二、colors

十三、express脚手架

十三、npm view指令

十四、String

十五、node是单线程

十六、错误处理

十七、process.nextTick(callback)

十八、根据下标打印动物

十九、node通过网页读取文件目录

20、重命名文件或文件夹

21、js区分对象函数和数组

22、事件触发器

23、手动封装事件

24、父子进程通信


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Node.js是单线程的,基于事件循环,非阻塞 IO的。事件循环中使用一个事件队列,在每个时间点上,系统只会处理一个事件,即使电脑有多个CPU核心,也无法同时并行的处理多个事件。因此,node.js适合处理I/O型的应用,不适合那种CPU运算密集型的应用。在I/O型的应用中,给每一个输入输出定义一个回调函数,node.js会自动将其加入到事件轮询的处理队列里,当I/O操作完成后,这个回调函数会被触发,系统会继续处理其他的请求。

一、什么是npm

npm是javascript的包管理工具,是前端模块化下的一个标志性产物。简单地地说,就是通过npm下载模块,复用已有的代码,提高工作效率。

  • 1.从社区的角度:把针对某一特定问题的模块发布到npm的服务器上,供社区里的其他人下载和使用,同时自己也可以在社区里寻找特定的模块的资源,解决问题
  • 2.从团队的角度:有了npm这个包管理工具,复用团队既有的代码也变的更加地方便

新建一个项目,cd进去,然后执行npm init来初始化项目的配置。

在执行npm init之前,有两点需要我们注意一下:

  • 包名不能重复
  • npm对包名的限制:不能有大写字母/空格/下划线

npm init 一路回车

或者:npm init -y

生成的package.json文件:

name和version组成唯一标识。每次发包时都要修改版本号。

description:描述

main:入口,别人安装你的npm包后,import时自动找到这个文件

scripts: 脚本 npm run test或者yarn test

keywords:关键字。放简介,字符串。方便别人查找。

author: 作者

license: 许可证

ISC许可证:https://baike.baidu.com/item/ISC%E8%AE%B8%E5%8F%AF%E8%AF%81/5490986?fr=aladdin

MIT许可证:https://baike.baidu.com/item/MIT%E8%AE%B8%E5%8F%AF%E8%AF%81/6671281?fr=aladdin

files:files是一个包含项目中的文件的数组。如果命名了一个文件夹,那也会包含文件夹中的文件。

{
  "name": "xu-20191024",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
{
  "name": "xu-20191024",
  "version": "1.0.2",
  "description": "1705E,项目实战",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["1705E","1706E"],
  "author": "徐同保",
  "license": "ISC"
}

检查包名是否存在:

https://www.npmjs.com/package/xu-20191025

node入门
 

通过keywords找:

node入门

repository:npm和git关联

  "repository": {
    "type": "git",
    "url": "https://github.com/xutongbao"
  },

node入门

homepage: 项目官网

  "homepage": "https://blog.csdn.net/xutongbao",

node入门

 

dependencies与devDependencies的区别:

在发布npm包的时候,本身dependencies下的模块会作为依赖,一起被下载;devDependencies下面的模块就不会自动下载了;但对于项目而言,npm install 会自动下载devDependencies和dependencies下面的模块。

当别人使用我们的插件时,peerDependencies就会告诉明确告诉使用方,你需要安装该插件哪个宿主版本:

  "dependencies": {
    "axios": "^0.19.0"
  },
  "devDependencies": {
    "element-ui": "^2.12.0"
  },
  "peerDependencies": {
    "react": "^16.11.0"
  },
  "optionalDependencies": {
    "redux": "^4.0.4"
  }

node入门

参考链接:

https://blog.csdn.net/yq_oxygen/article/details/90040392

https://cloud.tencent.com/developer/ask/40773

https://nodejs.org/zh-cn/blog/npm/peer-dependencies/

optionalDependencies:

可选依赖,如果有一些依赖包即使安装失败,项目仍然能够运行或者希望npm继续运行,就可以使用optionalDependencies。另外optionalDependencies会覆盖dependencies中的同名依赖包,所以不要在两个地方都写。

bin字段:

参考链接:

https://blog.csdn.net/feng98ren/article/details/93729399

src/index.js:

请确保你的index.js文件里面最开头写上 #!/usr/bin/env node,否则文件里的脚本不会再Node环境下执行

#!/usr/bin/env node
console.log(1)
  "bin": {
    "myapp": "./src/index.js"
  },

node入门

node入门

全局安装:

node入门

node入门

 

常用命令:

npm config list

npm config ls -l

安装npm包,安装到dependencies:

npm install commander --save-prod

npm install commander --save

npm install commander -S

npm install commander

npm add commander

npm i commander

安装npm包,安装到devDependencies:

npm install commander --save-dev

npm install commander -D

卸载npm包:

npm uninstall commander

npm unlink commander

npm remove commander

npm rm commander

npm un commander

npm r commander

安装到全局:

npm install create-react-app -g

从全局删除:

npm un create-react-app -g 

 

 

 

 

二、命令行程序

console.log('hello world!')

node入门

命令行参数:

1)

console.log('hello world!', process.argv[2])

node入门

2)

console.log('hello world!', process.argv[1])

node入门

三、commander.js

使用.option()方法定义commander的选项options

短标志可以作为单个arg传递,例如-abc相当于-a -b -c。

多词组成的选项,像“--template-engine”会变成 program.templateEngine 等

<>代表必填,[]代表选填,选填可以设置默认值

.version('0.0.1')  使用node app -V查版本

.version('0.0.1', '-v, --version')   使用node app -v或node app --version查版本

使用node app -h或node app --help查看帮助

program.parse方法用于解析process.argv,解析后可以program.xxx使用

const program = require('commander');
 
program
  .version('0.0.1')  //node app -V
  //.version('0.0.1', '-v, --version')   //node app -v
  .option('-d, --debug', 'output extra debugging')
  .option('-s, --small', 'small pizza size')
  .option('-p, --pizza-type <type>', 'flavour of pizza');
  
program.parse(process.argv);
 
if (program.debug) console.log(program.opts());
console.log('pizza details:');
if (program.small) console.log('- small pizza size');
if (program.pizzaType) console.log(`- ${program.pizzaType}`);

node入门

求和:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --my-a, <a>', '第一个值')
  .option('-b, --my-b, <b>', '第二个值')
  .parse(process.argv);

console.log(program.myA)
console.log(program.myB)
console.log(program.myA*1 + program.myB*1)

node入门

求和二:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --add', '求和')
  .parse(process.argv);
  
if (program.add) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
}

node入门

阶乘:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --add', '求和')
  .option('-f, --factorial <num>', '阶乘')
  .parse(process.argv);

const factorial = (num) => {
  if (num < 0) {
    return -1
  } else if (num === 0 || num === 1) {
    return 1
  } else {
    return num * factorial(num - 1)
  }
}

if (program.add) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
} else if (program.factorial) {
  let result = factorial(program.factorial)
  console.log(result)
}

node入门

node入门

多单词形式:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --my-add', '求和,多单词形式')
  .parse(process.argv);

//驼峰
if (program.myAdd) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
}


以--no形式开头的选项,代表后面紧跟单词的相反面:

const program = require('commander');
 
program
  .version('0.0.1')
  .option('-a, --no-add', '求和,以--no形式开头的选项,代表后面紧跟单词的相反面')
  .parse(process.argv);

console.log(program)  

if (program.add) {
  let sum = 0
  program.args.forEach(item => {
    sum += item * 1
  })
  console.log(sum)
} else {
  console.log('取反')
}

node入门

command方法,自定义命令

description方法, 命令的描述性语句

action方法,定义命令的回调函数

const program = require('commander');
program
  .version('1.0.0')
  .command('my-add <num>')
  .option('-a, --add, <num>', '加法')
	.action((num, cmd) => {
    console.log(num, cmd.add)
  })

program
  .option('-u, --upadte', '更新')  
  .description('描述信息!!!')
  
program.parse(process.argv)

node入门

参考链接:

https://juejin.im/post/5c8be466f265da2dc849af70

https://www.npmjs.com/package/commander#commands

四、npm包管理

发布npm包:

1.先注册一个npm账号

2.在终端登录npm账号:npm login 回车输入用户名密码和邮箱

3.新建一个文件夹,cd到新创建的文件夹,使用npm init 生成package.json

4.使用npm publish上传npm包,你会收到一封邮件,在npm官网可以看到刚上传的npm包

 

yarn更新包:

yarn upgrade

五、node提供一个链接可以下载图片

 

const fs = require('fs')
const request = require('request')
const program = require('commander')

program
  .option('-d, --down <url>', '下载')
  .parse(process.argv)
  
let url = program.down

const name = url.slice(url.lastIndexOf('/') + 1)
request(url).pipe(fs.createWriteStream('./' + name));

//node app -d https://n3-q.mafengwo.net/s15/M00/16/18/CoUBGV2xnO6ALntcAB_DZLkVUnY568.png
//node app -d https://p4-q.mafengwo.net/s15/M00/B3/B1/CoUBGV2wYYmAAByNACD9lHJSPKY794.png
//node app --down https://n2-q.mafengwo.net/s15/M00/D0/E4/CoUBGV2vBYGAbzADAB1W_rqrlCM012.png

六、使用node原生http模块写接口

跨域:

所以ajax跨域请求附带自定义响应头时,被请求服务器除了添加Access-Control-Allow-Origin响应头,还得注意注意添加Access-Control-Allow-Headers响应头为对应的自定义请求头的名称,多个自定义请求头用英文状态下逗号分开。

  //跨域
  res.setHeader('Access-Control-Allow-Origin', '*')  //可以把 * 改成 http://localhost:3000 避免xss攻击
  //res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS')   //放行的方法
  res.setHeader('Access-Control-Allow-Headers', 'content-type')  //放行的请求头
  res.setHeader('Access-Control-Max-Age', 1800)  //隔30分钟才发起预检请求,1800秒

url.parse:

url.parse('http://localhost:3000/api/list?id=0')  :

node入门

url.parse('http://localhost:3000/api/list?id=0', true)  :

node入门

204状态码:

请求收到,但返回信息为空。请求执行成功,但是没有数据,浏览器不用刷新页面.也不用导向新的页面。常用于跨域请求。

node入门

node入门

 跨域请求:

node入门

node入门

OPTIONS是一种“预检请求”,浏览器在处理跨域访问的请求时如果判断请求为复杂请求,则会先向服务器发送一条预检请求,根据服务器返回的内容浏览器判断服务器是否允许该请求访问。如果web服务器采用cors的方式支持跨域访问,在处理复杂请求时这个预检请求是不可避免的。 

跨域不可避免,预检请求也不可避免,那我们能做的,就是减少预检请求,处理办法就是设置跨域的有效期Access-Control-Max-Age,这样就只会跨域预检一次了。

浏览器的同源策略,就是出于安全考虑,浏览器会限制从脚本发起的跨域HTTP请求(比如异步请求GET, POST, PUT, DELETE, OPTIONS等等),所以浏览器会向所请求的服务器发起两次请求,第一次是浏览器使用OPTIONS方法发起一个预检请求,第二次才是真正的异步请求,第一次的预检请求获知服务器是否允许该跨域请求:如果允许,才发起第二次真实的请求;如果不允许,则拦截第二次请求。

Access-Control-Max-Age用来指定本次预检请求的有效期,单位为秒,,在此期间不用发出另一条预检请求。

例如:

res.setHeader('Access-Control-Max-Age', 1800) 表示隔30分钟才发起预检请求。也就是说,发送两次请求

 

七、使用node原生http模块实现购物车所有接口(不需要装包,不需要中间件)

const http = require('http')
const fs = require('fs')
const url = require('url')
const { bookNavData, bookMallData, userList } = require('./data')

let bookList = []

const server = http.createServer((req, res) => {
  //跨域
  res.setHeader('Access-Control-Allow-Origin', '*')  //可以把 * 改成 http://localhost:3000 避免xss攻击
  //res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS')   //放行的方法
  res.setHeader('Access-Control-Allow-Headers', 'content-type')  //放行的请求头
  res.setHeader('Access-Control-Max-Age', 1800)  //隔30分钟才发起预检请求,1800秒
  
  let { pathname } = url.parse(req.url, true)
  console.log(req.method, url.parse(req.url, true))
  console.log(pathname)

  if (req.url === '/') {   //hello world!
    res.writeHead(200, { 'Content-Type': 'text/html' })
    res.write('hello world!')
    res.end()
  } else if (req.url === '/home') {  //路由
    res.writeHead(200, { 'Content-Type': 'text/html' })
    const home = fs.readFileSync('./index.html')   //读文件
    res.end(home)
  } else if (req.url === '/banner01') {   //图片
    //res.writeHead(200, { 'Content-Type': 'image/jpg' })
    const banner01 = fs.readFileSync('./images/banner01.jpg')  //读图片
    res.end(banner01)
  } else if (req.method == 'OPTIONS') { //跨域,处理options请求
    res.writeHead(204) //204 无内容
    res.end()
  } else if (req.method === 'POST' && pathname === '/api/login') { //登录
    let body = ''

    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到body变量中
    req.on('data', (chunk) => {
      body += chunk
    })

    // 在end事件触发后,通过JSON.parse将body解析为真正的POST请求格式
    req.on('end', () =>{
      body = JSON.parse(body)
      let { username, password } = body
      let user = userList.find(item => item.username === username)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      if (user) {
        if (user.password === password) {
          res.write(JSON.stringify({
            code: 200,
            data: {
              username
            },
            message: '登录成功'
          }))
        } else {
          res.write(JSON.stringify({
            code: 400,
            message: '密码错误'
          }))
        }
      } else {
        res.write(JSON.stringify({
          code: 400,
          data: body,
          message: '用户不存在'
        }))
      }
      res.end()
    })
  } else if (pathname === '/api/nav') {  //导航
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookNavData,
      message: '导航'
    }))
  } else if (pathname === '/api/list') {  //列表
    let { id } = url.parse(req.url, true).query
    let list = bookMallData.find(item => item.id == id).list
    list.forEach(item => {
      if (bookList.findIndex(book => book.id === item.id) >= 0) {
        item.is_in_my_book = true
      } else {
        item.is_in_my_book = false
      }
    })
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: list,
      message: '列表'
    }))
  } else if (pathname === '/api/get_book_list') { //书包
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookList,
      message: '书包'
    }))
  } else if (pathname === '/api/add') {  //添加到书包
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })

    req.on('end', () => {
      body = JSON.parse(body)
      let { item } = body
      bookList.push(item)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '添加成功'
      }))
    })
  } else if (pathname === '/api/detail') {   //详情
    let { id } = url.parse(req.url, true).query
    let detail
    bookMallData.forEach(listItem => {
      listItem.list.forEach(book => {
        if (book.id == id) {
          detail = book
        }
      })
    })

    if (bookList.find(book => book.id === detail.id)) {
      detail.is_in_my_book = true
    } else {
      detail.is_in_my_book = false
    }
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: detail,
      message: '详情'
    }))
  } else if (pathname === '/api/delete') {  //删除
    let body = ''
    req.on('data', (chunk) => {
      body +=chunk
      console.log('chunk:', chunk)
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { ids } = body
      bookList = bookList.filter(item => !ids.find(id => id === item.id))
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '删除成功'
      }))
    })
  } else if (pathname === '/api/update') {
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { bookListNew } = body
      bookList = bookListNew
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '更新成功'
      }))
    })
  } else {   //404
    res.writeHead(404, { 'Content-Type': 'text/html' })
    res.end('404')
  }
})

server.listen(9999, () => {
  console.log(9999)
})

八、node原生写接口,搭建静态web服务器,处理前端history路由

参考链接:

https://www.npmjs.com/package/connect

https://www.npmjs.com/package/connect-history-api-fallback

项目上线啦:

http://39.97.238.175/index/home

const http = require('http')
const url = require('url')
const path = require('path')
const fs = require('fs')
const connect = require('connect')
const history = require('connect-history-api-fallback')
const { bookNavData, bookMallData, userList } = require('./data')

let bookList = []

//使原生http模块可以使用中间件功能
const app = connect()

//处理react前端路由(BrowserRoute),vue前端路由(mode:history)
app.use(history())

//跨域,静态web服务器
app.use((req, res, next) => {
  //跨域
  res.setHeader('Access-Control-Allow-Origin', '*')  //可以把 * 改成 http://localhost:3000 避免xss攻击
  //res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,PATCH,DELETE,HEAD,OPTIONS')   //放行的方法
  res.setHeader('Access-Control-Allow-Headers', 'content-type')  //放行的请求头
  res.setHeader('Access-Control-Max-Age', 1800)  //隔30分钟才发起预检请求,1800秒

  let { pathname } = url.parse(req.url, true)
  let extName = path.extname(pathname)
  console.log(pathname, extName)
  if (pathname === '/') {
    pathname = '/index.html'
  }
  if  (pathname.indexOf('/api') >= 0) {
    next()
  } else {
    fs.readFile(`./public/${pathname}`, (err, data) => {
      if (err) {
        res.writeHead(404, {'Content-Type': 'text/html' })
        res.end('404')
      } else {
        if (extName === '.css') {
          res.writeHead(200, {'Content-Type': 'text/css'})
        }
        res.end(data)
      }
    })
  }
})

//接口
app.use((req, res) => {
  let { pathname } = url.parse(req.url, true)

  if (req.method == 'OPTIONS') { //跨域,处理options请求
    res.writeHead(204) //204 无内容
    res.end()
  } else if (req.method === 'POST' && pathname === '/api/login') { //登录
    let body = ''

    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到body变量中
    req.on('data', (chunk) => {
      body += chunk
    })

    // 在end事件触发后,通过JSON.parse将body解析为真正的POST请求格式
    req.on('end', () =>{
      body = JSON.parse(body)
      let { username, password } = body
      let user = userList.find(item => item.username === username)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      if (user) {
        if (user.password === password) {
          res.write(JSON.stringify({
            code: 200,
            data: {
              username
            },
            message: '登录成功'
          }))
        } else {
          res.write(JSON.stringify({
            code: 400,
            message: '密码错误'
          }))
        }
      } else {
        res.write(JSON.stringify({
          code: 400,
          data: body,
          message: '用户不存在'
        }))
      }
      res.end()
    })
  } else if (pathname === '/api/nav') {  //导航
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookNavData,
      message: '导航'
    }))
  } else if (pathname === '/api/list') {  //列表
    let { id } = url.parse(req.url, true).query
    let list = bookMallData.find(item => item.id == id).list
    list.forEach(item => {
      if (bookList.findIndex(book => book.id === item.id) >= 0) {
        item.is_in_my_book = true
      } else {
        item.is_in_my_book = false
      }
    })
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: list,
      message: '列表'
    }))
  } else if (pathname === '/api/get_book_list') { //书包
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: bookList,
      message: '书包'
    }))
  } else if (pathname === '/api/add') {  //添加到书包
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })

    req.on('end', () => {
      body = JSON.parse(body)
      let { item } = body
      bookList.push(item)
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '添加成功'
      }))
    })
  } else if (pathname === '/api/detail') {  //详情
    let { id } = url.parse(req.url, true).query
    let detail
    bookMallData.forEach(listItem => {
      listItem.list.forEach(book => {
        if (book.id == id) {
          detail = book
        }
      })
    })

    if (bookList.find(book => book.id === detail.id)) {
      detail.is_in_my_book = true
    } else {
      detail.is_in_my_book = false
    }
    res.writeHead(200, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({
      code: 200,
      data: detail,
      message: '详情'
    }))
  } else if (pathname === '/api/delete') {  //删除
    let body = ''
    req.on('data', (chunk) => {
      body +=chunk
      console.log('chunk:', chunk)
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { ids } = body
      bookList = bookList.filter(item => !ids.find(id => id === item.id))
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '删除成功'
      }))
    })
  } else if (pathname === '/api/update') {  //更新
    let body = ''
    req.on('data', (chunk) => {
      body += chunk
    })
    req.on('end', () => {
      body = JSON.parse(body)
      let { bookListNew } = body
      bookList = bookListNew
      res.writeHead(200, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({
        code: 200,
        data: bookList,
        message: '更新成功'
      }))
    })
  } else {   //404
    res.writeHead(404, { 'Content-Type': 'text/html' })
    res.end('404')
  }
})

const server = http.createServer(app)

server.listen(9998)
console.log(9998)

九、安装FileZilla服务端

下载filezilla客户端和服务端:

https://filezilla-project.org/

安装server端:

node入门

 

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

十、安装FileZilla客户端

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

十一、阿里云配置支持FTP

node入门

node入门

node入门

node入门

node入门

十二、colors

装包:

yarn add colors

node代码:

const color = require('colors')

console.log('hello world!'.green)
console.log('hello world!'.underline.red)
console.log('hello world!'.inverse)
console.log('hello world!'.rainbow)

效果:

node入门

十三、express脚手架

装包:

yarn global add express-generator

运行:

express --view=pug m-express-demo

cd m-express-demo

yarn

yarn start

node入门

十三、npm view指令

显示npm包的相关信息:

npm view axios

npm show axios

npm info axios

npm v axios

node入门

查询npm包的所有版本号:

npm view axios versions

node入门

查询npm包的所有版本号和所有依赖:

npm view axios versions dependencies

node入门

十四、String

    let a = 'hello'
    let b = 'hello'
    let c = new String('hello')

    console.log(a === b)  //true
    console.log(a === c)  //false
    console.log(typeof a) //string
    console.log(typeof c) //object
    console.log(a instanceof String) //false
    console.log(c instanceof String) //true

十五、node是单线程

    let start = Date.now()
    console.log(start)
    setTimeout(() => {
      console.log(Date.now() - start)  //1000左右
      for (let i = 0; i < 5000000000; i++) {
        
      }
    }, 1000)
    setTimeout(() => {
      console.log(Date.now() - start)  //大于2000,具体大多少,取决于上面for循序的次数
    }, 2000)

node入门

 

十六、错误处理

错误堆栈:

test.js:

const a = () => {
  console.log(obj.name)
}

const b = () => {
  a()
}

b()

node入门

在异步函数中,堆栈信息将丢失:

const a = () => {
  setTimeout(() => {
    console.log(obj.name)
  }, 10)
}

const b = () => {
  a()
}

b()

node入门

uncaughtException捕获异常(丢失了错误发生位置的上下文):

process.on('uncaughtException', (error) => {
  console.error("xu:", error)
})

const a = () => {
  console.log(obj.name)
}

const b = () => {
  a()
}

b()

node入门

domain模块:

当res是上下文时,可以把错误信息返回给前端!

参考链接:https://www.runoob.com/nodejs/nodejs-domain-module.html

const domain = require('domain')

const d = domain.create()

let name = 'tom'


d.on('error', (error) => {
  console.log('上下文环境:', name)
  console.log('domain捕获到的异常信息:', error.stack)
})

d.run(() => {
  console.log(obj.name)
})

node入门

十七、process.nextTick(callback)

在事件循环的下一次循环中调用 callback 回调函数。

console.log(1)

process.nextTick(() => {
  console.log(2)
})

console.log(3)

node入门

十八、根据下标打印动物

const program = require('commander')
const fs = require('fs')
const packageInfo = require('./package.json')

program.version(packageInfo.version)
  .option('-i, --index <type>', "下标")

program.parse(process.argv)

console.log(program.index)

fs.readFile('./animals.txt', 'utf-8', (err, data) => {
  if (err) {
    return
  }
  let animalsArr = data.split('===============++++SEPERATOR++++====================')
  console.log(animalsArr[program.index])
})

node入门

动物数据:

链接:https://pan.baidu.com/s/1C3LKzQtdVifCAap7Nr9gAQ
提取码:g1sv

十九、node通过网页读取文件目录

const program = require('commander')
const fs = require('fs')
const http = require('http')
const { exec } = require('child_process')
const path = require('path')
const packageInfo = require('./package.json')

program.version(packageInfo.version)
  .option('-p, --port <port>', "set port")

program.parse(process.argv)

let PORT = program.port || 8000

const app = http.createServer((req, res) => {
  let rootPath = process.cwd()
  if (req.url === '/favicon.ico') {
    res.end()
    return
  }
  let myPath = path.join(rootPath, req.url)
  console.log('a', myPath)
  if (fs.statSync(myPath).isFile()) {
    fs.readFile(myPath, 'utf8', (err, data) => {
      res.end(data)
    })
  } else {
    let list = fs.readdirSync(myPath).map(filePath => {
      return `<div>
      <a href="${path.join(req.url, filePath)}">${filePath}</a>
      </div>`
    }).join('')
    let html = fs.readFileSync(__dirname + '/public/index.html', 'utf8')
    html = html.replace("{{list}}", list)
    res.end(html)
  }
})

app.listen(PORT, () => {
  //exec(`start http://localhost:${PORT}`)
})

node入门

node入门

20、重命名文件或文件夹

const fs = require('fs')
const path = require('path')

let target = process.argv[2]
let rename = process.argv[3]
let rootPath = process.cwd()

target = path.join(rootPath, target)
if (fs.existsSync(target)) {
  fs.renameSync(target, path.join(rootPath, rename))
} else {
  console.log('文件或文件夹不存在')
}

21、js区分对象函数和数组

const fs = require('fs')
const path = require('path')

let obj = {}

console.log(obj instanceof Object)  //true
console.log(typeof obj)  //object
console.log(Object.prototype.toString.call(obj))  //[object Object]

let fun = () => {}

console.log(fun instanceof Function)  //true
console.log(fun instanceof Object)  //true
console.log(typeof fun)   //function
console.log(Object.prototype.toString.call(fun))  //[object Function]

let arr = []

console.log(arr instanceof Array)  //true
console.log(arr instanceof Object)  //true
console.log(typeof arr)   //object

console.log(Object.prototype.toString.call(arr))  //[object Array]

node入门

22、事件触发器

const EventEmitter = require('events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()

myEmitter.on('myEventName', (a, b) => {
  console.log(a, b)
})

myEmitter.emit('myEventName', 1, 2)
myEmitter.emit('myEventName', 1, 2)

myEmitter.once('myOnce', () => {
  console.log('只触发一次')
})

myEmitter.emit('myOnce')
myEmitter.emit('myOnce')

myEmitter.on('error', (err) => {
  console.error(err)
})

myEmitter.emit('error', new Error('错误'))

node入门

23、手动封装事件

class MyEmitter {
  constructor() {
    this.events = {}
  }
  on(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName].push(callback)
    } else {
      this.events[eventName] = [callback]
    }
  }

  emit(eventName, ...arg) {
    let callbackArr = this.events[eventName]
    callbackArr && callbackArr.forEach(item => {
      if (Object.prototype.toString.call(item) === '[object Function]') {
        item(...arg)
      } else if (Object.prototype.toString.call(item) === '[object Object]') {
        if (item.once) {
          item.callback(...arg)
          item.callback = () => {}
        }
      }
    })
  }

  once(eventName, callback) {
    if (this.events[eventName]) {
      this.events[eventName].push({
        once: true,
        callback
      })
    } else {
      this.events[eventName] = [{
        once: true,
        callback
      }]
    }
  }
}
const myEmitter = new MyEmitter()

module.exports = myEmitter

24、父子进程通信

app.js:

const child_process = require('child_process')

const child = child_process.fork('./compute.js')

child.send({ type: 'start' })
child.on('message', (action) => {
  if (action.type === 'sum') {
    console.log('子进程计算出来的结果:', action.sum)
    process.exit()
    
  }
})

process.on('exit', () => {
  console.log('主进程结束')
})

console.log('运行到这里')

compute.js:


const computeSum = () => {
  let sum = 0
  for (let i = 0; i < 1000000; i++) {
    sum += i
  }
  return sum
}

process.on('message', (action) => {
  if (action.type === 'start') {
    let sum = computeSum()
    process.send({
      type: 'sum',
      sum
    })
  }
})

node入门

25、docker

docker:码头工人

doctor:医生

docker toolbox下载链接:https://github.com/docker/toolbox/releases

docker toolbox 国内下载地址:http://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/

docker官网:https://www.docker.com/

docker hub官网:https://hub.docker.com/

docker菜鸟教程:https://www.runoob.com/docker/docker-tutorial.html

安装:

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

node入门

 

 

node入门

 

 

下载最新版的 boot2docker.iso 放在本地缓存文件夹里,否则启动时会联网下载最新版的,切很难下载下来,会报错

可以去百度云盘下载:

链接:https://pan.baidu.com/s/1Y9bLSSvyNdyK_dYvVzKW8w
提取码:esp0
node入门

hello world:

docker run ubuntu:15.10 /bin/echo "hello world"

node入门

 

运行交互式的容器:

docker run -i -t ubuntu:15.10 /bin/bash

node入门

ctrl + D 或者 exit 退出

 

docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello; sleep 5;done"

docker ps

docker logs determined_meitner

node入门

node入门

进入容器:

docker attach determined_meitner

26、koa-compose

https://github.com/koajs/compose

 

 

 

 

 

 

相关文章:

  • 2021-06-12
  • 2021-11-24
  • 2021-06-28
  • 2021-10-03
  • 2021-07-08
  • 2022-12-23
  • 2022-12-23
  • 2022-01-06
猜你喜欢
  • 2021-10-18
  • 2022-01-05
  • 2021-09-13
相关资源
相似解决方案