我的知识记录分享

我的知识记录分享

4.3 云函数的调用与返回

2020-10-9 糖果小宝 小程序学习

调用云函数的方式有很多,如小程序端、管理端调用、定时触发器、HTTP触发、云函数等,不同的方式存在哪些差异?我们知道调用云开发资源可以通过小程序端SDK和云函数端的SDK,这两种方式有什么不同?在调用云函数的过程中,我们需要注意哪些问题?

4.3.1 云函数的传参与返回

在小程序端我们可以使用wx.cloud.callFunction接口调用云函数并向云函数传递参数。参数的来源和参数的数据类型有很多,我们已经了解参数的传递情况呢?

比如在小程序function页面的function.js里输入以下代码,我们知道页面js的data对象常用于事件处理的过渡,通过数据渲染可以控制小程序的页面;这里我们将data对象里面的数据以参数的形式传递给云函数:

Page({ data:{ rectangle:{ width:22, height:33,
		}
	},
	onLoad(){ this.getData()
	},
	getData(){
		wx.cloud.callFunction({ name:"invoke", data:{ rectangle:this.data.rectangle
			}
		}).then(res=>{ console.log("res对象",res)
		})
	}
});

在这里调用的云函数是invoke,那invoke云函数应该如何接收小程序端传递的参数呢?在不熟悉或开发时建议可以先通过打印了解参数传递的状态或参数的数据类型。使用开发者工具新建一个云函数,名称如invoke,然后输入以下代码并部署上传到云端:

 
const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main = async (event, context) => { console.log("event对象",event) }

通过invoke云函数的日志可以了解到event对象里参数的情况,然后再使用解构赋值将参数取出,如:

 
const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main = async (event, context) => { console.log("event对象",event) const {rectangle:{width,height}} = event return { circum:(width+height)*2, area:width*height } }

