Node.js学习(express+node项目实战)

一. 什么是node.js?

  • JavaScript 运行时环境
  • 既不是语言,也不是框架,它是一个平台
  • node中的javascript没有BOM、DOM
  • 在 Node 中为 JavaScript 提供了一些服务器级别的 API
  • 文件操作的能力
  • http 服务的能力

二. node中的模块化开发

在node中每个js都是一个独立的文件,相互之间并不干扰,他们之前的通信是通过exports 向外暴露,然后在通过 require 引入。

事例

a.js

var bEpt = require('./b')

console.log(bEpt.fo) //会报错 因为 b.js中未暴露该变量
console.log(bEpt.foo)  //控制台会输出打印 hello

b.js

var fo = 'bbb'
exports.foo = 'hello' //exports 表示向外暴露

三. 文件的读取与写入

// 浏览器中的 JavaScript 是没有文件操作的能力的
// 但是 Node 中的 JavaScript 具有文件操作的能力

// 1. 使用 require 方法加载 fs 核心模块
var fs = require('fs')  //fs 是 file-system 的简写,就是文件系统的意思


//读取文件
//    第一个参数就是要读取的文件路径
//    第二个参数是一个回调函数
//          
//        成功
//          data 数据
//          error null
//        失败
//          data undefined没有数据
//          error 错误对象

fs.readFile('./data/a.txt', function (error, data) {
  // <Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a>
  // 文件中存储的其实都是二进制数据 0 1
  // 这里为什么看到的不是 0 和 1 呢?原因是二进制转为 16 进制了
  // 但是无论是二进制01还是16进制,人类都不认识
  // 所以我们可以通过 toString 方法把其转为我们能认识的字符

  // 在这里就可以通过判断 error 来确认是否有错误发生
  if (error) {
    console.log('读取文件失败了')
  } else {
    console.log(data.toString()) //data中的数据默认是二进制的<Buffer 68 65 6c 6c 6f 20 6e 6f 64 65 6a 73 0d 0a>   toString转成 utf8编码格式显示
  }
})
// 第一个参数:文件路径
// 第二个参数:文件内容
// 第三个参数:回调函数
//    error
//    
//    成功:
//      文件写入成功
//      error 是 null
//    失败:
//      文件写入失败
//      error 就是错误对象
//写入文件
fs.writeFile('./data/a.md', '大家好,给大家介绍一下,我是Node.js', function (error) {
  // console.log('文件写入成功')
  // console.log(error)
  if (error) {
    console.log('写入失败')
  } else {
    console.log('写入成功了')
  }
})

四. node中搭建服务器

// 1. 加载 http 核心模块
var http = require('http')

// 2. 使用 http.createServer() 方法创建一个 Web 服务器
//    返回一个 Server 实例
var server = http.createServer()
server.on('request', fuction(request, response){
    console.log('收到客户端的请求了,请求路径是:' + request.url)
    // response 对象有一个方法:write 可以用来给客户端发送响应数据
  // write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待
  response.write('hello')
  response.write(' nodejs')

  // 告诉客户端,我的话说完了,你可以呈递给用户了
  response.end()
})
//开启端口号
server.listen(3000, function () {
  console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})




//可以配置路由 通过判断请求过来的路径,响应相应的数据

var server = http.createServer()
server.on('request', fuction(request, response){
  var url = request.url
  if (url === '/') {
  // 如果你发送的是 html 格式的字符串,则也要告诉浏览器我给你发送是 text/html 格式的内容 // text/plain 就是普通文本
    res.setHeader('Content-Type', 'text/html; charset=utf-8')
    res.write('<p>hello html <a href="">点我</a></p>')
    res.end()
  } else if (url === '/login') {
    res.end('登录页')
  } else if (url === '/products') {
    var products = [{
        name: '苹果',
        price: 8888
      },
      {
        name: '牛奶',
        price: 5000
      },
      {
        name: '电视机',
        price: 1999
      }
    ]

    // 响应内容只能是二进制数据或者字符串
    //  数字
    //  对象
    //  数组
    //  布尔值
    res.end(JSON.stringify(products))
  } else {
    res.end('404')
  }
  
  response.end()
})
//开启端口号
server.listen(3000, function () {
  console.log('服务器启动成功了,可以通过 http://127.0.0.1:3000/ 来进行访问')
})


https://tool.oschina.net/ Content-Type可以查找有关资源对应的头部信息

其他核心模块

// 用来获取机器信息的
var os = require('os')

// 用来操作路径的
var path = require('path')

