微信小程序云函数NodeJs如何等待两次异步操作后返回数据给前端


1.引入

最近在搞小程序,采用的是微信云开发云函数作为后端,云函数是nodejs开发,但是因为不是很会nodejs,导致遇到一个印象深刻的bug与知识点,在此记录下来。
知识点比较浅显,大佬看了的话见笑了,这里更多是做个笔记

2.需求举例

集合中有category与items,如下
category
在这里插入图片描述
items
在这里插入图片描述
需要通过用户输入的cname字段找出属于此类的项,如上:通过用户输入的美食找出宫保鸡丁、回锅肉、鱼香肉丝返回给前端。

3.错误例子

  • 代码

前端
index.wxml

<view class="btnview">
  <button type="primary" bindtap="callFunc">获取美食类别下的美食</button>
</view>

index.js

Page({
  callFunc:function(){
    wx.cloud.callFunction({
      name: 'quickstartFunctions',
      data: {
        type: 'index/index',
        cname:'美食'
      }
    }).then((res) => {
      console.log(res)
    })
  }
})

云函数

const cloud = require('wx-server-sdk');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
});
const db = cloud.database();
/*
1.通过 cname参数查询category集合中的cid
2.再通过获取的cid查询items下属于该类别的项
3.返回获取该类别的项
*/
exports.main = async (event, context) => {
  var cname = event.cname;
  return await db.collection('category').where({
    cname:cname
  }).get().then(res=>{
    console.log(res)
    db.collection('items').where({
      cid:res.data[0]._id
    }).get().then(res=>{
      console.log(res)
      return res // 返回查找所属cname的项
    });
  });
};
  • 运行结果

云函数:
在这里插入图片描述
前端:
在这里插入图片描述
通过前端的输出发现,虽然云函数查找到了所属美食的项并且写了return这查找的列表代码,但是前端输出的确实undefined,经过排查,发现是云函数的代码问题

4.分析错误

db.collection…查询数据库是异步操作,虽然如上代码云函数前有return await,但是这里是两个db操作,发生了两次异步,而只await了一次
在这里插入图片描述
await只会等待红色框的异步操作,而青色框内的异步操作则不会等待,程序运行到青色的db时会跳过直接运行接下来的代码,而接下来没有代码了,所以会直接返回,而不会等待青色框内的异步return结果,所以前端得到的结果是undefined

5.尝试解决方法

既然不会等待青色框的异步,那么我想着在db前加上await,结果是代码编译报错,这样的写法是错误的
在这里插入图片描述

6.解决方法、代码及结果

  1. 解决方法,在CSDN网站搜索相关知识点后,得知await只能在声明了async的function中才有效,那么只好用function封装一下或者在then的作用域内用async声明才可以使用await
  2. 代码
    方式一:另写一个function
const cloud = require('wx-server-sdk');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
});
const db = cloud.database();
/*
1.通过 cname参数查询category集合中的cid
2.再通过获取的cid查询items下属于该类别的项
3.返回获取该类别的项
*/
exports.main = async (event, context) => {
  var cname = event.cname;
  return await 
  db.collection('category').where({
    cname:cname
  }).get().then(res=>{
    console.log(res)
    return getItems(res)
  });
};
// await 只能用在声明了async的函数中
async function getItems(res){
  return await db.collection('items').where({
    cid:res.data[0]._id
  }).get().then(res=>{
    console.log(res)
    return res // 返回查找所属cname的项
  });
}

方式二:在then的作用域内用async声明

const cloud = require('wx-server-sdk');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
});
const db = cloud.database();
/*
1.通过 cname参数查询category集合中的cid
2.再通过获取的cid查询items下属于该类别的项
3.返回获取该类别的项
*/
exports.main = async (event, context) => {
  var cname = event.cname;
  return await 
  db.collection('category').where({
    cname:cname
  }).get().then(async(res)=>{ // 声明async
    console.log(res)
    // 这样写法,代码较紧凑和乱
    return await db.collection('items').where({
	    cid:res.data[0]._id
	  }).get().then(res=>{
	    console.log(res)
	    return res // 返回查找所属cname的项
	  });
  });
};

3.这样写后,前端能得到正确数据了
在这里插入图片描述

6.后记

  1. 这是我个人的写法,可能不太正确,如果有更好的方法欢迎指导
  2. 简单的笔记
    个人认为
    声明了async的function,在里面可以执行同步或异步代码,异步代码可以用await变成同步代码.
    await只能使用在async声明的函数里,不能使用在普通函数里。

参考BLOG链接:CSDNBLog:async、await个人使用理解

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值