• node.js下when.js(Promises/A)的实践


    假设一个业务场景:

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

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

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

    2.获取rss。

    3.保存于文件。

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

     

    准备:

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

    http://programmer.csdn.net/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);
      });

    Promise给异步编程带来了巨大的方便,可以让我们专注于单个任务的实现而不会陷入金字塔厄运,以上代码仅仅是基本使用,when.js提供的功能远远不止本文提到的这些,具体参照官方API。

  • 相关阅读:
    谷歌浏览器离线安装
    C语言restrict关键字的使用
    Win32编程中radiobutton的分组
    在SourceForge中建立开源项目
    [转载]Linux解压缩命令
    [转载]vim配置文件
    解决VC6在win7下打开文件崩溃问题
    gson解析复杂的json数据
    catch中return语句的执行时间
    踏出了学习clojure的第一步
  • 原文地址:https://www.cnblogs.com/kongxianghai/p/4128856.html
Copyright © 2020-2023  润新知