// 获取当前机器的 CPU 信息
console.log(os.cpus())

// memory 内存
console.log(os.totalmem())

// 获取一个路径中的扩展名部分
// extname extension name
console.log(path.extname('c:/a/b/c/d/hello.txt'))
读取文件目录
var fs = require('fs')

fs.readdir('D:/', function (err, files) {
  if (err) {
    return console.log('目录不存在')
  }
  console.log(files)
})

五. 模板引擎


//首先:npm install art-template  第三方模块
//    该命令在哪执行就会把包下载到哪里。默认会下载到 node_modules 目录中

//引入模块
var template = require('art-template')



var str = `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <p>姓名:{{ name }}</p>
  <p>年龄: {{ age }} </p>
  <h1>地址: {{ province }}</h1>
  <p>爱好:{{each hobbies}} {{ $value }} {{/each}}</p>
</body>
</html>
`

//使用 语法  template.render(字符串,对象)
var ret = template.render(str,{
    name:'小明',
    age:20,
    province:'长沙',
    hobbies:['唱歌','跑步','打篮球']

})
console.log(ret)

在浏览器中使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>在浏览器中使用art-template</title>
</head>
<body>
  <!-- 
    注意:在浏览器中需要引用 lib/template-web.js 文件

    强调:模板引擎不关心你的字符串内容,只关心自己能认识的模板标记语法,例如 {{}}
    {{}} 语法被称之为 mustache 语法
   -->
  <script src="node_modules/art-template/lib/template-web.js"></script>
  <script type="text/template" id="tpl">
  <p>姓名:{{ name }}</p>
  <p>年龄: {{ age }} </p>
  <h1>地址: {{ province }}</h1>
  <p>爱好:{{each hobbies}} {{ $value }} {{/each}}</p>
  </script>
  <script>
    var ret = template.render(str,{
    name:'小明',
    age:20,
    province:'长沙',
    hobbies:['唱歌','跑步','打篮球']

})

    console.log(ret)
  </script>
</body>
</html>

示例
编写留言板

app.js



var http = require('http') // 用于创建服务器的模块

var fs = require('fs') //用于操作文件模块

var template = require('art-template') //使用模板引擎 需要 npm install art-template


//引入url 模块
var url = require('url')



var comments = [
    {
      name: '张三',
      message: '今天天气不错!',
      dateTime: '2020-10-16'
    },
    {
      name: '张三2',
      message: '今天天气不错!',
      dateTime: '2020-10-16'
    },
    {
      name: '张三3',
      message: '今天天气不错!',
      dateTime: '2020-10-16'
    },
    {
      name: '张三4',
      message: '今天天气不错!',
      dateTime: '2020-10-16'
    },
    {
      name: '张三5',
      message: '今天天气不错!',
      dateTime: '2020-10-16'
    }
  ]


  //创建服务
http.createServer(function(req,res){

  // 使用 url.parse 方法将路径解析为一个方便操作的对象,第二个参数为 true 表示直接将查询字符串转为一个对象(通过 query 属性来访问)
  var parseObj = url.parse(req.url,true)

  //获取请求路径 配置路由 返回相应数据
  //parseObj.pathname 不包含?之后的内容
  if(parseObj.pathname==='/'){
    //读取首页并返回
    fs.readFile('./views/index.html',function(err,data){
        if(err){
            return res.end('404')
        }
        var datas= template.render(data.toString(),{comments:comments}) //使用模板引擎进行渲染
        res.end(datas)
    })
  } else if(parseObj.pathname==='/post'){
    //读取评论页并返回
    fs.readFile('./views/post.html',function(err,data){
        if(err){
            return res.end('404')
        }
        res.end(data)
    })
  } else if(parseObj.pathname == '/pinglun'){
    //点击了评论按钮
    // 我们已经使用 url 模块的 parse 方法把请求路径中的查询字符串给解析成一个对象了
    //获取到参数对象
    var comment = parseObj.query
    comment.dateTime = '2020-11-2 17:01:01'
    comments.unshift(comment) //把 comment对象 添加到数据源中

    //1. 状态码设置为 302 临时重定向
      //        statusCode
      //    2. 在响应头中通过 Location 告诉客户端往哪儿重定向
      //        setHeader
    res.statusCode = 302 //状态码 302 表示重定向
    res.setHeader('Location', '/') //跳转到首页
    res.end()
    
  } else if(parseObj.pathname.indexOf('/public/')===0){      //配置静态资源路径  如果以此文件为入口文件 相当于这个服务器的根目录 / 表示与此文件在同一级的目录
      //'.'+parseObj.pathname 会在程序根目录下的相对路径 这里因为我吧静态文件放在public下 public又与此程序入口文件在同级目录下 所以要加./
    fs.readFile('.'+parseObj.pathname,function(err,data){
          if(err){
              return res.end('404')
          }
          res.end(data)  
      })
  }
}).listen(3000,function(){
    console.log('running...')
})

