详解Node.js串行化流程控制


Posted in Javascript onMay 04, 2017

串行任务:需要一个接着一个坐的任务叫做串行任务。

可以使用回调的方式让几个异步任务按顺序执行,但如果任务过多,必须组织一下,否则过多的回调嵌套会把代码搞得很乱。

为了用串行化流程控制让几个异步任务按顺序执行,需要先把这些任务按预期的执行顺序放到一个数组中,这个数组将起到队列的作用:完成一个任务后按顺序从数组中取出下一个。

数组中的每个任务都是一个函数。任务完成后应该调用一个处理器函数,告诉它错误状态和结果。

为了演示如何实现串行化流程控制,我们准备做个小程序,让它从一个随机选择的RSS预定源中获取一篇文章的标题和URL,并显示出来。

需要从npm存储苦衷下载两个辅助模块,在命令行中(以mac系统为例)输入以下命令:

mkdir random_story
cd random_story
npm install request
npm install htmlparser

request模块是个简化的HTTP客户端,可以获取RSS数据。htmlparser模块能够把原始的RSS数据转换成JavaScript数据结构。

在新目录下创建一个random_story.js文件,包含以下代码:

var fs = require('fs');
var request = require('request');
var htmlparser = require('htmlparser');
var configFilename = './rss_feeds.txt';
//确保包含RSS订阅列表的文件存在
function checkForRSSFile() {
  fs.exists(configFilename, function(exists) {
    if (!exists) {
      return next(new Error('Missing RSS file: ' + configFilename));
    }
    next(null, configFilename);
  });
}
//读取并解析包含RSS订阅列表的文件
function readRSSFile(configFilename) {
  fs.readFile(configFilename, function(err, feedList) {
    if (err) {
      return next(err);
    }

    feedList = feedList.toString().replace(/^\s+|\s+$/g, '').split("\n");
    var random = Math.floor(Math.random()*feedList.length);
    next(null, feedList[random]);
  });
}
//向预定源发送HTTP请求以获取数据
function downloadRSSFeed(feedUrl) {
  request({uri: feedUrl}, function(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) {
  var handler = new htmlparser.RssHandler();
  var parser = new htmlparser.Parser(handler);
  parser.parseComplete(rss);
  if (!handler.dom.items.length) {
    return next(new Error('No RSS items found.'));
  }
  var item = handler.dom.items.shift();
  console.log(item.title);
  console.log(item.link);
}

var tasks = [
    checkForRSSFile,
    readRSSFile,
    downloadRSSFeed,
    parseRSSFeed
  ];
function next(err, result) {
  if (err) {
    throw err;
  }
  var currentTask = tasks.shift();
  if (currentTask) {
    currentTask(result);
  }
}
//开始执行串行化任务
next();

在试用这个程序之前,现在程序脚本所在的目录下创建一个rss_feeds.txt文件。这里只包含了一条预定源信息:

http://dave.smallpict.com/rss.xml

之后执行脚本:

node random_story.js

详解Node.js串行化流程控制

返回信息如上图。成功实现了一个串行化流程控制。

[async/await形式的串行化流程控制]

之后将源代码改写了一下,改写成ES7的async/await形式。水平有限,如有错误请指出!

let fs = require('fs');
let request = require('request');
let htmlparser = require('htmlparser');
let configFilename = './rss_feeds.txt';

function checkForRSSFile() {
  return new Promise((resolve, reject) => {
    fs.exists(configFilename, (exists) => {
      if (!exists) {
        reject(new Error('Missing RSS file: ' + configFilename));
      }
      resolve();
    });
  });
}

function readRSSFile(configFilename) {
  return new Promise((resolve, reject) => {
    fs.readFile(configFilename, (err, feedList) => {
      if (err) {
        reject(err);
      }
      feedList = feedList.toString().replace(/^\s+|\s+$/g, '').split("\n");
      let random = Math.floor(Math.random()*feedList.length);
      resolve(feedList[random]);
    });
  });
}

function downloadRSSFeed(feedUrl) {
  return new Promise((resolve, reject) => {
    request({uri: feedUrl}, (err, res, body) => {
      if (err) {
        reject(err);
      }
      if (res.statusCode !== 200) {
        reject(new Error('Abnormal response status code'));
      }
      resolve(body);
    });
  });
}

function parseRSSFeed(rss) {
  let handler = new htmlparser.RssHandler();
  let parser = new htmlparser.Parser(handler);
  parser.parseComplete(rss);
  if (!handler.dom.items.length) {
    throw new Error('No RSS items found.');
  }
  let item = handler.dom.items.shift();
  console.log(item.title);
  console.log(item.link);
}

async function getRSSFeed() {
  await checkForRSSFile();
  let url = await readRSSFile(configFilename);
  let rss = await downloadRSSFeed(url);
  return rss;
}
getRSSFeed().then(rss => parseRSSFeed(rss), e => console.log(e));

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用EXT实现无刷新动态调用股票信息
Nov 01 Javascript
鼠标拖动实现DIV排序示例代码
Oct 14 Javascript
Js实现无刷新删除内容
Apr 29 Javascript
js实现点击文本框显示日期选择器特效代码分享
May 21 Javascript
跟我学习javascript的异步脚本加载
Nov 20 Javascript
JavaScript 对象详细整理总结
Sep 29 Javascript
基于Vue生产环境部署详解
Sep 15 Javascript
Node.js之readline模块的使用详解
Mar 25 Javascript
WebGL学习教程之Three.js学习笔记(第一篇)
Apr 25 Javascript
微信小程序如何实现radio单选框单击打勾和取消
Jan 21 Javascript
如何实现echarts markline标签名显示自己想要的
Jul 20 Javascript
vue项目如何监听localStorage或sessionStorage的变化
Jan 04 Vue.js
纯原生js实现贪吃蛇游戏
Apr 16 #Javascript
js调用刷新界面的几种方式
May 03 #Javascript
JavaScript中双向数据绑定详解
May 03 #Javascript
Js实现中国公民身份证号码有效性验证实例代码
May 03 #Javascript
Vue原理剖析 实现双向绑定MVVM
May 03 #Javascript
利用node.js写一个爬取知乎妹纸图的小爬虫
May 03 #Javascript
Vue实现双向数据绑定
May 03 #Javascript
You might like
PHP投票系统防刷票判断流程分析
2012/02/04 PHP
apache php mysql开发环境安装教程
2016/07/28 PHP
PHP使用PDO调用mssql存储过程的方法示例
2017/10/07 PHP
通过Unicode转义序列来加密,按你说的可以算是混淆吧
2007/05/06 Javascript
javascript replace方法与正则表达式
2008/02/19 Javascript
JavaScript this 深入理解
2009/07/30 Javascript
JQuery拖动表头边框线调整表格列宽效果代码
2014/09/10 Javascript
jQuery使用fadeout实现元素渐隐效果的方法
2015/03/27 Javascript
jquery地址栏链接与a标签链接匹配之特效代码总结
2015/08/24 Javascript
解决jquery无法找到其他父级子集问题的方法
2016/05/10 Javascript
详解微信小程序开发—你期待的分享功能来了,微信小程序序新增5大功能
2016/12/23 Javascript
ajax +NodeJS 实现图片上传实例
2017/06/06 NodeJs
浅谈Angular2 模块懒加载的方法
2017/10/04 Javascript
超出JavaScript安全整数限制的数字计算BigInt详解
2018/06/24 Javascript
js与jQuery实现获取table中的数据并拼成json字符串操作示例
2018/07/12 jQuery
vue路由切换之淡入淡出的简单实现
2019/10/31 Javascript
Js代码中的span拼接问题解决
2019/11/22 Javascript
Python 字典与字符串的互转实例
2017/01/13 Python
Python numpy.array()生成相同元素数组的示例
2018/11/12 Python
python抓取京东小米8手机配置信息
2018/11/13 Python
Django 全局的static和templates的使用详解
2019/07/19 Python
Python的Lambda函数用法详解
2019/09/03 Python
解决Tensorboard可视化错误:不显示数据 No scalar data was found
2020/02/15 Python
Django Haystack 全文检索与关键词高亮的实现
2020/02/17 Python
Python的in,is和id函数代码实例
2020/04/18 Python
python安装后的目录在哪里
2020/06/21 Python
python 装饰器的实际作用有哪些
2020/09/07 Python
详解python中的闭包
2020/09/07 Python
Amara德国:家居饰品、设计师品牌和豪华礼品
2019/05/20 全球购物
联想阿根廷官方网站:Lenovo Argentina
2019/10/14 全球购物
数据库什么时候应该被重组
2012/11/02 面试题
中国好声音华少广告词
2014/03/17 职场文书
就业协议书怎么填
2014/04/11 职场文书
道德大讲堂实施方案
2014/05/14 职场文书
纪律委员竞选稿
2015/11/19 职场文书
idea 在springboot中使用lombok插件的方法
2021/08/02 Java/Android