在node.js 中使用async await

2017-10-18  本文已影响0人  yaya520

一、历史

在用node.js编写程序代码时通常会遇到很多的异步操作,对于异步的处理,大概经历了以下几种方法:
1、回调。也就是第一个参数是error的函数,那么如果嵌套的层数多了,也就感觉特别非人类了,读起来会非常困难。

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);
                    }
                });
            }
        })
    }
});

2、Promise。我们也可以称作链式操作。从以下代码可以看出代码的可读性已经大大改善。但是我们仍然不可忽视某些问题,Promise 的最大问题是代码冗余,原来的任务被 Promise 包装了一下,不管什么操作,一眼看去都是一堆then,原来的语义变得很不清楚。

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);
    })

3、Generator。借着ES6的Generator迭代器,最早实现了异步编程同步化的功能,也就是最为我们所熟知的co库。我们通过co(function *(){})可以使函数内部通过迭代器来控制。而co在这里则是充当了启动器的角色。
参考:Generator 函数的异步应用

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);
});

4、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,更符合我们异步编程的语义。
参考:async 函数

二、使用

babel已经支持async的transform了,所以我们使用的时候引入babel就行。
在开始之前我们需要引入以下的package,其中babel-plugin-transform-runtime是babel的一个支持es7async的插件。 es7不同阶段语法提案的转码规则共有4个阶段,分别是babel-preset-stage-0,babel-preset-stage-1,babel-preset-stage-2,babel-preset-stage-3。选装一个就行,我这里用的是babel-preset-stage-3。

npm install babel-core --save-dev
npm install babel-preset-es2015 --save-dev
npm install babel-preset-stage-3 --save-dev
npm install babel-plugin-transform-runtime --save-dev

我们使用官方提供的require hook方法,顾名思义就是通过require进来后,接下来的文件进行require的时候都会经过Babel的处理。因为我们知道CommonJs是同步的模块依赖,所以也是可行的方法。我们需要多一个用于启动的js文件,一个真正执行程序的js文件。

// index.js 
// 用于引入babel,并且启动app.js
require("babel-core/register");
require("./app.js");
require("babel-core").transform("code", {
    plugins: ["transform-runtime"]
});

配置完hook之后,我们就配置babel的.babelrc文件,它是一个在项目根目录的json格式的文件。(在windows系统中新建文件名为以.开头的文件,如.babelrc,只需将文件名写为.babelrc.即可)

{
    "presets": [
        "stage-3",
        "es2015"
    ],
    "plugins": [
        [
            "transform-runtime",
            {
                "helpers": false,
                "polyfill": false,
                "regenerator": true,
                "moduleName": "babel-runtime"
            }
        ]
    ]
}

我们的异步代码写在app.js中即可。

上一篇下一篇

猜你喜欢

热点阅读