首页: index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>留言本</title>
  <!-- 
    浏览器收到 HTML 响应内容之后,就要开始从上到下依次解析,
    当在解析的过程中,如果发现:
      link script img
    等带有 src 或者 href(link) 属性标签(具有外链的资源)的时候,浏览器会自动对这些资源发起新的请求。
   -->
   <!-- 
      注意:在服务端中,文件中的路径就不要去写相对路径了。
      因为这个时候所有的资源都是通过 url 标识来获取的
      我的服务器开放了 /public/ 目录
      所以这里的请求路径都写成:/public/xxx
      / 在这里就是 url 根路径的意思。
      浏览器在真正发请求的时候会最终把 http://127.0.0.1:3000 拼上

      不要再想文件路径了,把所有的路径都想象成 url 地址
    -->
  <link rel="stylesheet" href="/public/css/bootstrap.css">
</head>

<body>
  <div class="header container">
    <div class="page-header">
      <h1>Example page header <small>Subtext for header</small></h1>
      <a class="btn btn-success" href="/post">发表留言</a>
    </div>
  </div>
  <div class="comments container">
    <ul class="list-group">
      {{each comments}}
      <li class="list-group-item">{{ $value.name }}说:{{ $value.message }} <span class="pull-right">{{ $value.dateTime }}</span></li>
      {{/each}}
    </ul>
  </div>
</body>

</html>

评论页:post.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="/public/css/bootstrap.css">
</head>

<body>
  <div class="header container">
    <div class="page-header">
      <h1><a href="/">首页</a> <small>发表评论</small></h1>
    </div>
  </div>
  <div class="comments container">
    <form action="/pinglun" method="get">
      <div class="form-group">
        <label for="input_name">你的大名</label>
        <input type="text" class="form-control" required minlength="2" maxlength="10" id="input_name" name="name" placeholder="请写入你的姓名">
      </div>
      <div class="form-group">
        <label for="textarea_message">留言内容</label>
        <textarea class="form-control" name="message" id="textarea_message" cols="30" rows="10" required minlength="5" maxlength="20"></textarea>
      </div>
      <button type="submit" class="btn btn-default">发表</button>
    </form>
  </div>
</body>

</html>

404 界面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <h1>抱歉!  您访问的页面失联啦...</h1>
</body>
</html>

静态资源
我这里使用的是bootstrap.css的样式下载地址如下
http://getbootstrap.com

六. Express(第三方 Web 开发框架)

模块系统

  • 核心模块
  • 第三方模块
  • 自己写的模块
  • 加载规则以及加载机制
  • 循环加载

导出多个成员 必须在对象中

exports.fo="hello"
exports.foo="hellos"

导出单个成员 得到的就是字符串函数

module.exports="aaa"
//后者会覆盖前者
module.exports=fuction(a,b){
return a+b
}

也可以用 module.exports导出多个成员

module.exports = {
  fo:"hello",
  fuc:function(a+b){ return a+b }
}

在 Node 中,每个模块内部都有一个自己的 module 对象该 module 对象中,有一个成员叫:exports 也是一个对象也就是说如果你需要对外导出成员,只需要把导出的成员挂载到 module.exports 中
console.log(exports === module.exports) //true

优先从缓存加载

a加载b,在b中加载c,a又加载c
由于 在 b 中已经加载过 c了,所以a不会重复加载,可以拿到其中的接口对象,但是不会重复执行里面的代码,这样做的目的是为了避免重复加载,提高模块加载效率

npm

npm init

  • npm init -y 可以跳过向导,快速生成 package.json 依赖信息文件

npm install

  • 一次性把dependencies选项中的依赖项全部安装

npm install 包名

  • 只下载到node_modules

npm install --save 包名

  • 下载并保存依赖信息(package.json中的dependencies中)

npm uninstall 包名

  • 只删除,依赖信息还在

npm uninstall 包名 --save

  • 删除包的同时删除依赖信息

npm install 包名 --global 表示全局安装 任意目录下都可执行此命令

Express

  • 第三方 Web 开发框架
  • 高度封装了 http 模块
  • 更加专注于业务,而非底层细节
    安装
