NodeJs通过async/await处理异步的方法
场景
远古时代
我们在编写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包裹的函数内部,只有一个异步执行完毕,才会继续执行狼蚁网站SEO优化的代码。并且错误的处理也是通过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_ponents)/, 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里即可。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持狼蚁SEO。
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程