简介
云函数是运行在云端的JavaScript代码,和普通的Node.js开发一样,熟悉Node.js的开发者可以直接上手。
如下是将传入的两个参数求和并返回客户端的云函数代码示例:
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
return {
sum:event.a + event.b
}
}
云函数的传入参数有两个,一个是event对象,一个是context对象。event指的是触发云函数的事件,当客户端调用云函数时,event就是客户端调用云函数时传入的参数。context对象包含了此处调用的调用信息和运行状态,可以用它来了解服务运行的情况。uniCloud会自动将客户端的操作系统(os)、运行平台(platform)、应用信息(appid)等注入context中,开发者可通过context获取每次调用的上下文,如下是一个示例:
'use strict';
exports.main = async (event, context) => {
//event为客户端上传的参数
...
//context中可获取客户端调用的上下文
let os = context.OS //客户端操作系统,返回值:android、ios 等
let platform = context.PLATFORM //运行平台,返回值为 mp-weixin、app-plus等
let appid = context.APPID // manifest.json中配置的appid
let clientIP = context.CLIENTIP // 客户端ip信息
let clientUA = context.CLIENTUA // 客户端user-agent
... //其它业务代码
}
关于CLIENTIP、CLIENTUA
通过管理端调用云函数(云函数上传并运行、腾讯云开发调试期间),使用腾讯云时想临时调试UA、IP等可以通过自行初始化uniCloud的方式(同时连多服务空间)传入debugFunction: false来实现客户端直连调用,需要注意的是此时控制台将不会打印云函数日志。
云函数中如果要使用其他服务(比如MySQL数据库、Redis等),可以按照Node.js的写法即可。
注意事项
服务商为阿里云时,暂不可使用相对路径读取文件(比如fs.readFileSync('./info.txt')),可以使用绝对路径fs.readFileSync(path.resolve(__dirname,'./info.txt'))
访问数据库
云函数中支持访问本服务空间下的数据库,调用方式详见规范
访问HTTP服务
uniCloud提供了uniCloud.httpclient供开发者使用。无需额外依赖,就可以请求任何HTTP和HTTPS协议的 Web 服务。uniCloud.httpclient返回的是一个urllib实例。
uniCloud.httpclient.request(URL, requestOptions)
requestOptions参数说明:https://uniapp.dcloud.io/uniCloud/cf-functions
示例代码
const res = await uniCloud.httpclient.request(apiUrl, {
method: 'POST',
data: {
test: 'testValue'
},
dataType: 'json'
})
console.log(res)
使用npm
在云函数中我们可以引入第三方依赖来帮助我们更快的开发。云函数的运行环境是Node.js,因此我们可以使用npm安装第三方依赖。
注意:鉴于阿里云的限制,目前仅支持全量上传云函数(整个
node_modules文件夹全部上传),因此尽量精简依赖,否则可能会每次上传时间很慢,影响开发体验注意:目前每个云函数上传包大小限制为
10M
客户端调用云函数
前端代码(H5前端、App、小程序),不再执行uni.request联网,而是通过uniCloud.callFunction调用云函数,callFunction定义如下:
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
String |
是 | 云函数名称 |
data |
Object |
否 | 客户端需要传递的参数 |
响应参数
| 字段 | 类型 | 说明 |
|---|---|---|
result |
Object |
云函数执行结果 |
requestId |
String |
请求序列号,用于错误排查 |
示例代码
// promise方式
uniCloud.callFunction({
name: 'test',
data: { a: 1 }
})
.then(res => {});
// callback方式
uniCloud.callFunction({
name: 'test',
data: { a: 1 },
success(){},
fail(){},
complete(){}
});
云函数中调用云函数
用法同客户端调用云函数,不支持callback形式
请求参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name |
String |
是 | 云函数名称 |
data |
Object |
否 | 云函数参数 |
响应参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
errCode |
String |
否 | 状态码,操作成功则不返回 |
errMsg |
String |
否 | 错误描述 |
result |
Object |
否 | 云函数执行结果 |
requestId |
String |
否 | 请求序列号,用于错误排查 |
示例代码
let callFunctionResult = await uniCloud.callFunction({
name: "test",
data: { a: 1 }
})
注意事项
云函数的启动模式(冷启动、热启动)
基于云函数按需执行的特点,函数在不被触发的时候,计算资源是不被激活的。当一个云函数初次被触发时,其完整过程如下:
- 实例化计算实例
- 加载函数代码
- 启动 node
- 执行代码
函数被调用时,执行这些完整步骤的过程一般称作冷启动,冷启动的耗时长于热启动,一般在一秒出头。
而如果函数实例和执行进程都被复用的情况下一般被定义为热启动,热启动没有性能问题。
如果一个云函数实例长时间没有被再次调用,则该计算实例会被回收;后续再次调用该云函数时,就会再次触发云函数的冷启动。
不同云厂商的函数实例回收时间,以及优化冷启动的建议,参考
因为存在冷热启动的差异,云函数中的全局变量就可能出现每次不一样的情况。
以如下代码为例,count作为全局变量,当多次调用该云函数时,可能会出现变量累加的情况(实例未复用时,每次返回0,若实例被复用,则可能返回1、2、3等各种意外情况)
let count = 0;
module.exports = async (event) => {
return count++
//此示例为错误示例
//云函数实例未复用时,每次返回0
//若实例被复用,则可能返回1、2、3等各种意外情况
}
临时存储空间
云函数是运行在云端的代码,运行环境由云服务器弹性调配,这是和传统Node.js应用很大的区别。
换言之,云函数每次执行的宿主环境(可简单理解为虚拟机或服务器硬件)可能相同,也可能不同,因此传统Node.js开发中将部分信息存储本地硬盘或内存的方案就不再适合,建议通过云数据库或云存储的方案替代。
云函数中的异步行为
书写云函数时应注意async、await的使用,Node.js有内置模块util可以将符合error-first形式callback的函数转换为promise形式,详情参考,比如以下示例:
const {
promisify
} = require('util')
let testCallback = {
value: 'testCallbackValue',
echo: function(num, callback) {
setTimeout(() => {
// 第一个参数为error,第二个为返回值
callback(null, `${this.value}:${num}`)
}, 2000)
}
}
exports.main = async function() {
// num=2,不传入callback参数,callback会自动作为回调函数处理
let val = await promisify(testCallback.echo).call(testCallback, 2)
console.log(val)
return val
}
如果想在云函数内使用回调形式可以让云函数返回一个promise,如以下示例:
exports.main = async function() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('some return value')
}, 1000)
})
}
其它
- 云函数中使用的时区是
UTC+0,而不是UTC+8,在云函数中使用时间时需特别注意 - 使用阿里云作为服务商时,暂时无法使用相对路径读取文件,如:
fs.readFileSync('./info'),可以替换为fs.readFileSync(path.resolve(__dirname,'./info'))




