Nodejs中when库的实例介绍

本文探讨了在处理异步逻辑时,如何利用Promise/A规范改进回调地狱问题,通过when.js库实现了更清晰、简洁的异步任务整合方式,包括读取RSS地址、获取RSS数据和保存至文件的操作,同时介绍了Promise模型的发布/订阅机制及其状态转移特性,最终展示了一种易于理解和维护的代码重构方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

假设一个业务场景:

通过rss地址,获取rss并保存于文件,rss地址保存于文件中。

完成该场景的业务需要完成3个任务:

1.从文件中读取rss地址。

2.获取rss。

3.保存于文件。

最后将这三个任务进行整合。

 

准备:

存放rss地址的文件,address.txt。

http://programmer.youkuaiyun.com/rss_programmer.html

 

任务1:

读取rss地址文件的内容并通过callback返回。

var getRssAddress = function(path, callback) {
  fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
    callback(err, data);
  });
}

 

任务2:

 通过rss地址get到rss,并通过callback返回错误或数据。

复制代码
var getRss = function(url, callback) {
  var data = '';
  http.get(url, function(res) {
    res.on('data', function(chrunk) {
      data += chrunk;
    });

    res.on('end', function() {
      callback(null, data);
    });
  }).on('error', function(err) {
    callback(err, null);
  });
}
复制代码

 

任务3:

将rss保存于文件并通过callback返回错误。

var saveRss = function(data, callback) {
  fs.writeFile('rss.txt', data, 'utf8', function(err) {
    callback(err);
  });
}

 

整合:

复制代码
getRssAddress('address.txt', function(err, data) {
  if(err) {
    console.log(err);
    return;
  }

  getRss(data, function(err, data) {
    if(err) {
      console.log(err);
      return;
    }

    saveRss(data, function(err) {
      if(err) console.log(err);
    });
  });
});
复制代码

上面的代码是全异步处理,使用最常见的callback处理异步逻辑的返回,好处是标准写法,大家都能容易接受;坏处是耦合性太强,处理异常麻烦,代码不直观,特别是处理业务逻辑复杂和处理任务多的场景,层层的callback会让人眼冒金星,代码难以维护。

 

Promise/A规范的实现之一when.js正是针对这样的问题域。

让我们来看一下改造后的代码。

任务1:

复制代码
var getRssAddress = function(path) {
    var deferred = when.defer();
      fs.readFile(path, {encoding: 'utf8'}, function (err, data) {
        if (err) deferred.reject(err);
        deferred.resolve(data);
      });

    return deferred.promise;
}
复制代码

 

任务2:

复制代码
var getRss = function(url) {
  var deferred = when.defer();
    var data = '';
    http.get(url, function(res) {
      res.on('data', function(chrunk) {
        data += chrunk;
      });
      res.on('end', function() {
        deferred.resolve(data);
      });
    }).on('error', function(err) {
      deferred.reject(err);
    });

    return deferred.promise;
}
复制代码

 

任务3:

复制代码
var saveRss = function(data) {
  var deferred = when.defer();
  fs.writeFile('rss.txt', data, 'utf8', function(err) {
    if(err) deferred.reject(err);
    deferred.resolve();
  });

  return deferred.promise;
}
复制代码

 

整合:

getRssAddress('address.txt')
  .then(getRss)
  .then(saveRss)
  .catch(function(err) {
    console.log(err);
  });

解释:

promise/A规范定义的“Deferred/Promise”模型就是“发布/订阅者”模型,通过Deferred对象发布事件,可以是完成resolve事件,或者是失败reject事件;通过Promise对象进行对应完成或失败的订阅。

在Promises/A规范中,每个任务都有三种状态:默认(pending)、完成(fulfilled)、失败(rejected)。

1.默认状态可以单向转移到完成状态,这个过程叫resolve,对应的方法是deferred.resolve(promiseOrValue);

2.默认状态还可以单向转移到失败状态,这个过程叫reject,对应的方法是deferred.reject(reason);

3.默认状态时,还可以通过deferred.notify(update)来宣告任务执行信息,如执行进度;

4.状态的转移是一次性的,一旦任务由初始的pending转为其他状态,就会进入到下一个任务的执行过程中。

 

按照上面的代码。

通过when.defer定义一个deferred对象。

var deferred = when.defer();

异步数据获取成功后,发布一个完成事件。

deferred.resolve(data);

异步数据获取失败后,发布一个失败事件。

deferred.reject(err);

并且返回Promise对象作为订阅使用。

return deferred.promise;

订阅是通过Promise对象的then方法进行完成/失败/通知的订阅。

getRssAddress('address.txt')
  .then(getRss)

then有三个参数,分别是onFulfilled、onRejected、onProgress

promise.then(onFulfilled, onRejected, onProgress)

上一个任务被resolve(data),onFulfilled函数就会被触发,data作为它的参数.

上一个任务被reject(reason),那么onRejected就会被触发,收到reason。

任何时候,onFulfilled和onRejected都只有其一可以被触发,并且只触发一次。

 

对于处理异常,when.js也提供了极其方便的方法,then能传递错误,多个任务串行执行时,我们可以只在最后一个then定义onRejected。也可以在最后一个then的后面调用catch函数捕获任何一个任务的异常。

如此写法简单明了。

getRssAddress('address.txt')
  .then(getRss)
  .then(saveRss)
  .catch(function(err) {
    console.log(err);
  });
### 如何在Node.js中使用MySQL #### 初始化Node.js应用程序并安装依赖项 为了初始化一个新的Node.js项目,可以运行命令`npm init`来创建一个`package.json`文件。在这个过程中,会设置项目的名称、版本号、描述以及入口文件等信息[^1]。 对于与MySQL交互的需求,在`package.json`中的`dependencies`部分应当加入特定于MySQL的模块,例如: ```json "dependencies": { "mysql": "2.0.0" } ``` 这确保了应用能够通过相应的驱动程序访问数据服务[^2]。 #### 安装必要的 除了上述提到的MySQL模块外,可能还需要额外安装一些系统级别的包以支持某些功能特性,比如OpenSSL开发工具和其他辅助组件。这些可以通过Linux下的包管理器完成安装操作,如Ubuntu上的APT: ```bash sudo apt-get update && sudo apt-get install -y libpopt-dev libssl-dev libnuma-dev ``` 此步骤有助于解决潜在的编译错误或其他兼容性问题[^4]。 #### 创建MySQL连接实例 下面是一个简单的例子展示怎样建立到MySQL服务器的安全链接,并执行基本查询语句: ```javascript const mysql = require('mysql'); // Create a new connection instance. let connection = mysql.createConnection({ host : 'localhost', // Database hostname or IP address. user : 'root', // Username used when connecting to MySQL. password : '', // Password associated with the username above. database : 'testdb' // Name of your target schema/database within MySQL. }); try { await connection.connect(); // Establishes an actual network connection. console.log("Connected successfully!"); let queryResult = await connection.query( `SELECT * FROM users WHERE id=?`, [userId]); console.table(queryResult); } catch(error){ throw error; } finally{ connection.end(); // Closes the established connection after operations are done. } console.log("Disconnected from server."); ``` 这段脚本展示了如何利用官方推荐的方式构建一个异步等待模式下的安全连接对象,并对其进行了简单测试——尝试获取指定ID用户的记录列表。注意这里采用了模板字符串语法`${}`来进行SQL注入防护措施的一部分处理方式。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值