• 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

  • 相关阅读:
    HDOJ 4248 A Famous Stone Collector DP
    Android开发系列(十九个):至SimpleAdapter设置样式
    matlab入门 蜂窝阵列
    OpenGL缓冲区
    如何在终端编辑命令
    struts2跳转类型解析
    设计模式(Facade)状态(注意事项)
    Swift与Objective-C API的交互
    Swift调用Objective C的FrameWork
    初探swift语言的学习—Object-C与Swift混编
  • 原文地址:https://www.cnblogs.com/xutongbao/p/11915669.html
Copyright © 2020-2023  润新知