而在小程序端如果需要对云函数return返回的数据进一步处理,既可以使用callback回调函数的方式,也可以使用Promise的方式,还可以将获取的数据赋值给变量,而要对返回的数据有更清晰的了解,也通过需要在开发时多打印或调试,而不能靠蒙或猜:

 
async getData(){ const result = await wx.cloud.callFunction({ name:"invoke", data:{ rectangle:this.data.rectangle } }) console.log("result对象",result) const {result:{circum,area}} = result //注意这里有两个result,有着不同的含义,注意区分,使用时也可以采用不同的变量名 console.log({circum,area}) this.setData({ circum,area }) }

4.3.2 不同调用方式下的event与context

云函数的调用方式很多,不同的调用方式传入给云函数的参数对象也会有所不同。每个云函数的传入参数有两个对象:event对象和context对象。其中event对象指的是SDK触发云函数时传入的事件;而context对象则包含此调用的调用信息和函数的运行状态。采用不同的调用方式以及调用链条,返回的event对象和event对象的值是不一样的。

1、通过打印了解event与context对象

将invoke云函数的index.js代码修改为如下,并将文件更新上传到云端,接下来我们会通过多种方式来调用这个云函数,只要云函数被触发,我们就可以在日志里查看到打印的event和context对象到底有何不同:

 
const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main = async (event, context) => { console.log("event对象",event) console.log("context对象",context) }

在开发者工具调试器的console控制台调用云函数可以直接在控制台输入以下命令:

wx.cloud.callFunction({name:"add"}).then(res=>{console.log(res)})

我们也可以把上面的代码写在小程序首页如function.js的onLoad生命周期函数里,通过开发者工具的调试以及真机调试来调用云函数;而要在管理端调用云函数,可以打开云开发控制台,对该云函数进行云端测试。打印的event对象和context对象大致如下:

 
event对象 { //通过管理端调用云函数,如云端测试,event对象是没有userInfo的 userInfo:{ appId: 'wxda99ae4531b57046', openId: 'oUL-m5FuRmuVmxvbYOGuXbuEDsn8' } } context对象 { memory_limit_in_mb: 256, time_limit_in_ms: 3000, request_id: 'f7e616b2-fb4d-11ea-a839-52540064cc91', environment:'',//部分值可以通过getWXContext()获取,后面会介绍 environ:'',//部分值可以通过getWXContext()获取,后面会介绍 function_version: '$LATEST', function_name: 'invoke', namespace: 'xly-xrlur', tencentcloud_region: '', tencentcloud_appid: '1300446086', tencentcloud_uin: '100011753314' }

通过管理端调用云函数,无论是event对象还是context对象都是获取不到用户的openId、appId、unionid等信息的,也就是说通过管理端调用云函数是获取不到用户的登录态信息的。

2、getWXContext()

context对象里的environment、environ过于复杂,云开发有专门的接口cloud.getWXContext()可以获取到其中比较关键的信息,比如会返回小程序用户的openid、小程序appid、小程序用户的unionid等。

 
const cloud = require('wx-server-sdk') cloud.init({ env:cloud.DYNAMIC_CURRENT_ENV }) exports.main = async (event, context) => { const wxContext = cloud.getWXContext() console.log("wxContext对象",wxContext) }

和context对象一样,通过不同的调用方式,cloud.getWXContext()返回的值也会有所不同,

 
{ UNIONID: '',//用户的unionid,只有绑定了开放平台,且在用户授权(允许获取用户信息、关注、支付)的情况下才有 CLIENTIP: '10.22.213.71',//小程序客户端的网络IPv4地址 CLIENTIPV6: '::ffff:10.22.213.71',//小程序客户端的网络IPv6地址 APPID: 'wxda99....b57046',//小程序AppID OPENID: 'oUL-m5FuRmuVmxvbYOGuXbuEDsn8',//小程序用户的openid ENV: 'xly-xrlur', SOURCE: 'wx_devtools' //云函数调用来源,wx_devtools开发者工具调用,wx_client小程序调用,wx_http HTTP API 调用,wx_unknown 微信未知来源调用等 }

3、登录态与openid的获取

由于context是调用云函数时传入的上下文对象,而getWXContext与context对象有关,因此调用cloud.getWXContext()接口时,不能在exports.main外。同时,openId、AppId、unionid等用户信息只有在小程序端调用时才能获取到。

 
const cloud = require('wx-server-sdk') cloud.init({ env:cloud.DYNAMIC_CURRENT_ENV }) exports.main = async (event, context) => { const wxContext = cloud.getWXContext() const {OPENID} = wxContext return OPENID }

不过值得一提的是,尽管我们在小程序端非常需要用户的openid这个值,但是更多的时候,我们没有必要浪费云函数资源来获取openid的值。比如,不少人在使用云开发时,都会先调用云函数返回用户的openid,然后在用户CRUD云数据库时云开发资源时传入获取到的openid。我们可以在用户读写云开发使用.where({_openid:'{openid}'})以及借助安全规则的方式,这样就不需要先获取用户的openid的具体值。

4.3.3 main函数与return

云函数主要执行的是index.js中的main方法,因此要确保云函数中含有main函数,而return除了会返回数据给云函数的调用方,同时也会终结云函数的执行。

在main函数的其他函数里要注意一些写法,比如云函数是支持async/await的,不过在await再用then链式写法,而没有返回值,那data对象就会是undefined,而云函数调用的结果为空

const cloud = require('wx-server-sdk')
cloud.init({ env:cloud.DYNAMIC_CURRENT_ENV 
}) const db = cloud.database() const _ = db.command
exports.main = async(event, context) => { const data = await db.collection("china")
	.where({ _id:_.exists(true)
	})
	.get()
	.then(res=>{ console.log("then打印的结果",res)//会返回数据库查询的结果 }) console.log("data对象",data)//data为undefined return data //返回的data为空 }

面对这个问题,有两个解决方法,一是不要使用then链式,二是在then方法里return一个返回值,更加土建采用第一种方式。

//方法一,不使用then链式 const data = await db.collection("china")
.where({ _id:_.exists(true)
})
.get() //方法二,使用return返回一个data const data = await db.collection("china")
.where({ _id:_.exists(true)
})
.get()
.then(res=>{ console.log("then打印的结果",res) return res
}) console.log("data对象",data)

注意方法二里尽管我们在then方法里使用了return,但是return只是终结数据库请求,以及返回数据给data,并不会中断云函数的执行,也不会把res的数据返回给main。因此,下面的方法调用云函数时也的返回值也会是null:

await db.collection("china") //const data = await db.collection("china") 同样也不会给main返回任何数据 .where({ _id:_.exists(true)
})
.get()
.then(res=>{ console.log("then打印的结果",res) return res
})

发表评论: