当前位置: 首页 > 编程笔记 >

node.js下when.js 的异步编程实践

唐沈义
2023-03-14
本文向大家介绍node.js下when.js 的异步编程实践,包括了node.js下when.js 的异步编程实践的使用技巧和注意事项,需要的朋友参考一下

假设一个业务场景:

通过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。

 类似资料:
  • 本文向大家介绍浅谈node.js中async异步编程,包括了浅谈node.js中async异步编程的使用技巧和注意事项,需要的朋友参考一下 1.什么是异步编程? 异步编程是指由于异步I/O等因素,无法同步获得执行结果时, 在回调函数中进行下一步操作的代码编写风格,常见的如setTimeout函数、ajax请求等等。 示例: 这里大部分人会认为输出123,或者333。其实它会输出 444 这里就是我

  • 问题内容: 我最近写了我的第一个Android应用程序,大约有8,000-10,000行代码。一直阻碍我使用常规设计模式的一件事是android对异步调用(打开对话框,活动等)的大量使用。因此,我的代码很快就开始看起来像“意大利面”,而我最终开始不喜欢某些类。 是否有适用于任何人都会推荐的系统的特定设计模式或编程方法?对于编写可管理的异步代码有什么建议吗? 问题答案: 使用全局变量 如果您不想用简

  • 介绍 Javascript 是一个单线程的编程语言,单线程的特点就是一次只能处理一件事情,当前代码任务耗时执行会阻塞后续代码的执行。异步编程则是一种事件驱动编程,请求调用函数或方法后,无需立即等待响应,可以继续执行其他任务,而之前任务响应返回后可以通过状态、通知和回调来通知调用者。 异步编程方法 js 中的异步编程方法有回调函数、事件处理函数、观察者、Promise、Generator、async

  • NodeJS最大的卖点——事件机制和异步IO,对开发者并不是透明的。开发者需要按异步方式编写代码才用得上这个卖点,而这一点也遭到了一些 NodeJS反对者的抨击。但不管怎样,异步编程确实是NodeJS最大的特点,没有掌握异步编程就不能说是真正学会了NodeJS。本章将介绍与异步编 程相关的各种知识。 回调 在代码中,异步编程的直接体现就是回调。异步编程依托于回调来实现,但不能说使用了回调后程序就异

  • 目前为止,我们在做的都是同步编程。同步编程执行过程很简单:一个程序从第一行开始,逐行执行一直到末尾。每次调用一个函数时,程序就会等待这个函数返回然后在执行下一行。 在异步编程中,函数地执行通常是非阻塞的。换句话说,每次你调用一个函数它就会立即返回,但相对得,这就表示函数并不会立即被执行。它有了一种机制(名为 调度程序),让可以随时在未来执行这些函数。 使用异步编程会导致程序在任何异步函数开始之前就

  • 问题内容: 如何将以下同步伪代码转换为异步js代码 在同步编程中,这似乎很自然: 得到一些ID 通过ID获取物品 获取每个项目的相关信息,并将这些信息附加到它们 将所有项目合并到一个数组中并返回 我尝试使用MULTI,但是当递归深入时,它似乎不起作用。 有没有建议学习异步范例编程?(最好是用js代码而不是.net的东西) 问题答案: 对于异步范例中的编程学习有什么建议吗? 尝试看看这些: 了解事件