写在前面
作者最近遇到了一个有趣的问题,我们都知道文件读取有两种类型
fs.readFileSync(); //同步读取
fs.readFile(); //异步读取
而Promise 是异步编程的一种解决方案, 那么我们能否封装一个Promise版本的 readFile呢?
引子
我们来看看阮一峰老师关于javascript是单线程的解释
链接:www.ruanyifeng.com/blog/2014/1…
JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事,在发出一个调用时,必须等待上一个任务执行完才能执行下一个任务,这种执行模式叫做同步。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。于是,所有任务可以分成两种,一种是同步任务,另一种是异步任务。
什么是同步编程?
所谓同步编程,就是计算机按顺序一行一行依次执行代码,当前代码任务耗时执行会阻塞后续代码的执行。
什么是异步编程?
所谓异步编程,就是在调用在发出后,这个调用就直接返回了,调用者不会立即得到结果,但是不会阻塞,可以继续执行后续的操作。用一句话来说就是
程序无须按照代码顺序自上而下的执行
需要的文件
这是我们要引入的template.html文件
<html>
<head></head>
<link rel="stylesheet" href="style.css">
<body>
<h1>不吃算拉~</h1>
<img src="./eat.jpg" alt="" width="100px" height="100px">
<script src="./common.js"></script>
</body>
</html>
样式和js可以自己写,我写的有点粗糙,在本地上预览效果如下:
同步方式读取
现在我们用同步的方式读取这个文件
const Koa = require('koa');
const app = new Koa();
const static = require('koa-static');
const fs = require('fs');
const main = ctx => {
ctx.response.type = 'html'; // 响应头
const html = fs.readFileSync('./template.html','utf-8'); // 同步读取
// console.log(html);
ctx.response.body =html;
}
app.use(static('./'));
app.use(main);
app.listen(3000);
这是同步的写法,会造成阻塞。对于高并发来说,非常消耗时间。
异步方式读取
现在我们来使用性能更高,速度更快,而且没有阻塞的异步方法。 代码如下:
const Koa = require('koa');
const app = new Koa();
const static = require('koa-static');
const fs = require('fs');
const main = async ctx => {
ctx.response.type = 'html'; // 响应头
// 封装Promise 版本的 readFile
let pReadFile = function (filePath) {
return new Promise(function (resolve, reject) {
fs.readFile(filePath, 'utf-8', function (err, data) {
if (err) {
reject(err);
}
resolve(data);
});
})
}
await pReadFile('./template.html').then(data => {
ctx.response.body = data;
})
}
app.use(static('./'));
app.use(main); // 启用了一个服务 给访问者用 Visitors 使用
app.listen(3000);
预览效果
对上述代码的一些解释
- 引入了koa-static 处理静态资源
- Promise,promise是ES6为解决异步回调而生,它通过 then 链来解决多层回调的问题,我又结合了 async/await 来进一步优化它。
- 什么是Async/Await?
- async/await是基于Promise实现的,它不能用于普通的回调函数。
- async/await与Promise一样,是非阻塞的。
- async 是“异步”的简写,而 await 可以认为是 async wait 的简写。所以应该很好理解 async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
总结
对于以上代码,其实我们还有更简单的方法来实现,这里用到了流(Stream)的思想
const fs = require('fs');
const Koa = require('koa');
const app = new Koa();
const static = require('koa-static');
const main = ctx =>{
ctx.response.type = 'html';
ctx.response.body = fs.createReadStream('./template.html');
}
app.use(static('./'));
app.use(main);
app.listen(3000,function(){
console.log('在3000端口上启动成功')
});
可以看到, 流的使用更加强大。这里不做过多赘述。
写在后面
笔者目前还是一名在读大三学生, 如果有相应错误,欢迎大佬指正,也欢迎大家能够一起交流问题,希望能和大家一起得到成长!