node入门

目录

 

 

 

一、什么是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


 

通过keywords找:

repository:npm和git关联

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

homepage: 项目官网

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

 

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"
  }

参考链接:

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"
  },

全局安装:

 

常用命令:

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!')

命令行参数:

1)

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

2)

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

三、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}`);

求和:

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)

求和二:

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)
}

阶乘:

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)
}

多单词形式:

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('取反')
}

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)

参考链接:

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')  :

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

204状态码:

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

 跨域请求:

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端:

 

十、安装FileZilla客户端

十一、阿里云配置支持FTP

十二、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)

效果:

十三、express脚手架

装包:

yarn global add express-generator

运行:

express --view=pug m-express-demo

cd m-express-demo

yarn

yarn start

十三、npm view指令

显示npm包的相关信息:

npm view axios

npm show axios

npm info axios

npm v axios

查询npm包的所有版本号:

npm view axios versions

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

npm view axios versions dependencies

十四、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)

 

十六、错误处理

错误堆栈:

test.js:

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

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

b()

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

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

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

b()

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

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

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

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

b()

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)
})

十七、process.nextTick(callback)

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

console.log(1)

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

console.log(3)

十八、根据下标打印动物

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])
})

动物数据:

链接: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}`)
})

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]

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('错误'))

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
    })
  }
})

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

安装:

 

 

 

 

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

可以去百度云盘下载:

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

hello world:

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

 

运行交互式的容器:

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

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

进入容器:

docker attach determined_meitner

26、koa-compose

https://github.com/koajs/compose

 

 

 

 

 

 

posted @ 2019-10-23 19:58  徐同保  阅读(589)  评论(0编辑  收藏  举报