Promise你把握不住?来看看异步转同步改造(上)

简介: Promise你把握不住?来看看异步转同步改造

前言

先说一下上一篇NodeJS文章

NodeJS 后端开发 06 连接MySQL

,这一篇展示了一个数据库链接的db.js 工具库。


该工具库提供了一个runSql函数,它的运行方式是先提交SQL,然后再异步把查询结果回调传递给callback函数的。


这个函数只适用于提前加载数据的情况,比如预先缓存批量的查库结果。然后用户请求WebAPI的时候,直接读查询缓存。

这样会有下面的问题:


新数据入库了,本地缓存需要更新。

而且无法支持动态查询。

说这么多,直接用Koa做个接口演示一下查询效果吧。


代码展示,KOA做接口查询数据库

const koa = require('Koa');                                                 
const app = new koa()
var router = require('koa-router')();
var db = require('./db-lite');
//做个简单接口
router.get('/', function(ctx, next){ctx.body='Hello, geeklevin!'});
//做个接口查询数据库
router.get('/query', function(ctx,next){
    db.runSql("SELECT * FROM COMPANY; ", function(result,fields){
        console.log('查询结果:', result);
        ctx.body = JSON.stringify(result);
        console.log('设置响应body成功!');
    });
    console.log('processing');
});
//启动服务器
app.use(router.routes());
const PORT = 8081
console.log('start app at port %s', PORT)
app.listen(PORT);

先查看简单接口展示效果:

image.png

再看看/query接口

日志看到设置了响应体ctx.body成功了,可这时候请求已经结束了。

因为db.runSql函数不是同步执行了,/query这个接口执行这个函数,碰到函数结束了,当前请求处理完毕,没有设置请求体,所以响应Not Found。

image.png

看看Promise吧

var data = new Promise(function(resolve, reject){
    asynFunction(function(error, result){
          if(error){
               reject(error);
          }else{
               resolve(result);
          }
    });
});
async getData(){
    var result = await data();
    console.log('result is:', result);
}

就两段代码,第一段是构造Promise对象;第二段为调用Promise对象处理异步请求。


先说Promise。data是一个Promise对象,它内部调用了一个异步函数asynFunction(这个函数可以是查库,请求其他网站接口,消息队列获取数据等),但是它能够保证两个结果:


处理异步请求成功的时候调用resolve函数,传递result对象;

出错的时候调用reject函数,传递error对象。

就这么简单。


第二段代码就是一个声明了异步响应的函数,虽然内部调用的Promise对象,又套娃调用了异步函数,但是await语法糖,能够保证result变量赋值这一行同步执行,也就是getData会等待result赋值这一行异步调用执行完毕,再执行console.log。


这里稍微有点绕了,请读者停下来,好好思考整理一下。


简单来说就是,在async声明的异步函数中,同步等待Promise内部执行结果,就是,同步等待异步请求。


这样,异步转同步,很神奇吧!


像查询数据库这样的异步操作就能够在API中被等待,并响应给用户了,下面来代码了。


好,用koa接口得怎么做呢?需要在数据库调用端怎么调整呢?


下面是runSql的简化实现代码,我们要改造它


const runSql = function(sql, callback){
    console.log('will run sql:', sql);
    //这里是异步调用的,但是不是Promise实现,没有办法使用asyn,await来实现同步等待异步请求。
    db.query(sql, function(error, result, fields){
        try{
            if(error) throw error;
            console.log('query result:', result); 
        }finally{
            if(callback) callback(result, fields);
        }
    });
}

先看koa怎么搞?

这个好办, 下面是一个简单的router(路由web API)。

我们看到在router.get 第二个参数加了async关键字修饰的方法。

根据ES6,我们知道async函数内可以使用await强制等待异步Promise函数的相应结果。

很明显,上面的runSql函数返回不是一个Promise对象的,所以这里先调用一个未实现的函数:prunSql。


router.get('/asynQuery', async function(ctx, next){
    //参考上面Promise使用,声明同步等待一个返回Promise对象的函数。
    var data = await prunSql('SELECT * FROM COMPANY;');
    ctx.body = JSON.stringify(data)
});

