首页 > 语言 > JavaScript > 正文

浅谈Node.js之异步流控制

2024-05-06 15:25:16
字体:
来源:转载
供稿:网友

前言

在没有深度使用函数回调的经验的时候,去看这些内容还是有一点吃力的。由于Node.js独特的异步特性,才出现了“回调地狱”的问题,这篇文章中,我比较详细的记录了如何解决异步流问题。

文章会很长,而且这篇是对异步流模式的解释。文中会使用一个简单的网络蜘蛛的例子,它的作用是抓取指定URL的网页内容并保存在项目中,在文章的最后,可以找到整篇文章中的源码demo。

1.原生JavaScript模式

本篇不针对初学者,因此会省略掉大部分的基础内容的讲解:

(spider_v1.js)

const request = require("request");const fs = require("fs");const mkdirp = require("mkdirp");const path = require("path");const utilities = require("./utilities");function spider(url, callback) {  const filename = utilities.urlToFilename(url);  console.log(`filename: ${filename}`);  fs.exists(filename, exists => {    if (!exists) {      console.log(`Downloading ${url}`);      request(url, (err, response, body) => {        if (err) {          callback(err);        } else {          mkdirp(path.dirname(filename), err => {            if (err) {              callback(err);            } else {              fs.writeFile(filename, body, err => {                if (err) {                  callback(err);                } else {                  callback(null, filename, true);                }              });            }          });        }      });    } else {      callback(null, filename, false);    }  });}spider(process.argv[2], (err, filename, downloaded) => {  if (err) {    console.log(err);  } else if (downloaded) {    console.log(`Completed the download of ${filename}`);  } else {    console.log(`${filename} was already downloaded`);  }});

上边的代码的流程大概是这样的:

    把url转换成filename 判断该文件名是否存在,若存在直接返回,否则进入下一步 发请求,获取body 把body写入到文件中

这是一个非常简单版本的蜘蛛,他只能抓取一个url的内容,看到上边的回调多么令人头疼。那么我们开始进行优化。

首先,if else 这种方式可以进行优化,这个很简单,不用多说,放一个对比效果:

/// beforeif (err) {  callback(err);} else {  callback(null, filename, true);}/// afterif (err) {  return callback(err);}callback(null, filename, true);

代码这么写,嵌套就会少一层,但经验丰富的程序员会认为,这样写过重强调了error,我们编程的重点应该放在处理正确的数据上,在可读性上也存在这样的要求。

另一个优化是函数拆分,上边代码中的spider函数中,可以把下载文件和保存文件拆分出去。

(spider_v2.js)

const request = require("request");const fs = require("fs");const mkdirp = require("mkdirp");const path = require("path");const utilities = require("./utilities");function saveFile(filename, contents, callback) {  mkdirp(path.dirname(filename), err => {    if (err) {      return callback(err);    }    fs.writeFile(filename, contents, callback);  });}function download(url, filename, callback) {  console.log(`Downloading ${url}`);  request(url, (err, response, body) => {    if (err) {      return callback(err);    }    saveFile(filename, body, err => {      if (err) {        return callback(err);      }      console.log(`Downloaded and saved: ${url}`);      callback(null, body);    });  })}function spider(url, callback) {  const filename = utilities.urlToFilename(url);  console.log(`filename: ${filename}`);  fs.exists(filename, exists => {    if (exists) {      return callback(null, filename, false);    }    download(url, filename, err => {      if (err) {        return callback(err);      }      callback(null, filename, true);    })  });}spider(process.argv[2], (err, filename, downloaded) => {  if (err) {    console.log(err);  } else if (downloaded) {    console.log(`Completed the download of ${filename}`);  } else {    console.log(`${filename} was already downloaded`);  }});            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选