设为首页 收藏本站
查看: 908|回复: 0

[经验分享] NodeJs通过async/await处理异步

[复制链接]

尚未签到

发表于 2017-2-22 12:13:26 | 显示全部楼层 |阅读模式
##场景

远古时代
  我们在编写express后台,经常要有许多异步IO的处理。在远古时代,我们都是用chunk函数处理,也就是我们最熟悉的那种默认第一个参数是error的函数。我们来模拟一个Mongo数据库的操作,感受一下。
  

mongoDb.open(function(err, db){  if(!err){
  db.collection("users", function(err, collection){
  if(!err){
  let person = {name: "yika", age: 20};
  collection.insert(person, function(err, result){
  if(!err){
  console.log(result);
  }
  });
  }
  })
  }
  
});
  

  这个也就是被我们所诟病的callback hell,一堆横向金字塔,如果将回调拆分成函数,则会变得非常支离破碎。为了防止到恶心到大家,我甚至没有写关于错误的处理,正常来说,每一个异步的操作都需要都它的error进行相应的显示或处理的。

Promise时代
  后来进入了好一点的时代就是Promise,我们也可以称作链式操作。关于Promise,我也是之前有专门写过一系列的博文,有兴趣可以回头翻一下。这里来看看,将以上改写之后的状况。
  

let person = {name: "yika"};  
mongoDb
  .open()
  .then(function(database){
  return database.collection("users");
  })
  .then(function(collection){
  return collection.insert(person);
  })
  .then(function(result){
  console.log(result);
  })
  .catch(function(e){
  throw new Error(e);
  })
  

  我们可以看到,我们将金字塔已经平铺成一条线状结构了。相比之前恶心难以维护的chunk函数,变成了promise函数,并且错误的处理也变得十分优雅。但是我们仍然不可忽视某些问题,例如我们必须忍受各个逻辑被一个又一个的then()包裹起来,每一个函数都有其独立的作用域,如果为了共享某个数据就必须挂在最外层,最重要的还是,它与我们熟悉的同步编程仍然有差别。

Generator时代
  TJ大神,借着ES6的Generator迭代器,最早实现了异步编程同步化的功能,也就是最为我们所熟知的co库。我们通过co(function *(){})可以使函数内部通过迭代器来控制。而co在这里则是充当了启动器的角色。关于Generator和co我在之前的博文也同样说过。
  

let co = require("co");  

  
co(function *(){
  let db, collection, result;
  let person = {name: "yika"};
  try{
  db = yield mongoDb.open();
  collection = yield db.collection("users");
  result = yield collection.insert(person);
  }catch(e){
  console.error(e.message);
  }
  console.log(result);
  
});
  

  我们已经非常接近同步编程了,在co包裹的函数内部,只有一个异步执行完毕,才会继续执行下面的代码。并且错误的处理也是通过try and catch进行实现的。不过我们不得不承认的是,迭代器终究不是为异步而存在的。里面的yield和*的语义也并不代表的就是异步函数标志。并且迭代器是需要co去驱动的,它和我们想象中的函数多少有一点点不同。

async/await时代
  我们关注到ES7的async/await,才发现这才是我们想要的!我们将上面的代码小小改写一下。
  

async function insertData(person){  let db, collection, result;
  try{
  db = await mongoDb.open();
  collection = await db.collection("users");
  result = await collection.insert(person);
  }catch(e){
  console.error(e.message);
  }
  console.log(result);
  
}
  

  
insertData({name: "yika"});
  

  我们可以看到inserData是一个真正的函数,是我们可以直接去调用而无需启动器驱动的。当然内部我们也可以感受到处理yield变成了await以外,并没有很大区别。async/await,更符合我们异步编程的语义。
  那么问题来了,how to use it?

## 使用
  我们一开始就说过,babel已经支持async的transform了,所以我们使用的时候引入babel就行。当然server端和browser端,可以有不同的处理方法。在开始之前我们需要引入以下的package,preset-stage-3里就有我们需要的async/await的编译文件。
  

$ npm install babel-core --save  
$ npm install babel-preset-es2015 --save
  
$ npm install babel-preset-stage-3 --save
  

Browser端
  Babel一开始的出现就是为了让旧浏览器也能支持新的ES6特性,提升我们的开发体验。所以在Babel一开始就是可以通过babel-cli终端进行编译的。或者引入babel文件在浏览器端进行编译。当然这些都不是我最推荐的,所以我就带过不说啦。在前端静态资源配置里,webpack是现在比较好的解决方案,它支持静态资源的模块依赖,打包合并,还有语言的预处理,当然在这里我们就是指babel的处理。
  

// webpack.config.js  
// 省略上面的文件输入输出的配置,直接看模块加载器的配置
  
module: {
  loaders: [
  {
  test: /\.js$/,
  exclude: /(node_modules|bower_components)/,
  loader: "babel",
  query: {
  presets: ['es2015', 'stage-3']
  }
  },
  ]
  
}
  

  这样我们就可以愉快的使用了。

Server端
  相对来说,后端比前端需要处理的异步IO地方多得多,也是更加需要这个。那我们在Server端又如何引入babel呢?
  其实最简单也是最麻烦的方法就是,直接把js文件通过babel编译出新的文件再来使用。当然也就免不了冗余文件了,眼不见心不烦,还是换一个方法吧。
  我们使用官方提供的require hook方法,顾名思义就是通过require进来后,接下来的文件进行require的时候都会经过Babel的处理。因为我们知道CommonJs是同步的模块依赖,所以也是可行的方法。我们需要多一个用于启动的js文件,一个真正执行程序的js文件。
  

// index.js  
// 用于引入babel,并且启动app.js
  

  
require("babel-core/register");
  
require("./app.js");
  

  配置完hook之后,我们就配置babel的.babelrc文件,它是一个json格式的文件。es2015看情况配置,如果是已经是Node5.0版本,就无需再进行编译。
  

{  "presets": ["stage-3", "es2015"]
  
}
  

  最后我们的异步函数代码,写在app.js里即可。
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-345749-1-1.html 上篇帖子: 开发nodejs模块并发布到npm的简单示例 下篇帖子: nodejs C/C++ Addons 中的指针操作
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表