npm init -y //生成一个package.json
npm i expree // 默认会保存依赖信息到package.json中

重写上面的事例 留言功能

// 1. 引包
var express = require('express')

// 2. 创建你服务器应用程序
//    也就是原来的 http.createServer
var app = express()

// 当以 /public/ 开头的时候,去 ./public/ 目录中找找对应的资源
// 这种方式更容易辨识,推荐这种方式
// app.use('/public/', express.static('./public/'))

// 必须是 /abc/d/puiblic目录中的资源具体路径
// app.use('/abc/d/', express.static('./public/'))

// 当省略第一个参数的时候,则可以通过 省略 /public 的方式来访问
// 这种方式的好处就是可以省略 /public/
         //app.use(express.static('./public/'))

         
app.use('/public/', express.static('./public/'))



// 配置使用 art-template 模板引擎
// 第一个参数,表示,当渲染以 .art 结尾的文件的时候,使用 art-template 模板引擎
// express-art-template 是专门用来在 Express 中把 art-template 整合到 Express 中
// 虽然外面这里不需要记载 art-template 但是也必须安装
// 原因就在于 express-art-template 依赖了 art-template
app.engine('html', require('express-art-template'))




// body-parser 专门用来解析表单post提交
const bodyParser = require('body-parser')
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())

var comments = [
    {
        name: '张三',
        message: '今天天气不错!',
        dateTime: '2015-10-16'
    },
    {
        name: '张三2',
        message: '今天天气不错!',
        dateTime: '2015-10-16'
    },
    {
        name: '张三3',
        message: '今天天气不错!',
        dateTime: '2015-10-16'
    },
    {
        name: '张三4',
        message: '今天天气不错!',
        dateTime: '2015-10-16'
    },
    {
        name: '张三5',
        message: '今天天气不错!',
        dateTime: '2015-10-16'
    }
]

//当以get请求时 执行处理回调函数  app.get 相当于增加了一个路由
app.get('/', function (req, res) {

    // Express 为 Response 相应对象提供了一个方法:render
    // render 方法默认是不可以使用,但是如果配置了模板引擎就可以使用了
    // res.render('html模板名', {模板数据})
    // 第一个参数不能写路径,默认会去项目中的 views 目录查找该模板文件
    // 也就是说 Express 有一个约定:开发人员把所有的视图文件都放到 views 目录中
    res.render('index.html', { comments: comments })
})

app.get('/post', function (req, res) {
    res.render('post.html')
})
//  app.get('/pinglun',function(req,res){
//     var comment = req.query                 //get 请求通过.query获取参数  只能拿 get 请求参数
//     comment.dateTime = '2017-11-2 17:11:22'
//     comments.unshift(comment)
//     res.redirect('/')
//  })
app.post('/pinglun', function (req, res) {
    var comment = req.body //post 取值 .body
    console.log(comment)
    comment.dateTime = '2020-11-2 17:11:22'
    comments.unshift(comment)
    res.redirect('/') //重定向到首页
})


//开启端口
app.listen(3000, function () {
    console.log('running...')
})


Express 封装路由

实例


//创建服务
var express = require('express')
//引入封装的路由
var router = require('./router')
//解析post请求  npm i body-parser
var bodyParser = require('body-parser')

var app = express()

//处理静态资源路径
app.use('/node_modules/', express.static('./node_modules/'))
app.use('/public/', express.static('./public/'))

//express使用模板引擎
app.engine('html', require('express-art-template'))

// 配置模板引擎和 body-parser 一定要在 app.use(router) 挂载路由之前
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())

// 把路由容器挂载到 app 服务中
app.use(router)

app.listen(3000, function () {
  console.log('running 3000...')
})

module.exports = app

router.js

//处理路由
 //  根据不同的请求方法+请求路径设置具体的请求处理函数
var fs = require('fs')
var Student = require('./student')

// Express 提供了一种更好的方式
// 专门用来包装路由的
var express = require('express')

// 1. 创建一个路由容器
var router = express.Router()

// 2. 把路由都挂载到 router 路由容器中

/*
 * 渲染学生列表页面
 */
router.get('/students', function (req, res) {
  Student.find(function (err, students) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.render('index.html', {
      fruits: [
        '苹果',
        '香蕉',
        '橘子'
      ],
      students: students
    })
  })
})

/*
 * 渲染添加学生页面
 */
router.get('/students/new', function (req, res) {
  res.render('new.html')
})

/*
 * 处理添加学生
 */