这是一个新的接口, 跟其他接口不一样的就是,它处理请求的方法是用async声明的异步函数。

我们需要改造runSql函数

const prunSql = function(sql){
    console.log('will run sql:', sql);
    return new Promise(function(resolve, reject){
        console.log('asyn run sql: ', sql);
        db.query(sql, function(error, result, fields){
            if(error){
                console.log('[%s] asyn error:', error);
                reject(error);
            }else{
                console.log('asyn result:', result);
                resolve(result);
            }
        });
    });
};

这就是改造好的prunSql,这里用了resolve函数把数据库查询结果传递出去。

这样在使用Promise的then可以获取到异步查询结果。

或者在一个异步响应的方法内await Promise对象,等待查询返回值。

目录
相关文章
|
24天前
|
关系型数据库 数据库 Docker
Docker Compose 实战指南:多容器应用的一站式部署解决方案
大家好,我是D枫。随着容器化普及,单个Docker已难满足复杂应用需求。Docker Compose通过一个YAML文件定义多容器服务,实现一键启动、停止与配置管理,彻底解决环境不一致、操作繁琐和依赖混乱问题。本文带你深入理解其核心原理,实战搭建Flask+MySQL应用,掌握高效开发利器。
263 1
|
存储 算法 定位技术
每个系统都在用的appid、appkey、appsecret都是什么意思?
每个系统都在用的appid、appkey、appsecret都是什么意思?
12873 0
|
UED 开发者
鸿蒙next版开发:ArkTS组件通用属性(边框设置)
在HarmonyOS 5.0中,ArkTS提供了丰富的边框设置属性,允许开发者自定义组件的边框样式,提升应用的视觉效果和用户体验。本文详细解读了border属性的使用方法,并提供了示例代码,展示了如何设置不同边的边框宽度、颜色、圆角和样式。边框设置在UI开发中具有重要作用,如区分组件、强调重要元素和美化界面。
1185 6
|
编解码 Ubuntu 算法
Ubuntu桌面图标指南:一文了解如果设置ubuntu 软件图标
Ubuntu桌面图标指南:一文了解如果设置ubuntu 软件图标
3656 0
|
机器学习/深度学习 前端开发 JavaScript
WebAssembly:让前端性能突破极限的秘密武器
WebAssembly(简称 WASM)作为前端开发的性能加速器,能够让代码像 C++ 一样在浏览器中高速运行,突破了 JavaScript 的性能瓶颈。本文详细介绍了 WebAssembly 的概念、工作原理以及其在前端性能提升中的关键作用。通过与 JavaScript 的配合,WASM 让复杂运算如图像处理、3D 渲染、机器学习等在浏览器中流畅运行。文章还探讨了如何逐步集成 WASM,展示其在网页游戏、高计算任务中的实际应用。WebAssembly 为前端开发者提供了新的可能性,是提升网页性能、优化用户体验的关键工具。
5935 2
WebAssembly:让前端性能突破极限的秘密武器
|
Java 数据库连接 数据库
Spring基础3——AOP,事务管理
AOP简介、入门案例、工作流程、切入点表达式、环绕通知、通知获取参数或返回值或异常、事务管理
Spring基础3——AOP,事务管理
|
Shell Linux
在linux shell脚本中root切换到普通用户执行脚本或命令的方法
在linux shell脚本中root切换到普通用户执行脚本或命令的方法
343 1
|
SQL 安全 数据库
基于SQL Server事务日志的数据库恢复技术及实战代码详解
基于事务日志的数据库恢复技术是SQL Server中一个非常强大的功能,它能够帮助数据库管理员在数据丢失或损坏的情况下,有效地恢复数据。通过定期备份数据库和事务日志,并在需要时按照正确的步骤恢复,可以最大限度地减少数据丢失的风险。需要注意的是,恢复数据是一个需要谨慎操作的过程,建议在执行恢复操作之前,详细了解相关的操作步骤和注意事项,以确保数据的安全和完整。
651 0