如何用Q模块的链式调用来解决nodejs中的回调地狱问题

对于用过Nodejs的小伙伴都知道

Nodejs是典型的异步开发模式, 它最大的优势也是异步机制

这种机制带来巨大的性能优势的同时, 也带来了回调模式引发的回调地狱问题,从而导致开发者的梦魇如何用Q模块的链式调用来解决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顺序后面的语句.");

执行结果:

如何用Q模块的链式调用来解决nodejs中的回调地狱问题

结果显示”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顺序后面的语句.");

如何用Q模块的链式调用来解决nodejs中的回调地狱问题

这是成功了?

哦哟, 居然可以!

其实这是假象! 这个案例中, 3个文件大小一致, 导致调用和回调时机和时间几乎相同, 导致看上去好像是”顺序执行”成功, 但我们只要把其中一个换成读取不同大小的文件, 就能看出区别

比如把bb.txt换成一个稍大一些的HTML文件, 由于读取文件大小不同, 所需的消耗时间也不同, 异步就表现出不同的结果如下图如何用Q模块的链式调用来解决nodejs中的回调地狱问题

很显然,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顺序后面的语句.");

如何用Q模块的链式调用来解决nodejs中的回调地狱问题

这下可以了

应该看出来, 虽然这样写能解决问题

但是!

代码变得开始难以阅读

试想一下, 如果这种调用出现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顺序后面的语句.");

如何用Q模块的链式调用来解决nodejs中的回调地狱问题

执行成功

多个文件按顺序怎么读呢

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顺序后面的语句.");

如何用Q模块的链式调用来解决nodejs中的回调地狱问题

与预期结果相符

这种写法, 与回调地狱相比,有了很大的改善,多层执行只要同级多个then即可

好像叫瀑布流(串行)的方式?

缺点是要把异步代码封装在方法里再调用

个人觉得, 这种方法还是不够彻底

下期用co模块+Promise的方式记录一篇, 实现真正的顺序代码方式.

内容出处:,

声明:本网站所收集的部分公开资料来源于互联网,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。文章链接:http://www.yixao.net/procedure/25501.html

发表评论

登录后才能评论

评论列表(1条)