router.post('/students/new', function (req, res) {
  // 1. 获取表单数据
  // 2. 处理
  //    将数据保存到 db.json 文件中用以持久化
  // 3. 发送响应
  Student.save(req.body, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })  
})

/*
 * 渲染编辑学生页面
 */
router.get('/students/edit', function (req, res) {
  // 1. 在客户端的列表页中处理链接问题(需要有 id 参数)
  // 2. 获取要编辑的学生 id
  // 
  // 3. 渲染编辑页面
  //    根据 id 把学生信息查出来
  //    使用模板引擎渲染页面

  Student.findById(parseInt(req.query.id), function (err, student) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.render('edit.html', {
      student: student
    })
  })
})

/*
 * 处理编辑学生
 */
router.post('/students/edit', function (req, res) {
  // 1. 获取表单数据
  //    req.body
  // 2. 更新
  //    Student.updateById()
  // 3. 发送响应
  Student.updateById(req.body, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

/*
 * 处理删除学生
 */
router.get('/students/delete', function (req, res) {
  // 1. 获取要删除的 id
  // 2. 根据 id 执行删除操作
  // 3. 根据操作结果发送响应数据

  Student.deleteById(req.query.id, function (err) {
    if (err) {
      return res.status(500).send('Server error.')
    }
    res.redirect('/students')
  })
})

// 3. 把 router 导出
module.exports = router

student.js

var fs = require('fs')

var dbPath = './db.json'

/**
 * 获取学生列表
 * @param  {Function} callback 回调函数
 */
exports.find = function (callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    callback(null, JSON.parse(data).students)
  })
}

/**
 * 根据 id 获取学生信息对象
 * @param  {Number}   id       学生 id
 * @param  {Function} callback 回调函数
 */
exports.findById = function (id, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students
    var ret = students.find(function (item) {
      return item.id === parseInt(id)
    })
    callback(null, ret)
  })
}

/**
 * 添加保存学生
 * @param  {Object}   student  学生对象
 * @param  {Function} callback 回调函数
 */
