对于用过Nodejs的小伙伴都知道
Nodejs是典型的异步开发模式, 它最大的优势也是异步机制
这种机制带来巨大的性能优势的同时, 也带来了回调模式引发的回调地狱问题,从而导致开发者的梦魇
作为例子, 先准备3个文件
先来一个最简单的回调样例:
const fs = require("fs");
fs.readFile('d:/aa.txt', (err, res1)=>{
if(err) console.error(err);
else{
console.log('1...', res1.toString());
}
});
console.log("2...这句是在fs.readFile顺序后面的语句.");
执行结果:
结果显示”2…”比”1…”先输出
原因是”1…”是在回调后执行, 比顺序执行的”2…”慢上半拍
现在提出问题: 要求依次输出”aa.txt”, “bb.txt”, “cc.txt”的文件内容, 要怎么做?
如果按传统的顺序编程思路,将会这么写:
fs.readFile('d:/aa.txt', (err, res1)=>{
if(err) console.error(err);
else{
console.log('1...', res1.toString());
}
});
fs.readFile('d:/aa.txt', (err, res2) => {
if (err) console.error(err);
else {
console.log('1.1...', res2.toString());
}
});
fs.readFile('d:/cc.txt', (err, res3) => {
if (err) console.error(err);
else {
console.log('1.2...', res3.toString());
}
});
console.log("2...这句是在fs.readFile顺序后面的语句.");
这是成功了?
哦哟, 居然可以!
其实这是假象! 这个案例中, 3个文件大小一致, 导致调用和回调时机和时间几乎相同, 导致看上去好像是”顺序执行”成功, 但我们只要把其中一个换成读取不同大小的文件, 就能看出区别
比如把bb.txt换成一个稍大一些的HTML文件, 由于读取文件大小不同, 所需的消耗时间也不同, 异步就表现出不同的结果如下图
很显然,1.2跑到1.1前面来了
这时候怎么解决这个问题?
最简单的思路就是:那就在上一个回调块内执行下一个回调块:
fs.readFile('d:/aa.txt', (err, res1)=>{
if(err) console.error(err);
else{
console.log('1...', res1.toString());
fs.readFile('d:/aa.html', (err, res2) => {
if (err) console.error(err);
else {
console.log('1.1...', res2.toString());
fs.readFile('d:/cc.txt', (err, res3) => {
if (err) console.error(err);
else {
console.log('1.2...', res3.toString());
}
});
}
});
}
});
console.log("2...这句是在fs.readFile顺序后面的语句.");
这下可以了
应该看出来, 虽然这样写能解决问题
但是!
代码变得开始难以阅读
试想一下, 如果这种调用出现10次10次, 那这代码还能读(维护)吗? 这就是经典回调地狱现象
解决办法也有不少
我们本次先用Q模块来演示怎么把这种代码变得稍微优雅一点
先安装Q模块
npm install q
然后代码改进一下:
const Q = require("q");
//封装一下读文件的方法
function rfile(fn){
let deferred = Q.defer();
fs.readFile(fn, (err, res) => {
if (err){
deferred.reject(err);
}else {
deferred.resolve(res);
}
});
return deferred.promise;
}
读一个文件的例子:
let res;
rfile('d:/aa.txt').then((res1) => {
res = res1.toString();
console.log(1.1, res);
}).then(()=>{
console.log(1.2, res);
})
console.log("2...这句是在fs.readFile顺序后面的语句.");
执行成功
多个文件按顺序怎么读呢
let res = [];
rfile('d:/aa.txt').then((res1)=>{
res[0] = res1.toString();
console.log(1.1, res);
}).then(
rfile('d:/bb.txt').then((res2) => {
res[1] = res2.toString();
console.log(1.2, res);
}).then(
rfile('d:/cc.txt').then((res3) => {
res[2] = res3.toString();
console.log(1.3, res);
}).then(()=>{
console.log(1.4, res);
})
)
)
console.log("2...这句是在fs.readFile顺序后面的语句.");
与预期结果相符
这种写法, 与回调地狱相比,有了很大的改善,多层执行只要同级多个then即可
好像叫瀑布流(串行)的方式?
缺点是要把异步代码封装在方法里再调用
个人觉得, 这种方法还是不够彻底
下期用co模块+Promise的方式记录一篇, 实现真正的顺序代码方式.
内容出处:,
声明:本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。文章链接:http://www.yixao.com/procedure/25501.html
评论列表(1条)