Node的进程控制什么是进程控制在Node中,进程控制是让一组异步任务顺序执行的概念,进程控制分为串行和并行。串行图:graphTDStart-->work-1-->work-2-->...-->work-n-->Stop并行图:graphLRStart-->work-1-->StopStart-->>work-2-->StopStart-->...-->StopStart-->work-n-->Stop串行流控串行应用场景串行流控在某些情况下是相关的一种控制形式,操作必须依次执行。比如我想在新的目录test下新建一个文件test1.txt,在test1.txt里面写上helloworld,然后新建一个文件test2.js读取test1.txt里的helloword,这里可以只有一个序列。虽然文件的读写是异步的,但是我们只能等待上一步完成,再进行下一步。graphLR创建目录test-->新建文件test1.txt-->在test1.txt中写入helloword-->新建文件test2.js-->写下读取test1.txt的代码实现串口的方法使用定时器setTimeout来模拟。这里使用三个定时器来模拟。当第一个定时器的回调函数执行时,第二个定时器会被挂起等待回调执行,然后执行第二个回调,第三个定时器会被挂起。一个定时器等待回调执行,最后执行第三个回调,依次输出:graphLRfirst-->next-->lastsetTimeout(()=>{console.log('我先执行。');setTimeout(()=>{console.log('Iexecutenext.');setTimeout(()=>{console.log('Iexecutelast.');},100);},500);},1000);使用async库实现使用第三方开源库async可以很方便的实现顺序执行,只需要将顺序执行的函数放到一个数组中即可。安装asyncnpmi--saveasyncconstasync=require('async');async.series([callback=>{setTimeout(()=>{console.log('Iexecutefirst.');callback();},1000);},callback=>{setTimeout(()=>{console.log('Iexecutenext.');callback();},500);},callback=>{setTimeout(()=>{console.log('我最后执行。');callback();},100);}]);手动实现序列化流控,本质上是让回调在需要的时候进来,而不是简单的嵌套。这里我们定义了一个task,用它来保存各个异步函数的操作,通过next()依次调用,并将结果作为参数传递给next函数,从而保证执行的顺序。constfs=require('fs');constrequest=require('request');consthtmlparser=require('htmlparser');constconfigFilename='./rss_feeds.txt';functioncheckForRSSFile(){fs.exists(configFilename,(exists)=>{if(!exists)returnnext(newError(`MissingRSSfile:${configFilename}`));next(null,configFilename);});}functionreadRSSFile(configFilename){fs.readFile(configFilename,(err,feedList)=>{if(err)returnnext(err);feedList=feedList.toString().replace(/^\s+|\s+$/g,'').split('\n');constrandom=Math.floor(Math.random()*feedList.length);next(null,feedList[random]);});}functiondownloadRSSFeed(feedUrl){request({uri:feedUrl},(err,res,body)=>{if(err)returnnext(err);if(res.statusCode!==200)returnnext(newError('异常响应状态码'));next(null,正文);});}函数parseRSSFeed(rss){consthandler=newhtmlparser.RssHandler();constparser=newhtmlparser.Parser(handler);parser.parseComplete(rss);if(!handler.dom.items.length)returnnext(newError('NoRSSitemsfound'));constitem=handler.dom.items.shift();console.log(item.title);console.log(item.link);}consttasks=[checkForRSSFile,readRSSFile,downloadRSSFeed,parseRSSFeed];函数next(err,result){if(err)throwerr;constcurrentTask=tasks.shift();if(currentTask){currentTask(result);}}next();并行流程控制并行应用场景同时请求多个资源,读取多个文件实现并行的方法为了让异步任务并行执行,仍然是将任务放在数组中,只是任务的顺序存储无所谓。每个任务都应该调用处理函数来增加已完成任务的数量。当所有任务完成后,处理函数应该执行后续逻辑。使用并行流控统计几个文件中词的出现频率:graphTD获取目录中的文件列表-->读取文件1-->显示词的计数值获取目录中的文件列表-->readFetchfile2-->显示word的计数值获取目录中的文件列表-->...-->显示word的计数值获取目录中的文件列表-->读取文件n-->显示单词的Constfs=require('fs');const任务=[];constwordCounts={};constfilesDir='./text';让completedTasks=0;函数checkIfComplete(){completedTasks++;if(completedTasks===tasks.length){for(letindexinwordCounts){console.log(`${index}:${wordCounts[index]}`);}}}functionaddWordCount(word){wordCounts[word]=(wordCounts[word])?wordCounts[word]+1:1;}functioncountWordsInText(text){constwords=text.toString().toLowerCase().split(/\W+/).sort();words.filter(word=>word).forEach(word=>addWordCount(word));}fs.readdir(filesDir,(err,files)=>{if(err)throwerr;files.forEach(file=>{consttask=(file=>{return()=>{fs.readFile(file,(err,text)=>{if(err)抛出错误;countWordsInText(文本);检查如果完成();});};})(`${filesDir}/${file}`);任务.推送(任务);})tasks.forEach(task=>task());});