exports.save = function (student, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // 添加 id ,唯一不重复
    student.id = students[students.length - 1].id + 1

    // 把用户传递的对象保存到数组中
    students.push(student)

    // 把对象数据转换为字符串
    var fileData = JSON.stringify({
      students: students
    })

    // 把字符串保存到文件中
    fs.writeFile(dbPath, fileData, function (err) {
      if (err) {
        // 错误就是把错误对象传递给它
        return callback(err)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

/**
 * 更新学生
 */
exports.updateById = function (student, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // 注意:这里记得把 id 统一转换为数字类型
    student.id = parseInt(student.id)

    // 你要修改谁,就需要把谁找出来
    // EcmaScript 6 中的一个数组方法:find
    // 需要接收一个函数作为参数
    // 当某个遍历项符合 item.id === student.id 条件的时候,find 会终止遍历,同时返回遍历项
    var stu = students.find(function (item) {
      return item.id === student.id
    })

    // 这种方式你就写死了,有 100 个难道就写 100 次吗?
    // stu.name = student.name
    // stu.age = student.age

    // 遍历拷贝对象
    for (var key in student) {
      stu[key] = student[key]
    }

    // 把对象数据转换为字符串
    var fileData = JSON.stringify({
      students: students
    })

    // 把字符串保存到文件中
    fs.writeFile(dbPath, fileData, function (err) {
      if (err) {
        // 错误就是把错误对象传递给它
        return callback(err)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

/**
 * 删除学生
 */
exports.deleteById = function (id, callback) {
  fs.readFile(dbPath, 'utf8', function (err, data) {
    if (err) {
      return callback(err)
    }
    var students = JSON.parse(data).students

    // findIndex 方法专门用来根据条件查找元素的下标
    var deleteId = students.findIndex(function (item) {
      return item.id === parseInt(id)
    })

    // 根据下标从数组中删除对应的学生对象
    students.splice(deleteId, 1)

    // 把对象数据转换为字符串
    var fileData = JSON.stringify({
      students: students
    })

    // 把字符串保存到文件中
    fs.writeFile(dbPath, fileData, function (err) {
      if (err) {
        // 错误就是把错误对象传递给它
        return callback(err)
      }
      // 成功就没错,所以错误对象是 null
      callback(null)
    })
  })
}

在这里插入图片描述

packge-lock.json

npm 5 以后才加入这个文件
当你npm install的时候会自动生成packge-lock.json
这个文件会保存node_modules中所有的信息(版本、下载地址)这样npm install 的时候速速就可以提升

lock 称为锁
所以此文件还可以用来锁定版本 防止自动升级

promise

ECMAscript 6 原生提供了 Promise 对象。

Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。
1、对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:

  • pending: 初始状态,不是成功或失败状态。
  • fulfilled: 意味着操作成功完成。
  • rejected: 意味着操作失败。
    在这里插入图片描述
var promise = new Promise(function(resolve, reject) {
    // 异步处理
    // 处理结束后、调用resolve 或 reject
});

实例

var fs = require('fs')

var p1 = new Promise(function (resolve, reject) {
  //读取文件 异步操作
  fs.readFile('./data/a.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p2 = new Promise(function (resolve, reject) {
  fs.readFile('./data/b.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

var p3 = new Promise(function (resolve, reject) {
  fs.readFile('./data/c.txt', 'utf8', function (err, data) {
    if (err) {
      reject(err)
    } else {
      resolve(data)
    }
  })
})

p1
  .then(function (data) {
    console.log(data)
    return p2
  }, function (err) {
    console.log('读取文件失败了', err)
  })
  .then(function (data) {
    console.log(data)
    return p3
  })
  .then(function (data) {
    console.log(data)
    console.log('end')
  })

在这里插入图片描述

在这里插入图片描述
封装promise

var fs = require('fs')

function pReadFile(filePath) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filePath, 'utf8', function (err, data) {
      if (err) {
        reject(err)
      } else {
        resolve(data)
      }
    })
  })
}

pReadFile('./data/a.txt')
  .then(function (data) {
    console.log(data)
    return pReadFile('./data/b.txt')
  })
  .then(function (data) {
    console.log(data)
    return pReadFile('./data/c.txt')
  })
  .then(function (data) {
    console.log(data)
  })

node中的模块

在每个模块中除了require、exports等相关api模块外,还有两个特殊成员

  • __dirname 可以用来获取文件的所属目录
  • __filename 可以用来获取文件的绝对路径

path 模块

参考文档:https://nodejs.org/docs/latest-v13.x/api/path.html

path.basename:获取路径的文件名,默认包含扩展名
path.dirname:获取路径中的目录部分
path.extname:获取一个路径中的扩展名部分
path.parse:把路径转换为对象
root:根路径
dir:目录
base:包含后缀名的文件名
ext:后缀名
name:不包含后缀名的文件名
path.join:拼接路径
path.isAbsolute:判断一个路径是否为绝对路径

var fs = require('fs')
var path = require('path')


// 模块中的路径标识和文件操作中的相对路径标识不一致
// 模块中的路径标识就是相对于当前文件模块,不受执行 node 命令所处路径影响
require('./b')

// ./a.txt 相对于当前文件路径
// ./a.txt 相对于执行 node 命令所处的终端路径
// 这不是错误,Node 就是这样设计的
// 就是说,文件操作路径中,相对路径设计的就是相对于执行 node 命令所处的路径
// fs.readFile('C:/Users/lpz/Desktop/nodejs/06/code/foo/a.txt', 'utf8', function (err, data) {
//   if (err) {
//     throw err
//   }
//   console.log(data)
// })

// console.log(__dirname + '/a.txt')

// C:\Users\lpz\Desktop\nodejs\06\code
fs.readFile(path.join(__dirname, './a.txt'), 'utf8', function (err, data) {
  if (err) {
    throw err
  }
  console.log(data)
})

art-template模板继承和子模板

header.html

<div>
  <h1>公共的头部</h1>
</div>

footer.html

<div>
  <h1>公共的底部</h1>
</div>

layout.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css">
  {{ block 'head' }}{{ /block }} <!--相当于一个插槽里面填什么东西由子组件决定-->
</head>
<body>
  {{ include './header.html' }} <!--引入公共头部-->
  
  <!--相当于一个插槽里面填什么东西由子组件决定-->
  {{ block 'content' }}
    <h1>默认内容</h1>
  {{ /block }}

  {{ include './footer.html' }} <!--引入公共的底部-->
  <script src="/node_modules/jquery/dist/jquery.js"></script>
  <script src="/node_modules/bootstrap/dist/js/bootstrap.js"></script>
  {{ block 'script' }}{{ /block }}
</body>
</html>

content.html

{{extend './layout.html'}}  <!--继承父组件的所有东西-->

<!--根据父组件定义插槽的位置来填写属于自己的内容-->
{{ block 'content' }}
<div>
  <h1>列表页自己的内容</h1>
</div>
{{ /block }}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值