如何创建小程序云函数
- 右键点击
cloudFunctions
,然后点击新建Node.js云函数
,之后输入云函数名称就可以了
- 云函数创建好以后,假设我们创建的云函数名字叫
test
,那么在test文件夹下会有3个文件。其中index.js是云函数的入口文件。
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
}
}
- 云函数的传入参数有两个,一个是 event 对象,一个是 context 对象。event 指的是触发云函数的事件,
当小程序端调用云函数时
,event 就是小程序端调用云函数时传入的参数
,外加后端自动注入的小程序用户的 openid 和小程序的 appid。context 对象包含了此处调用的调用信息
和运行状态
,可以用它来了解服务运行的情况
- 我们修改一下模板的返回值;
// 本段代码的意思是将传入的 a 和 b 相加并作为 sum 字段返回给调用端。
exports.main = async(event,context) => {
return {
sum:event.a+event.b
}
}
- 在小程序中调用这个云函数前,我们还需要先
将该云函数部署到云端
。在云函数目录上右键,在右键菜单中,我们可以将云函数整体打包上传并部署到线上环境中。
调用云函数
- 部署完成后,我们可以在小程序中调用该云函数:
// 回调函数风格的
wx.cloud.callFunction({
// 云函数名称
name: 'add',
// 传给云函数的参数
data: {
a: 1,
b: 2,
},
success: function(res) {
console.log(res.result.sum) // 3
},
fail: console.error
})
// promise风格的调用
wx.cloud.callFunction({
// 云函数名称
name: 'add',
// 传给云函数的参数
data: {
a: 1,
b: 2,
},
})
.then(res => {
console.log(res.result) // 3
})
.catch(console.error)
如何在云函数中向服务器发送请求?
- 我们要借助第三方的库来发送请求,比如
request
、request-promise
、axios
等。我们这里用axios
。既然要用第三方库,我们首先要安装这个库(前提是我们电脑已经安装了 node,可以进行NPM包管理)
。这个库安装的位置要注意一下。我们鼠标右键点击test云函数文件夹。然后选择在在外部终端窗口中打开
,在终端中输入安装命令npm i axios -S
- 之后在云函数的index.js里引入 axios
// 引入axios
const axios = require('axios')
// 下边是axios的一些用法
// get请求
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.then(function () {
// always executed
});
// Want to use async/await? Add the `async` keyword to your outer function/method.
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
// post请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// 执行多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});
// 可以通过将相关配置传递给axios来发出请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
});
- axios在云函数中的用法
// 云函数初始化
const cloud = require('wx-server-sdk')
cloud.init()
// 引入axios
const axios = require('axios')
// 请求接口
const URL = 'http://xxxxx/xxx'
// 云函数入口函数
exports.main = async (event, context) => {
const result = await axios.get(URL).then((res) => {
return res
})
console.log(result)
}
需要注意的是,云函数是属于后端代码,当我们在云函数中console.log()的时候,是不会打印到小程序开发工具的调试器里的。而是打印到云函数的
调用日志里
,(调试器打印的信息,都是前端的信息。)
-
当云函数写好以后,还需要上传云函数,方法就是右键点击云函数,然后点击上传并部署;尽量不要选择所有文件,因为这个代码是上传到云端的,就算我们不上传node_modules文件夹,也会帮我们下载好相关的依赖。
- 然后点击云开发到
云控制台
,我们可以云端测试一下云函数
- 有的时候,我们刚修改了云函数,还没有来得及上传,这个时候,我们也可以本地调试一下云函数。右键点击云函数,然后选项
开启云函数本地调试
。然后选择要调试的云函数,之后勾选本地调试。勾选之后回报错。需要打开终端,安装一下wx-server-sdk
,命令是npm install wx-server-sdk
- 本地调试开启以后,我们可以选择
模拟器触发
或者手动触发
。区别是模拟器触发是我们在某个页面上通过点击某个触发云函数的条件去触发,比如按钮。而手动触发是在控制台上手动点击调用
如何在云函数中操作数据库?
- 首先我们可以在云控制台数据库,手动创建一个
集合
- 然后在云函数里,引入数据库
// 云函数初始化
const cloud = require('wx-server-sdk')
cloud.init()
// 云数纪库引入
const db = cloud.database()
// 引入axios
const axios = require('axios')
- 然后操控数据库,比如我们把接口返回的数据存入数据库
// 云函数初始化
const cloud = require('wx-server-sdk')
cloud.init()
// 云数纪库引入
const db = cloud.database()
// 引入axios
const axios = require('axios')
// 请求接口
const URL = 'http://xxxxx/xxx'
// 云函数入口函数
exports.main = async (event, context) => {
const result = await axios.get(URL).then((res) => {
return res
})
for (let i = 0, len = result.length; i < len; i++) {
// 假设我们创建的集合的名字叫playlist
await db.collection('playlist').add({
data:{
// 通过扩展运算符,把返回数据的每个字段都插入集合
...result,
// 新增一个创建时间字段,值取的是服务器的时间,方便前端根据时间进行排序显示
createTime:db.serverDate()
}
}).then((res) => {
console.log('插入成功')
}).catch((err)=> {
console.log('插入失败')
})
}
}
// 在for循环遍历的时候,每一次插入数据库都是一个异步的过程,所以加了一个await,这样确保一个插入成功后,再去插入下一个。
- 上边的插入数据库的方式是一条一条的插入,如果数组里的数据很多,那么就需要操作多次数据库。这个时候我们可以用
批量插入
的方式来一次性插入,只需要操作一次数据库。data作为add方法的参数对象里的属性,不单单可以跟一个对象,还可以跟一个数组
exports.main = async (event, context) => {
const result = await axios.get(URL).then((res) => {
return res
})
//为防止扩展运算符报错,要先判断数组是否为空
if (result.length > 0) {
await db.collection('playlist').add({
// ... 扩展运算符
data: [...result]
}).then((res) => {
console.log('插入成功')
}).catch((err) => {
console.log('插入失败')
})
}
}
注意:云函数新建和修改后,一定要上传,否则是用不了的。
有时候,我们按照一定的频率请求数据,然后插入数据库,这个时候会面临一个问题,那就是请求的数据,跟数据库里的有重复的,那么就需要我们把重复的数据剔除,只插入数据库没有的数据。该怎么操作呢?我们就以数据库里的歌单为例子
const playlistCollection = db.collection('playlist')
const list = await playlistCollection .get() // 获取到云数据库里的playlist集合
const newData = [] // 声明一个空数组,用来装对比过后不重复的数据
// 假设 playlist 是我们通过接口获取的歌单数据
for(let i=0,len = playlist.length;i<len;i++){
let flag = true // 声明一个标识符,用来标记该条数据是否有重复 true是不重复
for(let j=0,len = list.data.length;j<len;j++){
if(playlist[i].id === list.data[j].id){
flag = false
break
}
}
// 如果flag为ture证明数据库里的数据没有跟playlist[i]这条数据重复的,就放到数组里
if(flag){
newData.push(playlist[i])
}
//然后我们再遍历newData数组,把数据插入数据库playlist集合
for(let i = 0,len = newData.length;i < len;i ++){
await playlistCollection.add({
data:{
...newData[i],
createTime:db.serverDate()
}
}).then((res) => {
console.log('插入成功')
}).catch((err) => {
console.log('插入失败')
})
}
}
云函数中读取云数据库的数据,一次最多只能读取100条,小程序端读取云数据库数据,一次最多只能读20条。如果数据库某集合中的数据超过了100条,我们该怎么突破最大读取数的限制呢?
- 我们还以刚才的歌单集合为例,假设,我们的歌单集合中,有280条数据。而我们每次最多只能读取100条。那么我们要读取3次才可以读取完毕。
const MAX_LIMIT = 100 // 最大柯读取数
const countResult = await playlistCollection.count() // count()方法用来获取集合里数据的条数,返回的是一个对象
const total = countResult.total
const batchTimes = Math.ceil(total / MAX_LIMIT ) // 次数
const tasks = [] // 每次从数据库读取数据,都是一个异步的任务,所以声明一个数组来装这些异步任务。方便后边使用promise.all
for(let i=0;i<batchTimes;i++){
//limit()方法,每次查询数据的上限
// skip()方法,从指定序列后的结果开始返回。
// 读取数据库,一开始肯定是从第0条数据开始的,然后读取100条,第二次是从第100条开始,依此类推
const promise = playlistCollection.skip(i*MAX_LIMIT ).limit(MAX_LIMIT).get()
tasks.push(promise )
}
// 声明一个list对象,之所以有data属性,是为了对应数据库返回的数据的格式。
let list = {
data:[]
}
if(tasks.length > 0){
// Promise.all(tasks)) 等待所有异步任务完成的过程,也是一个异步的过程,所以加await
// reduce()累加数组里的元素,acc参数代表前一个,cur代表当前一个元素
list = (await Promise.all(tasks)).reduce((acc,cur) => {
return {
data: acc.data.concat(cur.data)
}
})
}
定时触发云函数
- 在需要添加触发器的云函数目录下新建文件 config.json,格式如下:
{
// triggers 字段是触发器数组,目前仅支持一个触发器,即数组只能填写一个,不可添加多个
"triggers": [
{
// name: 触发器的名字,规则见下方说明
"name": "myTrigger",
// type: 触发器类型,目前仅支持 timer (即 定时触发器)
"type": "timer",
// config: 触发器配置,在定时触发器下,config 格式为 cron 表达式,规则见下方说明
"config": "0 0 2 1 * * *"
}
]
}
-
cron表达式示例
- 当我们定时触发配置写好以后,我们还需要上传触发器。右键点击当前云函数,然后选择
上传触发器
。只有上传触发器后,才会按照我们设置的时间自动执行云函数
- 有的时候,云函数逻辑比较复杂,网络不好的情况下,云函数默认的超时时间3秒,可能满足不了我们的需求,这个时候,我们可以自己设置云函数的超时时间。云函数列表中 点击
版本与配置
-配置
-高级配置
如何在云函数中,分页获取云数据库数据,并按照创建时间逆序排列呢?
exports.main = async (event, context) => {
return await db.collection('playlist')
.skip(event.start)
.limit(event.count)
.orderBy('createTime','desc')
.get()
.then((res) => {
return res
})
}
如何在小程序端调用云函数,并获取到我们读取的分页数据呢?
_getPlayList(){
wx.showLoading({
title: '加载中',
})
wx.cloud.callFunction({
name:'music',
// data是传递给云函数的数据,云函数可以通过event获取到这几个参数
data:{
start:this.data.playlist.length,
count:MAX_LIMIT,
$url:'playlist'
}
}).then((res) => {
this.setData({
playlist:this.data.playlist.concat(res.result.data)
})
wx.stopPullDownRefresh()
wx.hideLoading()
})
},