`
weiqingfei
  • 浏览: 312079 次
  • 性别: Icon_minigender_1
  • 来自: 黑洞
社区版块
存档分类
最新评论

Node.js中的异步调用演变

阅读更多

Node.js里的异步调用是通过回调函数实现的,不管javascript的语言特性如何转变,至少在Node.js的native api里,肯定是回调函数。

比如读取文件

 

fs.readFile('/home/wqf/a.txt', function (err, data) {
  if (err) throw err;
  console.log(data);
  fs.readFile('/home/wqf/b.txt', function (err, data) {
    if (err) throw err;
    console.log(data);
  });
});

 

 

回调函数面临一个最大的问题就是callback hell,也就是多个异步操作有先后顺序时,会嵌套很多的回调函数。


为了防止这种情况,后来es6添加了yield关键字,我们看看它是如何运行的

 

function* asnycProc() {
  var data1 = yield readFile('/home/wqf/a.txt');
  console.log(data1);
  var data2 = yield readFile('/home/wqf/b.txt');
  console.log(data2);
}

 这个方法要做的事情和上面的回调写法没啥区别,实际上可以把每个yield语句以后的处理,当成yield语句所调用方法的回调。

 

但是毕竟后面的处理并不是一个方法,所以也不能用普通的方式进行回调,那么后面的处理是怎么执行的呢?

答案是next()

 

var g = asnycProc();
g.next();
g.next();

 

 

但是我们知道native api是通过回调方法执行的,默认不可能执行next()方法,那么就必须包装一下,通过包装一个执行next()的回调方法给native api用,但是next()方法是通过上面的形式执行的,我们没有办法直接把next()包装到回调方法里,必须得借助外力来执行这个next()。

这里有两种方法,一种是通过thunk函数,一种是通过promise对象。

关于thunk函数的介绍可以看这篇

http://www.ruanyifeng.com/blog/2015/05/thunk.html

目的就是把方法的其他参数跟回调方法参数分离,最终生成的方法就只有一个回调方法参数。

写个简单的thunk函数转换器就是

 

var Thunk = function(fn){
  return function (){
    var args = Array.prototype.slice.call(arguments);
    return function (callback){
      args.push(callback);
      return fn.apply(this, args);
    }
  };
};

 那么上面的readFile方法就可以写成

 

 

var readFile = Thunk(fs.readFile);
readFile('/home/wqf/a.txt');这个方法返回了一个只能接收回调函数的方法

 那么我们要做的事情就是下面这个语句返回的是native api里回调函数的参数data

 

yield readFile('/home/wqf/a.txt');

 

这又是怎么做到的呢?对于Generator方法,第一个yield语句的返回值是通过第二个next()方法传参回去的。

那么可以通过执行一下方法实现

 

var g = asnycProc();

var r1 = g.next();
r1.value(function(err, data){
  if (err) throw err;
  var r2 = g.next(data);
  r2.value(function(err, data){
    if (err) throw err;
    g.next(data);
  });
});

 

 

这里r1.value,就是yield readFile('/home/wqf/a.txt');语句中yield后面的值,也就是一个只可以接受回调方法参数的方法。然后再通过第二个g.next(data)方法把结果传了回去。

上面的这个执行函数顺序执行的处理是一样的,所以可以用递归来执行。

function run(fn) {
  var gen = fn();

  function next(err, data) {
    var result = gen.next(data);
    if (result.done) return;
    result.value(next);
  }

  next();
}

run(asnycProc);

 

接下来再看看promise的实现方法

把readFIle方法包装成promise对象

 

var readFile = function (fileName){
  return new Promise(function (resolve, reject){
    fs.readFile(fileName, function(error, data){
      if (error) reject(error);
      resolve(data);
    });
  });
};
 那么执行应该是这样的

 

 

var g = asnycProc();

g.next().value.then(function(data){
  g.next(data).value.then(function(data){
    g.next(data);
  });
})
 同样这个方法也可以用递归来实现

 

function run(gen){
  var g = gen();

  function next(data){
    var result = g.next(data);
    if (result.done) return result.value;
    result.value.then(function(data){
      next(data);
    });
  }

  next();
}

run(asnycProc);
 
既然不管用哪种方法,都需要一个执行器,为什么不能把这个处理弄成语言的语法糖呢,es7的async/await便是做这个的,写法和generator一样,只是把*换成了async,把yield换成了await。
var asyncReadFile = async function (){
  var f1 = await readFile('/etc/fstab');
  var f2 = await readFile('/etc/shells');
  console.log(f1.toString());
  console.log(f2.toString());
};
 调用很简单只要直接写
asyncReadFile();
便会自动用执行器执行,await后面跟的必须是一个promise对象,所以其实本质上还是使用的第二种方法。
分享到:
评论

相关推荐

    Node.js(node-v16.15.1-win-x64.zip)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1-win-x86.zip)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1.pkg)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1.tar.gz 源码)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js英文书籍2015出版共9本(一次下载)

    Full Stack Javascript - Learn Backbone.js, Node.js and MongoDB (APress 2015).epub Learning Node.js for Mobile Application Development (Packt 2015).pdf Microsoft Press Node.js for .NET Developers (2015...

    Node.js-StuQ分享专题《深入浅出jsNode.js异步流程控制》完整版

    StuQ分享专题《深入浅出js(Node.js)异步流程控制》完整版

    Node.js(node-v16.15.1-linux-arm64.tar.xz)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js-node.js的异步BDD和持续测试

    node.js的异步BDD和持续测试

    node-firebird, 纯javascript和 node.js的异步 firebird 客户端.zip

    node-firebird, 纯javascript和 node.js的异步 firebird 客户端 用于 Node.js.的纯 JavaScript firebird-客户端纯JavaScript和 node.js的异步 firebird 客户端。 firebird 论坛在Google网上论坛。社交

    Node.js-winston-一个node.js多传输异步日志库

    winston - 一个node.js多传输异步日志库

    Node.js-opencv4nodejs-用于node.js的异步OpenCV3.xAPI

    用于node.js的异步OpenCV 3.x API,包含以下示例:人脸检测,机器学习,深度神经网络,手势识别,对象跟踪,特征匹配,图像直方图

    Node.js(node-v16.15.1-aix-ppc64.tar.gz)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1-darwin-arm64.tar.gz)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1-x64.msi)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1-linux-x64.tar.xz)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1-x86.msi)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js(node-v16.15.1-linux-armv7l.tar.xz)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js 调用 dll动态库 以华旭身份证阅读器为例

    Electron Node.js 调用 dll动态库 以华旭金卡J10身份证阅读器为例,提示了dll动态库文件以及js源码: 文档说明:https://blog.csdn.net/qq_18944765/article/details/107913125?spm=1001.2014.3001.5501

    Node.js(node-v16.15.1-linux-ppc64le.tar.xz)

    Node.js 应用程序是用 JavaScript 编写的,可以在 Mac OS X、Windows 和 Linux 上的 Node.js 运行时中运行而无需更改。 Node.js 应用程序旨在最大限度地提高吞吐量和效率,使用非阻塞 I/O 和异步事件。Node.js 应用...

    Node.js开发实战详解源代码

    涵盖的主要内容有:Node.js的概念、应用场景、环境搭建和配置、异步编程;Node.js的模块概念及应用、Node.js的设计模式;HTTP简单服务的搭建、Node.js静态资源管理、文件处理、Cookie和Session实践、Crypto模块加密...

Global site tag (gtag.js) - Google Analytics