`
weiqingfei
  • 浏览: 318276 次
  • 性别: 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对象,所以其实本质上还是使用的第二种方法。
分享到:
评论

相关推荐

    JavaScript 异步调用

    JavaScript中的异步调用是编程中的重要概念,特别是在前端开发和Node.js环境中。异步调用主要用于处理耗时的操作,如网络请求、文件读写、定时任务等,以避免阻塞主线程,确保用户界面的流畅性。 在给定的问题中,...

    浅谈Express异步进化史

    在JavaScript的世界,异步编程是不可或缺的一部分,尤其是在Node.js环境中,由于其单线程特性,异步处理显得尤为重要。Express作为Node.js中最受欢迎的Web服务器框架之一,自然而然地需要面对和处理各种异步操作。...

    Async [removed] Build More Responsive Apps with Less Code,

    此外,文档还讲述了JavaScript如何在服务器领域成为一股不可忽视的力量,通过Node.js的兴起,JavaScript成功地拓展到了非浏览器的环境中。 文档还提到了Paul Graham在2001年曾认为JavaScript不值得使用,但随后在其...

    native-node-module:从简单的根源开始,模块将不断发展

    标题“native-node-module:从简单的根源开始,模块将不断发展”揭示了这个主题的核心,即探讨原生Node.js模块的发展历程和演变。 首先,让我们理解一下Node.js的基础。Node.js是一种基于Chrome V8引擎的JavaScript...

    使用Browserify来实现CommonJS的浏览器加载方法

    Browserify允许开发者将Node.js的CommonJS模块规范应用到浏览器端,它通过分析程序中的require调用,将所有依赖的模块打包到一个单独的JavaScript文件中。这意味着你可以在浏览器端使用类似于Node.js的模块加载方式...

    js32.lib sipdermonkey

    3. **多线程支持**: SpiderMonkey允许在多线程环境中并行执行JavaScript,通过使用“worker”来支持异步计算,提高性能。 4. **API集成**: "js32.lib" 可能是SpiderMonkey的C/C++接口,使得开发者可以在原生应用中...

    2017 page661 JavaScript_Novice to Ninja, 2nd Edition-SitePoint(2017)

    - **Node.js的兴起:** Node.js作为一个运行时环境,让JavaScript能够在服务器端执行,极大地扩展了JavaScript的应用范围。 - **JavaScript版本更新:** 介绍了ECMAScript标准的演进过程,强调了ES6(ECMAScript ...

    科技新闻

    随着时间的发展,JavaScript已经超越了浏览器环境,成为了一种全平台的编程语言,支持服务器端开发(Node.js)、移动应用、桌面应用、游戏开发等多种领域。 【JavaScript语法基础】 JavaScript语法基于ECMAScript...

    CommonJS和ES6模块的区别

    随着JavaScript的发展与应用领域的扩展,特别是Node.js的出现,让JavaScript不仅局限于浏览器环境,更拓展到了服务器端。为了更好地管理和组织代码,模块化成为了JavaScript开发中不可或缺的一部分。在这个过程中,...

    css,DHTML,javascript,vbscript 全套手册

    现代JavaScript已经发展出了Node.js平台,可以在服务器端进行开发。 【VBScript(Visual Basic Scripting Edition)】 VBScript是Microsoft开发的一种脚本语言,主要用于ASP(Active Server Pages)和Windows脚本...

    test

    随着Web技术的发展,JavaScript逐渐演变为一种全栈语言,不仅可以用于前端开发,也可以在服务器端通过Node.js运行。 1. **前端开发**:JavaScript在浏览器环境中运行,通过DOM(文档对象模型)操作HTML和CSS,实现...

    JavaScript学习经历

    如今,JavaScript 不仅是 Web 前端开发的核心技术之一,也在后端开发领域(如 Node.js)发挥着重要作用。 #### 二、JavaScript学习入门指南 ##### 1. DIV+CSS布局的重要性 - **概念理解**:DIV+CSS 是一种将网页...

    小路

    10. **Node.js**:JavaScript也可以用于服务器端开发,Node.js是一个开放源代码、跨平台的JavaScript运行环境,它让开发者可以使用JavaScript编写服务器端代码。 11. **前端构建工具**:Webpack、Gulp、Grunt等工具...

    example_test

    随着时间的发展,它已经演变成一种全栈语言,不仅限于前端,还能在后端(如Node.js)和移动应用(如React Native)中使用。 1. **基础概念**: - 变量与数据类型:JavaScript支持动态类型,变量可以存储不同类型的...

    推特自动转发评论机源码.7z

    2. **编程语言**:源码使用的编程语言可能有多种,如Python、JavaScript(Node.js)、Java或C#等。了解代码所用的语言是理解代码的第一步。 3. **网络请求与异步编程**:自动操作通常涉及网络请求,因此需要理解...

    宣讲

    JavaScript在现代Web开发中的角色不断演变,从简单的客户端脚本语言发展到全栈开发工具。理解和掌握JavaScript,对于任何IT从业者来说,都是提升技术能力的关键步骤。通过深入学习和实践,开发者可以利用JavaScript...

    NicolasCorman_4_17022021

    9. **Node.js**:JavaScript也可以在服务器端运行,通过Node.js平台,它允许开发者使用JavaScript进行服务器编程,处理文件系统、网络请求等。 10. **前端框架**:JavaScript是React、Vue、Angular等现代前端框架的...

    projeto-alura:JavaScript的原始存储库和JavaScript的原始库

    JavaScript提供了CommonJS(Node.js环境)和ES模块(浏览器环境)两种模块系统,用于组织代码和重用功能。 7. **AJAX和Fetch API**:用于在不刷新页面的情况下与服务器进行数据交换,是创建动态和交互式Web应用的...

    IAS2017- 黄勇-轻量级微服务架构实践之路.pdf

    - **调用中心**:Nginx + Node.js实现服务路由和负载均衡。 - **消息中心**:RabbitMQ处理异步通信和解耦。 - **日志中心**:Elasticsearch + Logstash + Kibana构建日志收集和分析平台。 - **监控中心**:...

    Project-35

    在这个特定的项目中,我们可能会发现一系列与JavaScript相关的编程资源,因为“JavaScript”是给定的标签。JavaScript是一种广泛应用于网页和网络应用的编程语言,它允许实现动态内容,如交互式表单、动画效果以及...

Global site tag (gtag.js) - Google Analytics