随笔(Node的流程控制)
Node的流程控制
什么是流程控制
【随笔(Node的流程控制)】在Node中,流程控制是让一组异步任务顺序执行的概念,流程控制分为串行
和并行
。
串行示意图:
graph TD
Start --> work-1--> work-2 --> ... --> work-n --> Stop
并行示意图:
graph LR
Start --> work-1 --> Stop
Start --> work-2 --> Stop
Start --> ...--> Stop
Start --> work-n --> Stop
串行流程控制 串行的应用场景
串行流程控制是在某些情况下,相关操作必须按顺序执行而产生的一种控制方式。比如我要在一个新目录
test
里创建一个新文件test1.txt
,并且在test1.txt
中写入hello world
,然后再创建一个新文件test2.js
读取test1.txt
中的hello word
一样,这里的顺序只能有一个,尽管文件的读写是异步,但是我们只能等待上一步完成,才能继续进行下一步。graph LR
创建目录test --> 创建新文件test1.txt --> 在test1.txt中写入helloword --> 创建新文件test2.js --> 写下读取test1.txt的代码
实现串行的方法
- 使用定时器
setTimeout
来模拟
这里使用三个定时器来模拟,当第一个定时器回调函数执行后会将第二个定时器挂起等待回调执行,然后执行第二个回调,挂起第三个定时器等待回调执行,最后执行第三个回调,依次输出:
graph LR first --> next--> last
setTimeout(() => { console.log('I execute first.'); setTimeout(() => { console.log('I execute next.'); setTimeout(() => { console.log('I execute last.'); }, 100); }, 500); }, 1000);
- 使用
async
库实现
利用第三方开源库async
可以轻松实现顺序执行,只需要把顺序执行的函数放入数组中即可。
使用前先安装async
npm i --save async
const async = require('async'); async.series([ callback => { setTimeout(() => { console.log('I execute first.'); callback(); }, 1000); }, callback => { setTimeout(() => { console.log('I execute next.'); callback(); }, 500); }, callback => { setTimeout(() => { console.log('I execute last.'); callback(); }, 100); } ]);
- 手动实现
串行化流程控制本质上是在需要时让回调进场,而不是简单地把它们嵌套起来。这里我们定义一个tasks
,用它来保存每一个异步函数的操作,通过next()
来依次调用,并将结果作为参数传入下一个函数中去,从而保证执行的顺序。
const fs = require('fs'); const request = require('request'); const htmlparser = require('htmlparser'); const configFilename = './rss_feeds.txt'; function checkForRSSFile() { fs.exists(configFilename, (exists) => { if (!exists) return next(new Error(`Missing RSS file: ${configFilename}`)); next(null, configFilename); }); }function readRSSFile(configFilename) { fs.readFile(configFilename, (err, feedList) => { if (err) return next(err); feedList = feedList .toString() .replace(/^\s+|\s+$/g, '') .split('\n'); const random = Math.floor(Math.random() * feedList.length); next(null, feedList[random]); }); }function downloadRSSFeed(feedUrl) { request({ uri: feedUrl }, (err, res, body) => { if (err) return next(err); if (res.statusCode !== 200) return next(new Error('Abnormal response status code')); next(null, body); }); }function parseRSSFeed(rss) { const handler = new htmlparser.RssHandler(); const parser = new htmlparser.Parser(handler); parser.parseComplete(rss); if (!handler.dom.items.length) return next(new Error('No RSS items found')); const item = handler.dom.items.shift(); console.log(item.title); console.log(item.link); } const tasks = [ checkForRSSFile, readRSSFile, downloadRSSFeed, parseRSSFeed ]; function next(err, result) { if (err) throw err; const currentTask = tasks.shift(); if (currentTask) { currentTask(result); } } next();
同时请求多个资源、读取多个文件
实现并行的方法
为了让异步任务并行执行,仍然是要把任务放到数组中,但任务的存放顺序无关紧要。每个任务都应该调用处理器函数增加已完成任务的计数值。当所有任务都完成后,处理器函数应该执行后续的逻辑。
用并行化流程控制实现对几个文件中单词频度的计数:
graph TD
得到目录中的文件列表 --> 读取文件1--> 显示单词的计数值
得到目录中的文件列表 --> 读取文件2--> 显示单词的计数值
得到目录中的文件列表 --> ...--> 显示单词的计数值
得到目录中的文件列表 -->读取文件n --> 显示单词的计数值
手动实现并行
const fs = require('fs');
const tasks = [];
const wordCounts = {};
const filesDir = './text';
let completedTasks = 0;
function checkIfComplete() {
completedTasks++;
if (completedTasks === tasks.length) {
for (let index in wordCounts) {
console.log(`${index}: ${wordCounts[index]}`);
}
}
}function addWordCount(word) {
wordCounts[word] = (wordCounts[word]) ? wordCounts[word] + 1 : 1;
}function countWordsInText(text) {
const words = text
.toString()
.toLowerCase()
.split(/\W+/)
.sort();
words
.filter(word => word)
.forEach(word => addWordCount(word));
}fs.readdir(filesDir, (err, files) => {
if (err) throw err;
files.forEach(file => {
const task = (file => {
return () => {
fs.readFile(file, (err, text) => {
if (err) throw err;
countWordsInText(text);
checkIfComplete();
});
};
})(`${filesDir}/${file}`);
tasks.push(task);
})
tasks.forEach(task => task());
});
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量