首页 > 编程语言 >NodeJs通过async/await处理异步

NodeJs通过async/await处理异步

时间:2024-04-07 18:02:06浏览次数:20  
标签:function 异步 NodeJs babel await collection async 我们

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包裹的函数内部,只有一个异步执行完毕,才会继续执行下面的代码。并且错误的处理也是通过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里即可。

标签:function,异步,NodeJs,babel,await,collection,async,我们
From: https://www.cnblogs.com/sexintercourse/p/18119599

相关文章

  • 用async/await改造Node.js(Express)网站
    用async/await改造Node.js(Express)网站Mike的读书季关注IP属地:北京2018.11.0200:13:00字数582阅读3,1151.回调的嵌套陷阱在Node.js中,使用回调的方式进行异步操作,我们以读取文件内容为例:constfs=require('fs');//定义一个以回调的方式获取文件的函数funct......
  • NodeJs进阶开发、性能优化指南
    相信对于前端同学而言,我们去开发一个自己的简单后端程序可以借助很多的nodeJs的框架去进行快速搭建,但是从前端面向后端之后,我们会在很多方面会稍显的有些陌生,比如性能分析,性能测试,内存管理,内存查看,使用C++插件,子进程,多线程,Cluster模块,进程守护管理等等NodeJs后端的知识,在这里为大......
  • C++多线程:async、future、packaged_task、promise、shared_future的学习与使用(九)
    1、异步任务线程异步线程的概念:异步:就是非同步,同步就是必须一个一个的执行,异步可以两个事情一起干异步线程:异步线程就相当于把非关联的两件事分开找两个线程去执行,而分开的那个就是异步线程举例:例如登录信息,用户登录完毕主线程肯定是需要去及时响应用户的请求的,而系统设......
  • 回调地狱--promise与async+await
    一、回调地狱首先了解两个概念,什么是回调函数?什么是异步任务?1.1回调函数当一个函数作为参数传入另一个参数中,并且它不会立即执行,只有当满足一定条件后该函数才可以执行,这种函数就称为回调函数。(它是作为参数传递给另一个函数的函数)我们熟悉的定时器和Ajax中就存在有回......
  • nodejs+python开发基于uniapp的校园跑腿系统 微信小程序
    本文先提出了开发基于uniapp的高校校园跑腿系统的背景意义,然后通过功能性和非功能性分析阐述本系统的需求,然后从功能设计和数据库设计两方面进行系统的设计建模。在技术实现部分采用了nodejs作为开发后台的编程语言,客户端使用uniapp,数据库选择MySQL。最后进行了代码的编写,并说......
  • nodejs中使用Nunjucks 模板引擎
    要在Koa2中使用Nunjucks模板引擎,你需要进行一些额外的设置。以下是一个示例代码,演示了如何在Koa2中集成Nunjucks:首先,确保已经安装了Koa和Nunjucks:npminstallkoanunjucks然后,在项目中创建一个名为app.js的文件,并添加以下代码:constKoa=require('koa');con......
  • run Python asyncio code in a Jupyter notebook
     NewJupyterlab/notebookimportasyncioimporttimeasyncdefmy_coroutine():awaitasyncio.sleep(1)print("Coroutineexecuted!")s=time.perf_counter()loop=asyncio.get_event_loop()loop.create_task(my_coroutine())asyncio.r......
  • asyncio 异步io相关知识
    importasyncio#运行器asyncdefhello_async(delay,words):awaitasyncio.sleep(delay)print(words)#协程与任务asyncdeftest_async():#等待第一个协程hello_async执行完以后再串行执行下一个任务,两个协程没有并发效果start_time=time.time()prin......
  • nodejs守护进程 PM2
    nodejs守护进程PM2 概述PM2是用于Node.js应用程序的生产环境进程管理器,内置负载均衡器。它允许你将应用程序持续运行,无需停机重新加载,并简化常见的系统管理任务。官方网站 Github特性进程管理:PM2可以启动、停止和重启Node.js应用程序进程,确保应用程序一直处于运行......
  • 使用NodeJS将数据保存成JSON文件
    使用NodeJS将数据保存成JSON文件 在平时我需要把后端一些object变量保存至本地,可以这样做:constexpress=require("express");constapp=express();constserver=require("http").createServer(app);constfs=require('fs');app.use(express.static("publ......