我的知识记录分享
用编程来写项目,就像是在做一系列精密而复杂的实验,你不能总是劳烦他人帮你解决问题,而是要掌握调试、测试、日志打印等手段来检查每一步操作是否正确,你需要学会查看报错信息,如果不正确问题在哪、出了什么问题,你才能有针对性的去搜索,有针对性的去咨询他人。
为了能够让大家更加清楚的了解:完整操作一个云函数的流程以及本地调试与云端测试的重要性,我们以长方形的边长(a、b)求周长、面积这个简单的数学公式为例。
首先我们右键点击云函数根目录(也就是cloudfunctions文件夹),选择新建Node.js云函数,函数名为长方形的英文rectangle,然后打开index.js,将代码修改为如下:
const cloud = require('wx-server-sdk')
cloud.init({ env:cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => { const {width,height} = event console.log("长方形的周长与面积",[(width+height)*2,width*height]) return { circum:(width+height)*2, area:width*height
}
}
circum是周长,周长=(宽度width+高度height)✖️2;area是面积,面积=宽度width✖️高度height,只要我们之后把长方形的参数宽度width和高度height传递进来(之后我们会来讲怎么传),即可获得长方形的周长和面积。
建好云函数之后,我们右键点击云函数目录,也就是rectangle文件夹,选择在终端中打开,使用npm install来安装依赖。
npm install
对于一个复杂的云函数,我们最好是先在本地测试一下云函数是否正确,然后再部署上传到云端。那如何本地测试呢?右键点击云函数目录,也就是rectangle文件夹,选择本地调试(这种方式进入本地调试会默认开启rectangle的本地调试)。
我们可以根据情况来选择手动触发和模拟器触发,使用手动触发需要我们在本地调试输入参数之后,点击调用:
我们给参数宽度width和高度height赋值(注意传递的是JSON格式,最后一个参数结尾不能有逗号,),比如赋值为3和7:
{ "width": 3, "height":7 }
然后点击调用,如果显示函数执行成功(注意仍然是在调试的console标签),并得到周长circum和面积area的结果分别为20、21,那证明云函数没有写错。
当开启了本地调试,我们在开发者工具调试器的console控制台(非本地调试的console标签页)调用云函数时也会调用本地的云函数。在本地调试窗口无论是选择手动触发、模拟器触发亦或是通过其他云函数来调用云函数,取决于你的云函数的调用方式,比如如果云函数调用是在页面的生命周期函数里调用,我们本地调试时就可以使用模拟器触发。
打开云开发控制台的云函数标签页,找到rectangle云函数,点击云端测试,同样我们给参数赋值,将以下代码进行修改,比如给宽度width赋值为4,高度height赋值为7,即代码修改为:
{ "width": 4, "height": 7 }
然后点击运行测试,(会等一段时间),再来查看测试的结果,如果返回结果如下,则表示在云端的云函数可以正常调用:
{"circum":22,"area":28}
云函数的调用采用事件触发模型,小程序端的调用、本地调试和云端测试都会触发云函数的调用事件,其中本地调试调用的不是云端的云函数,而是小程序本地的云函数;而在云端测试调用云函数的结果是可以在云开发控制台云函数的日志里查看到的。
上传到云端的云函数,我们还可以通过云开发的网页控制台(登录方式见第一章【云开发资源的管理】的介绍)在线修改代码。通过在线编辑,我们不仅可以检查代码是否更新成功,还可以脱离微信开发者工具、Cloudbase CLI等来临时修改代码。
当调用云函数时,在开发者工具调试器里并没有看到console.log打印的结果,我们可以打开云开发控制台–云函数–日志,按函数名筛选,选择rectangle云函数,可以看到云函数被调用的日志记录了(日志也可以在云开发网页控制台查看)。
在云函数日志里,我们除了可以在返回结果里看到return返回的对象,还可以在日志里查看到云函数执行的时间点(使用的是服务端时间,时区为UTC+0),以及云函数里使用console.log打印的日志。
云函数调试的时候,不能只依赖小程序端的wx.cloud.callFunction
使用return返回的报错,因为它只是反馈云函数的调用结果以及调用是否出现错误error,更多的还是要在云函数里使用console.log
打印云函数在执行过程中的一些日志情况。也就是说,return只会返回中断函数执行的一些报错,而比如函数是否获取到参数,参数是什么数据类型,以及是否包含你想要的预期值,这些都需要勤使用console.log来反馈。
在小程序端调用云函数时,我们经常会使用到return,return语句可以终止函数的执行并返回一个值给小程序端,因此很多人会依赖return返回的这个值来了解云函数是否获取到了最终想要的结果。对于复杂的云函数,仅仅只是使用return并不能精确定位到云函数在执行过程中哪里出错。
而小程序端的报错,只能显示云函数为什么没有等到执行return就中断了,比如以下案例集合名本为cloudbase,但是在书写的过程中,却不小心写错了:
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) => { return await db.collection("cloubase").where({ _id:_.exists(true)
}).get()
}
这种错误由于会中断云函数的执行,因此会被返回到小程序端,报错也会显示集合或记录不存在,截图如下:
当然出现这个报错,首先要检查你调用的集合与云数据库的集合名是否一致(或确实不存在这个集合),如果都没有问题,则需要检查云函数的初始化是否正确的选择了集合所在的云开发环境。
大多数情况下,可能云函数里并没有出现中断函数执行的错误error,但是return却并没有返回到预期的结果,比如前面介绍的rectangle云函数,我们可以在开发者工具的调试器console里调用云函数:
res=>
在调用时,我们忘记了传入参数,或者参数名写错了,或者由于异步的问题参数其实没有值等等原因,云函数可以正常执行,但是return的值却为result: {circum: null, area: null}
,对于这样的错误如果不通过日志,就很难反馈出来。
注意 错误(Error) 与 异常(Exception) 是完全不一样的,错误会中断JavaScript函数的执行,而异常不会导致JavaScript进程被终止,通过return只能返回错误而不能获取到异常,要获取云函数执行的异常需要通过
try..catch
的方式。
值得一提的是,return语句除了可以返回一个值给调用者外,它还会终结一个函数的执行。当return后面还有函数语句,开发者工具会提示这些代码为灰色,表明这些语句不会执行。
以上面的截图为例,第15行的console.log由于是在return语句的后面,所以是灰色的不会执行;不过整个云函数在第8行就被return中断了,整个函数最终只会返回width*height的值。
在return关键字和被返回的表达式之间不允许使用行终止符,也就是说return与要返回的表达式之间不能有换行,开发者工具的代码提示也会显示有错误。
在云函数中,return只能返回错误,而有些异常我们可以通过try..catch
来返回,try..catch
的语法如下。
try { // 代码... } catch (err) { // 错误捕获 }
也就是如果在try块中有任何一个语句或函数抛出异常,控制会立即转向catch子句。如果在try块中没有异常抛出,则会跳过catch子句。我们写的每一个云函数都建议采用try..catch
的方式来进行错误处理。
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) => { try{ const data = await db.collection("cloubase").where({ _id:_.exists(true)
}).get() return data
}catch(err){ return err
}
}
前面通过return获取不到的异常,通过try...catch
的方式就能获取到了,异常返回如下:
errCode: -502005 errMsg: "[ResourceNotFound] Db or Table not exist. Please check your request, but if the problem cannot be solved, contact us.;
不过对于一些异常,Node.js存在error对象的字段不支持遍历,所以序列化成字符串时会忽略所有的字段,比如下面的代码不仅集合不存在,连upData这个变量也没有声明,直接返回error显示的会为空:
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) => { try { const result =await db.collection('users').where(upData).get() return result
}catch (error) { //return error有时候返回不了一些异常,可以通过通过返回error的具体属性 // return { name: error.name, message: error.message, stack: error.stack } return error
}
}
我们可以通过返回error对象的name、message、stack的方式来获取异常,如catch子句里我们可以使用return { name: error.name, message: error.message, stack: error.stack }
,这样就可以返回报错了。
不过更加建议的方式是在做云函数错误处理时结合使用console.log或高级日志的方式来记录报错,因为即使采用了try...catch
的方式,还是有一些错误、异常无法被反馈,而console.log强大的调试测试能力却可以做到。
比如下面的一个云函数,需要我们在调用云函数时给云函数传入两个参数a
和b
,云函数会将获取到的参数相加并返回:
const cloud = require('wx-server-sdk')
cloud.init({ env:cloud.DYNAMIC_CURRENT_ENV
})
exports.main = async (event, context) => { try { const {a,b} = event const sum = a + b console.log("获取到的a,b,sum的值",[a,b,sum]) return sum
}catch (e) { console.log(e) return { name: error.name, message: error.message, stack: error.stack }
}
}
如果我们在调用云函数时忘记传入参数,比如在控制台输入以下代码,即使在用了try...catch
的情况下也是无法准确定位到错误的:
res=>
我们可以在try语句打印云函数参数获取的情况console.log("获取到的a,b,sum的值",[a,b,sum])
,在云函数的调用日志里面查看就能发现问题:
获取到的a,b,sum的值 [ undefined, undefined, NaN ]
当小程序发布之后,通过筛选“调用失败”只能获取到中断云函数执行的错误,而对于一些bug或异常,则需要通过云函数日志。但是云函数调用次数非常多,而console.log日志却没办法筛选,这个时候我们可以使用云开发提供的高级日志服务。高级日志服务实现日志采集和检索分析等功能,方便开发者通过日志快速的发现和定位问题。每条日志可最长存储30天,超过 30 天的日志将被自动清理。
在云函数日志里,我们可以看到云函数的执行时间、内存和内存消耗,比如Duration:5ms Memory:256MB MemUsage:35.218750M
,意思是整个云函数执行时间为5ms,当前云函数的内存为256MB,内存消耗为35.218750M。
云函数的执行时间和内存是一个非常关键的指标,比如云函数执行时间可以反映该云函数的性能,如果执行时间过长,比如超过500ms,云函数就应该尽可能优化一下;而同时云函数的计费也与执行时间和内存(也就是256M,非内存消耗)相关,云函数资源使用量 = 函数配置内存(256M) X 运行计费时长(5ms)。
调用云函数时,我们还可以在开发者工具调试面板的NetWork标签查看调用云函数的情况。
发表评论: