Nodejs的解读(三)

nodejs的异步编程

用回调处理一次性事件

 a.json,我们要读取的文件内容

[
  "标题一",
  "标题二",
  "标题三"
]

template.html模板文件

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Latest posts</title>
</head>

<body>
  <ul>
    <li>%</li>
  </ul>
</body>

</html>

app.js

const http = require('http');
const fs = require('fs');

var server = http.createServer((req, res) => {
  console.log(req.url)
  if (req.url == '/') {
    fs.readFile('./a.json', (err, data) => {
      if (err) {
        console.log(err)
      }
      else {
        const titles = JSON.parse(data.toString());
        console.log(titles)
        fs.readFile('./template.html', (err, data) => {
          if (err) {
            console.log(err)
          }
          else {
            const tmpl = data.toString();
            const html = tmpl.replace('%', titles.join('</li><li>'));
            res.writeHead(200, { 'Content-Type': 'text/html;charset=UTF8' });
            res.end(html)
          }
        })
      }
    })

  }
})

server.listen(3030, () => {
  console.log('服务器启动了。。。')
})

使用nodejs的fs模块读取文件时习惯用相对路径,但是运行的时候出现了上述的错误,原因就是fs模块读取文件的相对路径是以启动server.js的位置为基准的,而不是以server.js文件的位置。

 问题一:

{ Error: ENOENT: no such file or directory, open './a.json' errno: -2, code: 'ENOENT', syscall: 'open', path: './a.json' }

 原因就是没有进入到该文件目录,启动服务器app.js,所以必须进入到服务器文件所在的目录进行启动,否则就要使用绝对路径读取文件

 问题二:

嵌套了三层回调

http.createServer((req, res) => {...

   fs.readFile('./a.json', (err, data) => {...

     fs.readFile('./template.html', (err, data) => {

 优化方法一:把回调函数用命名函数替换

const http = require('http');
const fs = require('fs');

var server = http.createServer((req, res) => {
  getTitles(req, res);
})


function getTitles (req, res) {
  if (req.url == '/') {
    fs.readFile('./a.json', (err, data) => {
      if (err) {
        hasErr(err, res)
      }
      else {
        getTemplate(data, res)
      }
    })

  }
}
function getTemplate (data, res) {
  const titles = JSON.parse(data.toString());
  console.log(titles)
  fs.readFile('./template.html', (err, data) => {
    if (err) {
      hasErr(err, res)
    }
    else {
      formatHtml(data, titles, res)
    }
  })
}

function formatHtml (data, titles, res) {
  const tmpl = data.toString();
  const html = tmpl.replace('%', titles.join('</li><li>'));
  res.writeHead(200, { 'Content-Type': 'text/html;charset=UTF8' });
  res.end(html)
}

function hasErr (err, res) {
  console.log(err);
  res.end("Server error")
}

server.listen(3030, () => {
  console.log('服务器启动了...')
})

最后的结果是:

优化方法二:

const http = require('http');
const fs = require('fs');

var server = http.createServer((req, res) => {
  getTitles(req, res);
})


function getTitles (req, res) {
  if (req.url == '/') {
    fs.readFile('./a.json', (err, data) => {
      if (err) return hasErr(err, res)   //如果发生错误,直接返回,后面就没必要执行了
      getTemplate(data, res)
    })

  }
}
function getTemplate (data, res) {
  const titles = JSON.parse(data.toString());
  console.log(titles)
  fs.readFile('./template.html', (err, data) => {
    if (err) return hasErr(err, res)  //如果发生错误,直接返回,后面就没必要执行了
    formatHtml(data, titles, res)
  })
}

function formatHtml (data, titles, res) {
  const tmpl = data.toString();
  const html = tmpl.replace('%', titles.join('</li><li>'));
  res.writeHead(200, { 'Content-Type': 'text/html;charset=UTF8' });
  res.end(html)
}

function hasErr (err, res) {
  console.log(err);
  res.end("Server error")
}

server.listen(3030, () => {
  console.log('服务器启动了...')
})


 事件发射器处理重复事件

事件是通过监听处理的,监听器是跟事件相关的,当有事件出现时就被触发的回调函数。TCP socket的data事件,每当socket有新数据时就会被触发

socket.on('data',callback)

const net = require('net');
const server = net.createServer(socket => {
  socket.on('data', data => {
    socket.write(data)
  })
})
server.listen(8000, () => {
  console.log('started')
})

 响应只应该发生一次的事件

const net = require('net');
const server = net.createServer(socket => {
  socket.once('data', data => {
    socket.write(data)
  })
})
server.listen(8000, () => {
  console.log('started')
})

事件发射器,PUB/SUB

const EventEmitter = require('events').EventEmitter;
const channel = new EventEmitter();

channel.on('join', () => {
  console.log('welcome')
})
channel.emit('join')  //welcome
channel.emit('join')  //welcome
channel.emit('join')  //welcome

异步逻辑的顺序 

function asyncFunc (cb) {
  setTimeout(cb, 200);
}
let color = 'blue'
asyncFunc(() => {
  console.log(`the color is ${color}`)  //the color is green
})
color = 'green'

 用闭包冻结了color,asyncFunc异步函数被封装在以color为参数的匿名函数里,让其立即调用,就可以把当前的color值blue传递给它,color成了匿名函数的参数,也就是内部的本地变量,当外部的变量发生变化时,不影响里面的color

function asyncFunc (cb) {
  setTimeout(cb, 200);
}
let color = "blue";

(color => {
  asyncFunc(() => {
    console.log('haha', color)  //blue
  })
})(color)

color = 'green'

异步逻辑的顺序化 

有些任务只能在某些特定的任务之前或之后做,让一组异步任务顺序执行的概念被叫做流程控制。分为串行和并行

串行执行 :  任务一 =》 任务二 =》 任务三 =》 继续下去。。。(跟同步逻辑类似)


                    || === 任务开始1    =》                               

并行执行:  || === 任务开始 2   =》    =========》 所有任务结束后继续

                    || === 任务开始 3   =》


用回调让任务顺序执行,setTimeout

setTimeout(() => {
  console.log('1111')
  setTimeout(() => {
    console.log('222')
    setTimeout(() => {
      console.log('333')
    }, 100)
  }, 500)
}, 1000)


nelsen-mac:cb_event mac$ node async.js
1111
222
333

 cnpm i async --save

const async = require('async');
async.series([
  callback => {
    setTimeout(() => {
      console.log('111');
      callback()
    }, 1000)
  },
  callback => {
    setTimeout(() => {
      console.log('222');
      callback()
    }, 100)
  },
  callback => {
    setTimeout(() => {
      console.log('333');
      callback()
    }, 10)
  }
])

nelsen-mac:cb_event mac$ node async.js
111
222
333

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值