node.js回调地狱解决之async库

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/themagickeyjianan/article/details/88782062

1)背景

回调地狱在node.js中是一件让人头疼的事情,但是仔细想想:nodejs中多个异步任务之间的配合无非3种情况:

顺序执行: 后者使用前者的输入

顺序执行: 前后2者没啥关系(个人觉得这个没啥用,既然没关系就用并发的方式处理)

并发执行: 各个执行没有关系,需要同时执行

async库完美解决上面3个问题,虽然async有很多用法,但是主要解决上面3种,具体代码如下:

2)前者输出作为后者输入的顺序执行 async.waterfall

var async = require('async');
var fs = require('fs');

function main() {
    console.time('start');
    async.waterfall([
        function (callback) {
            fs.readFile('./data/1.txt', 'utf-8', function (err, nextFileName) {
                callback(err, nextFileName);
            });
        },
        function (nextFileName, callback) {
            fs.readFile(nextFileName, 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                callback(err, data);
            });
        }
    ],
        function (err, result) {
            if (err) {
                console.log('err =', err);
                return;
            }
            console.log(result);
            console.timeEnd('start');
        }
    );
}

main();

setTimeout(function () {
    console.log('app end');
}, 7000);

输出:

$ node app3.js
abcdefg
start: 4.407ms
app end

可见,第一个任务读取完后才知道下一个文件读取什么,这样2个任务有前后依赖关系

当有一个任务出错时

var async = require('async');
var fs = require('fs');

function main() {
    console.time('start');
    async.waterfall([
        function (callback) {
            fs.readFile('./data/1.txt', 'utf-8', function (err, nextFileName) {
                callback(err, nextFileName);
            });
        },
        function (nextFileName, callback) {
            fs.readFile('222.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                callback(err, data);
            });
        }
    ],
        function (err, result) {
            if (err) {
                console.log('err =', err);
                return;
            }
            console.log(result);
            console.timeEnd('start');
        }
    );
}

输出:

$ node app3.js
err = { Error: ENOENT: no such file or directory, open 'E:\coding_now\NodeDemos\18-async\222.txt'
    at Error (native)
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'E:\\coding_now\\NodeDemos\\18-async\\222.txt' }
app end

可见同样所有成功才算成功

3)各个异步任务无依赖的顺序执行(感觉这个没啥用) aysnc.series

var async = require('async');
var fs = require('fs');

function main() {
    async.series([
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
             },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
            },
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);  // 模拟错误
                });
            },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
            }
         ],
        function (err, results) {
            if(err){
                console.log('err =', err); 
                return;
            }
            console.log(results);
        }
    );  
}

main();

在4个任务都成功执行的情况下,输出

$ node app.js
[ '1234567', 'abcdefg', '1234567', 'abcdefg' ]

考虑出错情况(读取不存在的文件)

var async = require('async');
var fs = require('fs');

function main() {
    async.series([
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
             },
            function (callback) {
                fs.readFile('./data/22.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                    callback(err, data);
                });
            },
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);  
                });
            },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
            }
         ],
        function (err, results) {
            if(err){
                console.log('err =', err); 
                return;
            }
            console.log(results);
        }
    );  
}

main();

那么4个任务都将失败:

$ node app.js
err = { Error: ENOENT: no such file or directory, open 'E:\coding_now\NodeDemos\18-async\data\22.txt'
    at Error (native)
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'E:\\coding_now\\NodeDemos\\18-async\\data\\22.txt' }

4)并发执行 async.parallel

var async = require('async');
var fs = require('fs');

function main() {
    console.time('start');
    async.parallel([
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
             },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                    setTimeout(function () {
                        callback(err, data);
                    }, 3000);  
                });
            },
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);  
                });
            },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                    setTimeout(function () {
                        callback(err, data);
                    }, 3000);
                });
            }
         ],
        function (err, results) {
            if(err){
                console.log('err =', err); 
                return;
            }
            console.log(results);
            console.timeEnd('start');
        }
    );  
}

main();

结果:

[ '1234567', 'abcdefg', '1234567', 'abcdefg' ]
start: 3007.267ms

如果是前面那个series

var async = require('async');
var fs = require('fs');

function main() {
    console.time('start');
    async.series([
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
             },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                    setTimeout(function () {
                        callback(err, data);
                    }, 3000);  
                });
            },
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);  
                });
            },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                    setTimeout(function () {
                        callback(err, data);
                    }, 3000);
                });
            }
         ],
        function (err, results) {
            if(err){
                console.log('err =', err); 
                return;
            }
            console.log(results);
            console.timeEnd('start');
        }
    );  
}

main();

结果:

$ node app.js
[ '1234567', 'abcdefg', '1234567', 'abcdefg' ]
start: 6024.365ms

说明:parallel是并发执行的

有错误的情况(如文件不存在)

var async = require('async');
var fs = require('fs');

function main() {
    console.time('start');
    async.parallel([
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);
                });
             },
            function (callback) {
                fs.readFile('./data/22.txt', 'utf-8', function (err, data) {  // 模拟错误,22.txt找不到
                    setTimeout(function () {
                        callback(err, data);
                    }, 3000);  
                });
            },
            function (callback) {
                fs.readFile('./data/1.txt', 'utf-8', function (err, data) {
                    callback(err, data);  
                });
            },
            function (callback) {
                fs.readFile('./data/2.txt', 'utf-8', function (err, data) {  
                    setTimeout(function () {
                        callback(err, data);
                    }, 3000);
                });
            }
         ],
        function (err, results) {
            if(err){
                console.log('err =', err); 
                return;
            }
            console.log(results);
            console.timeEnd('start');
        }
    );  
}

main();

结果:

$ node app.js
err = { Error: ENOENT: no such file or directory, open 'E:\coding_now\NodeDemos\18-async\data\22.txt'
    at Error (native)
  errno: -4058,
  code: 'ENOENT',
  syscall: 'open',
  path: 'E:\\coding_now\\NodeDemos\\18-async\\data\\22.txt' }

5)总结

可见async方案完美解决回调地狱问题,简单易用

猜你喜欢

转载自blog.csdn.net/themagickeyjianan/article/details/88782062