- 在scroll-view中使用input,input键盘弹出时,滚动页面,输入框内容会出现错位问题?
[图片][图片]
2020-05-26 - 开发工具展示了所有页面路径,怎么关掉?
[图片] 接手别人的原生微信小程序代码,开发工具里面,不知道怎么打印出的这些页面路径的,怎么才能关掉,也没搜索到日志,是不是有什么配置需要关掉,请各位大神指点
06-21 - scroll-view抖动问题
wxml: <scroll-view class='page-menu-body' style='height:{{menuHeight}}rpx;' scroll-y="true" scroll-top="{{menuScrolltop}}" bindscroll="menuScrollHandle" bindscrolltolower="menuScrollLoading" bindscrolltoupper="menuScrollToupper"> wxss : .page-menu-body { display: flex; /* height: 100%; */ width: 636rpx; z-index: 100; } menuHeight 是屏幕高。 下拉弹性页面的时候,跳动。而且,很多 用到scroll-view的地方都这样。 ios 下,Android 下会闪动。我发现论坛很多这个问题。没有解决方案?还是我们比较菜一下。经常遇到bug。腾讯大神遇不到
2018-08-10 - 边框 border设置1rpx 在iPhoneX上面显示不完整
边框 border设置1rpx 在iPhoneX上面显示不完整 [图片] .count input { width: 260rpx; height: 70rpx; line-height: 70rpx; font-size: 26rpx; border: solid 1rpx #dbdbdb; padding: 0rpx 25rpx; color: #626262; text-align: center; } 另外1rpx在iOS和android端显示的宽度不一致的问题什么时候能解决? 麻烦官方给个解决方案
2018-05-09 - 小程序基础库 3.0.0 更新
各位微信开发者: 小程序基础库 3.0.0 已经开始灰度开发者,请大家基于业务情况关注相关变更。如遇问题请及时在该帖下方留言或在小程序交流专区发表标题包含「基础库3.0.0」的帖子反馈。 本次更新正式发布以下三大特性: 1、Skyline 渲染引擎发布正式版 为了进一步优化小程序性能,提供更为接近原生的用户体验,我们推出了一套新渲染引擎 Skyline。在经过近一年的 beta 版测试后,Skyline 已经趋于稳定。我们修复了大量问题并进行了诸多性能优化,使线上的小程序能够稳定运行且性能表现更优。此外,为了让开发者能更快迁移,我们支持了大多数常用的 CSS 特性,同时还添加了许多高级特性,以帮助开发者构建类原生体验的小程序。更多详细的信息请查阅 介绍文章。 2、XR-FRAME 发布正式版 经过迭代,我们补齐了XR-FRAME的许多基础能力,并针对稳定性等问题做了针对性的优化。XR-FRAME是一个基于小程序开发方案、高性能、渐进式的3D/XR开发框架。开发者可以非常简单得使用WXML便可构造出一个酷炫的3D小程序,并且还广泛支持了AR、物理、交互、粒子、后处理、视频等等能力,同时也能够满足服务商等高级用户各种进阶的定制需求。我们仍在不断迭代新功能,跟着这篇文档可以了解XR-FRAME框架并开始你的开发:开始入门。 3、推出新版组件框架 glass-easel glass-easel 是新一代的小程序页面和自定义组件框架,旨在替代老旧的组件框架,提供更好的性能和更多的特性。现在,我们率先在 Skyline 环境下引入,成为默认的组件框架。glass-easel 几乎完整兼容了旧版框架,仅有极个别的接口被废弃移除,在提升性能的同时,添加了诸多特性,如 Chaining API、动态 slot、在模板中调用 data 里的函数等,更多详细的信息请 查阅文档。 更多更新内容: 新增 框架 新增 wx.getCommonConfig 接口 详情新增 组件 scroll-view 支持下拉二楼交互 详情更新 框架 glass-easel 在兼容模式下运行时使用 wxs 事件响应函数的 ComponentDescriptor#getState 方法 更新 框架 scroll-view 支持 min-drag-distance 属性 详情更新 框架 video 组件遮罩逻辑导致全屏投屏按钮无法点击 详情更新 框架 sticky-header 支持 top 偏移 详情更新 框架 skyline 支持 css animation 事件 更新 框架 启动页无法绑定自定义路由 详情更新 框架 更新 scroll-view / grid-view / list-view / sticky-header / sticky-section 组件支持 padding 属性,设置组件内部的内边距 详情 更新 框架 XR-FRAME VideoTexture 发布正式版 详情更新 框架 Skyline 渲染引擎下,组件框架切换为 glass-easel 详情更新 组件 skyline button 组件 loading 属性添加动画 更新 API 基础库支持 visionkit depth 功能 详情修复 框架 scroll-view 封装成组件时 scroll-into-view 无法跳转 修复 框架 skyline 内存泄漏问题修复 框架 skyline input/textarea 组件获取焦点相关问题 修复 框架 skyline 下部分组件事件无法使用 wxs 函数响应的问题 修复 组件 video 视频遮罩报错修复
2023-07-19 - 小程序取消橡皮筋回弹效果解决方案及坑总结
提到ios系统的橡皮筋效果,作为开发者是又爱又恨,有想要这个效果又有不想要的,无奈的是却没有一个简单的开关来设置这个效果是否开启。 最近在开发小程序时也遇到有关于ios橡皮筋回弹的问题,这里分两部分(取消橡皮筋回弹效果和因为这个效果遇到的坑)和大家分享一下。 取消IOS橡皮筋回弹效果的解决方案 1) 页面无滚动区域时,可通过页面json配置文件设置disableScroll:true禁止整个页面滚动,从而取消橡皮筋效果。 [代码]{ "disableScroll":true } [代码] 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo1 2) 页面有滚动区域,滚动区域通过view模拟实现,然后在页面json配置文件设置disableScroll:true禁止整个页面滚动,从而取消橡皮筋效果。 [代码]json文件配置 { "disableScroll":true } view元素模拟实现滚动样式 { height: calc(100vh - 120rpx); //高度必须是固定的值 overflow-y: auto; } [代码] 不足之处在于view元素模拟的滚动区域滚动时不够连贯,没有scroll-view那种原生丝滑般的感觉。 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo2 3) 页面有滚动区域,滚动区域使用scroll-view,这时通过disableScroll则无法实现,尝试设置一下scroll-view的scroll-y="{{false}}",上拉或下拉时居然不再触发橡皮筋的回弹啦,当然滚动区域也不能滚动。 小脑袋动一动,解决方法有啦! 通过设置一个变量scrollY动态控制滚动区域的滚动从而阻止回弹。 监听bindscrolltoupper\bindscrolltolower当scroll-view区域滚动到顶部或底部时候设置scrollY:false来关闭页面滚动,从而阻止回弹。 监听bindtouchstart\bindtouchmove 当用户反方向滑动的时候设置scrollY:true,再次开启页面滚动。 [代码]wxml滚动区域属性和事件处理,具体实现请点击测试代码链接 <scroll-view scroll-y="{{scrollY}}" class="list" upper-threshold="5" lower-threshold="5" bindscrolltoupper="bindscrolltoupper" bindscrolltolower="bindscrolltolower" bindtouchstart="touchstart" bindtouchmove="touchmove"> <view class="list-item" wx:for="{{list}}" wx:key="{{index}}">{{item}}</view> </scroll-view> [代码] 相对view模拟实现滚动区域,scroll-view滚动更丝滑,不过每次滚动到底部或顶部的时候,再反向滑动时由于再次开启scroll-view滚动会有操作卡顿的感觉,暂时没想到好的解决方法,有解决的大佬希望提供一下想法,一起学习下。 测试代码:https://github.com/YuniorZen/minicode-debug/tree/master/minicode01/pages/demo3 IOS橡皮筋效果遇到的坑 1) 操作左滑删除组件时上下移动,会触发橡皮筋效果导致页面抖动的问题 这个坑的严重程度看设计师的意愿了,反正我们团队目前是需要解决的,方案类似取消橡皮筋解决方案的第三种 在左滑的时候关闭scroll-view的滚动,取消时再次开启滚动 2) 如果页面顶部有置顶的横向滚动区域scroll-view,当页面滚动到底部时继续上拉会导致置顶头部消失,松开回弹后头部又会出现。 坑是社区里的朋友提出来的,我借了个iphone x 一预览,我嚓,还是真是个奇坑! 微信官方回复已复现正在解决中… 不想继续等下去的,暂时解决方法是 监听页面的滚动区域,当滚动到底部时设置顶部横向滚动scroll-view的scroll-x=false来解决。 写在最后 以上便是我在小程序开发中有关于ios橡皮筋回弹效果的分享,示例代码已上传github,可自行下载体验。 https://github.com/YuniorZen/minicode-debug/tree/master/minicode01 目前微信官方虽说已经着手解决(已两年)此类bug,但哪吒说 我命由我不由天,所以还是我们开发者多分享些解决方案自救来的快。 分享方案如有问题还望不吝指出,没有涉及到的坑也欢迎评论提出,一起学习和解决,后续也会基于此篇不断更新总结。
2021-01-14 - 消息推送配置 - Token校验失败,请检查确认
https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Message_Encryption/Message_encryption_and_decryption.html 开发者可以在微信公众平台接口调试工具,在接口类型中选择“消息接口调试”,并选择安全模式的加密调试,进行消息加解密的在线调试。 微信公众平台接口调试工具:https://mp.weixin.qq.com/debug [图片]
2021-04-14 - 关于 wx.loadFontFace 加载字体在真机环境下不能正常显示的实验结果分享及正确解决方案
wx.loadFontFace 必须满足的条件: 跨域 / CORS 下载的字体文件的响应头中必须包含:Access-Control-Allow-Origin: * 这里指出一下,官方文档注意事项描述中的第3点这里有个问题(也可能是我理解错了,望指正): 官方写的是:“字体链接必须是同源下的,或开启了cors支持,小程序的域名是servicewechat.com”; 经过测试后发现如果将 Access-Control-Allow-Origin 设置为:“servicewechat.com” 的话在iOS设备中可以正确下载字体,但在安卓中不能下载,显示的是:“loadFontFace:fail”, 反复测试了一下如果将 Access-Control-Allow-Origin 设置为 * 在安卓真机环境下就可以下载成功并显示了。 响应文件类型 Content-Type 必须设置为正确的字体类型,例如 *.ttf 对应的类型是 “font/ttf” 总结 正确显示字体的必要条件就是: Access-Control-Allow-Origin: * Content-Type: font/ttf | font/woff | font/woff2 | ... *上面这两条配置需要后端在字体文件保存的服务器或者CDN设置 为了让字体快速的加载,尽可能压缩字体文件大小或者精简字体,1mb内的字体大小基本可以在正常4G网络下实时加载出来;wx.loadFontFace需要设置 global 属性,才能全局生效;下载字体文件的域名必须配置到小程序的 downloadFile 合法域名中;下载的字体文件域名需要使用HTTPS协议;以上是个人实验下来的结果和一些经验,如果有不正确的地方可以评论指出。 参考 常见文件类型列表跨域/CORS(跨域资源共享)
2021-02-18 - 小代码大作用,云函数openapi
以下云函数openapi的代码极简,但是作用很多,包括: (代码直接复制可用) 1、支持所有云调用;是所有哦。 2、支持大图片安全检查 3、支持环境共享的云调用。 云函数代码如下: const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const opt = {} exports.main = async event => { const wxc = cloud.getWXContext() opt.appid = wxc.FROM_APPID || wxc.APPID//获取环境或共享环境的访问端小程序appid if (event.action == 'security.imgSecCheck') return await imgSecCheck(event)//大图片安全检查 if (event.action == 'xxx') return await xxx(event)//其他特殊处理 return await cloud.openapi(opt)[event.action](event.body || {}) } async function imgSecCheck(event) { let res = await cloud.downloadFile({ fileID: event.fileID, }) return await cloud.openapi(opt).security.imgSecCheck({ media: { contentType: "image/png", value: res.fileContent } }) } 小程序端的调用代码示例: 1、获取小程序码 app.cloud.callFunction({ //app.cloud是小程序当前环境的cloud,在app.js中初始化,可能是wx.cloud,也可能是共享环境的cloud name: 'openapi', data: { action: 'wxacode.getUnlimited', body: { scene, width: 280 }, } }) 2、发送订阅消息 app.cloud.callFunction({ name: 'openapi', data: { action: 'subscribeMessage.send', body: { "touser": openid, "page": 'pages/index/index?orderId=' + order._id, data, "templateId": tid, "miniprogramState": 'trial' } } }) 3、获取小程序直播房间列表 app.cloud.callFunction({ name: 'openapi', data: { action: 'liveBroadcast.getLiveInfo', body: { start: 0, limit: 100 } } })
2022-06-14 - 一个云函数五行代码搞定云调用openapi
云调用接口如下: https://developers.weixin.qq.com/miniprogram/dev/api-backend/ 1、该文档中的几十个接口,全部可由下面5行代码实现: 2、同时支持共享环境下的云调用 云函数名:openapi index.js代码: const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) exports.main = async event => { let appid = cloud.getWXContext().FROM_APPID || cloud.getWXContext().APPID return await cloud.openapi({appid})[event.action](event.body) } 小程序端调用代码: onOpenapi: function () { wx.cloud.callFunction({ name: 'openapi', data: { action: 'urlscheme.generate', body: {} } }).then(res => { console.log(res) }) }, 将云调用相关的云函数合并成一个。 而且,极简。。。
2022-09-29 - 云开发云函数定时触发器讲解
任何可以产生事件,触发云函数执行的均可以被称为触发器,而定时触发器则是可以处理周期性的事情,比如时报、日报、周报等通知提醒,也可以处理倒计时任务,比如节假日、纪念日以及你可以指定一个具体时间的倒计时任务,除此之外,定时触发器还可以用来周期性处理一些定时任务。比如定期清理一些不必要的数据,定期更新集合内的数据。 13.5.1 定时触发器使用说明1、定时触发器的配置与部署配置了定时触发器的云函数,会在相应时间点被自动触发,云函数的返回结果不会返回给调用方。在对某个云函数使用定时触发器前,首先要保证该云函数在小程序端可以调用成功,更准确的说是能够在不传入参数的情况下在云开发控制台的云端测试能调试成功(小程序端调用有登录态)。 云函数目录里的 config.json 文件可以用来配置权限和定时触发器,如果你的云函数目录下面没有这个配置文件,可以自己创建一个,创建的结构目录如下: test //云函数目录 ├── config.json //权限和定时触发器等的配置文件 ├── index.js //云函数 ├── package.json //云函数的依赖管理 然后再来在配置文件 config.json 里进行类似如何格式的配置,config.json 严格遵循配置文件所要求的格式,比如数组最后一项不能有逗号[代码],[代码];配置文件里不能有注释等 triggers 字段是触发器数组,但是目前云函数只支持一个触发器,即数组只能填写一个,不可添加多个;name 是触发器的名字,最大支持 60 个字符,支持 a-z, A-Z, 0-9, - 和 _,必须以字母开头;type 为触发器类型,timer 是定时触发器config 是触发器的定时配置,里面为 cron 表达式(后面有介绍),cron 有七个必需字段,不能多也不能少(以下为每天早上 9 点到 12 点每隔 5 秒触发一次);{ "triggers": [ { "name": "tomylove", "type": "timer", "config": "*/5 * 9-12 * * * *" } ] } 当我们在修改触发器配置文件 config.json 后,首先鼠标右键 config.json 选择“云函数增量上传:更新文件”,然后再右键 config.json 选择“上传触发器”。这里的“云函数增量上传:更新文件”是让云函数端的触发器文件更新;而“上传触发器”则是让触发器开始生效执行。如果在云函数端的触发器没有更新的情况下就“上传触发器”来执行定时触发,文件可能没有更新,执行的还是旧的触发器内容。当我们想暂停或删除触发器时,可以右键选择“删除触发器”。 2、Cron 表达式语法Cron 表达式有七个必填字段,按空格分隔,既不能多写也不能少写,每一个字段都有它的含义对应着不同的时间点,表达式的取值都为整数且为时间制的范围(注意月在星期的前面): 第一位第二位第三位第四位第五位第六位第七位秒(0-59 )分钟(0-59)小时(0-23)日(1-31)月(1-12或三个字母的英文缩写)星期(0-6或三个字母的英文缩写)年(1970~2099 ) 下面是 cron 表达式的案例,以及我们需要了解一下 cron 表达式里的通配符以及直接写数字的含义: [代码],[代码],表示并集,在时间的表述里是“和”的意思,比如在“小时”字段中, [代码]1,2,3[代码]表示 1 点、2 点和 3 点;[代码]-[代码],指定范围的所有值,在时间的表述里是“到”的意思,比如在“日”字段中,[代码]1-15[代码]包含指定月份的 1 号到 15 号;[代码]*[代码],表示所有值,在时间的表述里是“每”的意思,比如在“小时”字段中,[代码]*[代码]表示每小时;[代码]/[代码],指定步长,在时间的表述里是“隔”的意思,比如在“秒”字段中,[代码]*/5[代码]表示每隔 5 秒;直接写数字,在时间的表述里是“第”(时间点)的意思,比如在“月”字段中,[代码]5[代码]表示每月的第 5 日;//表示每隔5秒触发一次, */5 * * * * * * //表示在每月的1日的凌晨2点触发 0 0 2 1 * * * //表示在周一到周五每天上午10:15触发 0 15 10 * * MON-FRI * //表示在每天上午10点,下午2点,4点触发 0 0 10,14,16 * * * * //表示在每天上午9点到下午5点内每半小时触发 0 */30 9-17 * * * * //表示在每个星期三中午12点触发 0 0 12 * * WED * 定时触发器的 Cron 语法没法实现每隔 90 秒钟或 90 分钟发送一次这样的效果,因为 90 秒超过了秒的时间制上限 60,而 cron 在跨位组合(比如 90 秒需要结合秒和分)上无法覆盖所有的时间;除此之外,云开发的触发器暂时不支持多个定时触发器的叠加;在 Cron 表达式中的“日”和“星期”字段同时指定值时,两者为“或”的关系,即两者的条件均生效;值得一提的是,尽管云函数的时区为 UTC+0 时区,但是定时触发器的时间还是北京时间。 13.5.2 用定时触发器调用云函数定时触发器的使用非常简单,使用开发者工具新建一个云函数比如 trigger,然后在 index.js 里输入以下代码: const cloud = require("wx-server-sdk"); cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV, }); exports.main = async (event, context) => { console.log(event); return event; }; 再在 trigger 云函数目录下的 config.json(如果没有这个文件,就创建一个),然后输入以下触发器,为了调试方便,我们可以每隔 5 秒触发一次: { "permissions": { "openapi": [ ] }, "triggers": [ { "name": "tomylove", "type": "timer", "config": "*/5 * * * * * *" } ] } 然后分别右键 index.js 和 config.json,选择“云函数增量上传:更新文件”,然后再来右键 config.json 选择“上传触发器”。云函数就会每隔 5 秒自动触发,相关的日志我们可以在开发者工具的云开发控制台以及腾讯云云开发网页控制台的云函数的日志里查看。 注意小程序端调用 trigger 云函数返回的 event 对象,和使用定时触发器返回的 event 对象的不同,用定时触发器触发云函数是获取不到 openId 的,同时这里有一个 Time 时间是时区为 UTC+0 的时间,比北京时间晚 8 个小时: //在小程序端调用trigger云函数之后返回的event对象 { "userInfo":{ "appId":"wxda99******7046", "openId":"oUL-m5F******buEDsn8" } } //使用定时触发器触发云函数之后返回的event对象 { "Message":"", "Time":"2020-06-11T11:43:35Z", "TriggerName":"tomylove", "Type":"timer", "userInfo":{ "appId":"wxda99********46" } } 13.5.3、定时触发器的应用定时触发器的应用非常广泛,以下仅举一些常用案例,并加以说明: 1、结合消息推送这里的消息推送不仅仅只是指订阅消息,还可以是统一服务消息、公众号的消息(可以用云函数开发微信公众号)、小程序内自己开发的通知(只是用户只有在打开小程序时才能看到)、Email 邮件等等。 比如用户订阅了日报、周报、月报等周期性的通知提醒或者我们需要给用户发送一些汇总信息,就可以固定写一个定时触发器,比如我们需要给指定用户发送工作周报,每周五晚上 17 点 30 分就定时从数据库获取数据发送消息,cron 表达式写法如下: * 30 17 * * FRI * 还可以用来处理一些倒计时(指定时间点)的任务,比如节假日、纪念日以及一些活动时间节点(定时触发器目前只能一个云函数配一个触发器,但是可以提前管理),比如我们希望在六一儿童节的早上 9 点调用云函数给指定用户群体发送消息: 0 0 9 1 6 * * 当然这样的具体时间点显得过于的不灵活,但是如果把时间与云开发数据库结合起来,灵活性就会大很多,比如在运营上每天早上 11 点是你们用户访问最多的时间点,你只需要写一个云函数,把所有的活动都在这个时间点来推送,让定时触发器每天这个时间点都触发,有活动(数据库里有数据)就会发消息,如果没有就不发(云函数调用一次的成本极低)。 如果是实时数据,我们还可以把定时触发器的频率调高,每 5 秒就触发一次,比如我们的数据库只要有最新的数据,就会发消息给指定用户。尽管不是完全的实时,但是 5 秒的频率和实时的差别也就不大了。你也可以根据情况,来调整触发器的频率,毕竟 5 秒和 1 分钟的频率给用户的体验差异并没有太大,但是成本却是 12 倍的关系。 可能你还希望在指定的时间段才触发云函数,比如你只希望在工作日、或者在早上 9 点到晚上 18 点才触发,在指定的时间段才触发既可以让触发更精准不扰民,也可以节约成本,比如下面的触发器就是工作日早上 9 点到 12 点和下午 14 点到 18 点这个时间段,每 5 秒触发一次。 */5 * 9-12,14-18 * MON,TUE,WED,THU,FRI * 从以上案例我们可以了解到,云函数的定时触发可以来自于 cron 表达式的配置,我们可以指定时间点时间段和频率来达到我们想要的效果,同时这个时间“也可以来自于数据库的配置”(伪装),意思是我们可以设置触发器的时间段或频率,如果数据库里有数据就发送,没有数据就不发送,这样就可以达到触发器在时间上的灵活性了。 2、实时获取数据有的时候我们的数据并不是来自于数据库,而是来自于第三方服务,比如前面介绍过的历史上的今天的 API,天气的 API,知乎日报的 API 等等,以及一些 webhook,这些 API 和第三方服务提供的是 json 格式的文件,API 的数据也会随时更新,但是它们更新了却并不会主动通知我们,这时我们可以使用定时触发器向这些 API 发起请求,如果数据出现更新,我们就可以将更新的数据存储到我们的数据库或者进行其他处理,比如企业微信的机器人等机器人通知服务就是如此。 当然定期获取的数据还可以是爬虫,比如我们可以定期抓取指定关键词的新闻或者指定网站的动态,当爬虫获取到了不同的数据的时候,就将最新的动态以机器人消息或者其他方式进行及时的处理。 也就是说,我们无法实时监听到第三方 API 或者网站数据的变动,但是可以用定时触发器来发起请求或者爬虫抓取数据,通过数据的变化来达到“实时”获取数据的目的。 3、自动化处理在数据库的设计里,我们就提到有时候需要对数据库里的数据进行定期的备份与删除等清理维护工作,比如超过一定时间的日志,具有很强时效性的活动数据,以及为了性能考虑而做的虚假删除(数据库性能与优化有介绍)等,毕竟数据库有一定的存储成本而且过多无用数据也会影响数据库的性能,我们可以写一个云函数用定时触发器来执行此类任务。 我们还可以在用户并发比较少的时间段(比如凌晨几点)来处理一些比较耗云函数、数据库性能的任务,比如图片的审核与裁剪、缩略等处理,用户评论是否包含敏感词汇(尽管经过安全处理,但是有时候我们还会设置特别的敏感词),数据的汇总,云存储里废弃文件的删除,用户信息是否完整等等。 也就是说,结合定时触发器,我们可以实现一些任务的自动化处理。 4、密集型任务分流我们知道云函数在处理一些复杂性的任务时是有一些限制的,一是执行时间的限制,建议在设置时执行时间一般不要超过 20s,最长不要超过 60s;二是并发的限制,云函数最大的并发为 1000;三是云函数在查询数据库时一次可以获取最多 1000 条的数据,面对这三个限制,我们应该如何处理密集型的任务呢,比如发送 100 万封邮件,导出几百万条数据到 Excel,发送十万级的订阅消息或消息等等,这个时候就可以使用到定时触发器来处理了。 借助于定时触发器,我们可以将需要耗时较长、对并发要求较高以及数据库请求等的任务进行分批处理,比如我们要给 100 万人发邮件:云函数发起数据库请求,一次只请求 1000 条未发送过邮件的用户(用 where 条件查询某个字段,比如[代码]status:false[代码]),然后将邮件发给 1000 个人(可以参考前面的邮件发送),发完邮件并对这 1000 条数据进行标记(比如使用更新指令将 status 改为 true),这样下次查询未发送过邮件的用户时,就不会重复发送了。通过定时触发器,每 2 秒执行一次发送任务,几十分钟就可以处理完任务。
2021-09-10 - 用【库存】看懂云开发数据库事务
在正常使用数据库(CRUD)的情况下,这些操作都会顺利进行所有数据都会被成功更新,由于某些特定的业务场景,需要进行一系列的操作,在这过程中必须保证每一步的操作都正常执行,如果任何一个环节出了差错,比如更新库存信息发生异常,这终将会导致数据库的信息混乱而不可预测,数据库事务正是用来保证这种一系列操作的稳定性技术。 什么是事务? 数据库事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。 事务的特性 ACID,指数据库事务正确执行的四个主要特性的缩写,一个事务,必需要具有这四种基本特性,否则在事务过程当中无法保证数据的正确性。 1:原子性(Atomicity) 指的是一个事务内所有操作共同组成一个原子包,要么全部成功,要么全部失败。 假如在数据库中对一个属性进行了更新,但是执行到一半的时候出现了异常,这样就可能使得操作后的数据与我们预期的数据不同,所以原子性要求你这个方法要么全部执行成功,要么全部失败 2:一致性(Consistency) 指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。 在原子性中规定方法中的操作都执行或者都不执行,但并没有说要所有操作一起执行,所以操作的执行也是有先后顺序的,那我们要是在执行一半时查询数据库,那我们会得到中间的更新的属性?一致性规定提交前后只存在两个状态,提交前的状态和提交后的状态 3:隔离性(Isolation) 指的是数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。 多个事务可能操作同一数据库资源,不同的事务为了保证隔离性,如果没有隔离会造成几种问题 事务A读到事务B修改却未提交的数据,事务B回滚数据修改操作,导致了事务A获得数据是脏数据 事务A先读取数据,事务B对数据进行修改,事务B再一次读取该行数据时就会造成前后两次读取结果不一致 事务A读取数据,事务B对其进行操作时,当事务A重新读取该段数据时会造成前后两次查询的数据不一致的现象 目前云开发数据库使用的是快照隔离,具体将在下面进行介绍 4:持久性(Durability) 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失 如果没有持久性的特性,一旦数据库出现异常,数据将会丢失 拥有持久性事务一旦提交后,数据库中的数据必须被永久的保存下来,即使服务器系统崩溃或服务器宕机等故障,只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。 ####云开发数据库事务 介绍 云开发数据库本身有提供(如 inc、mul、addToSet)等原子性操作符号和嵌套记录的数据结构设计,如跨多个记录或跨多集合的原子操作时,可以使用云数据库事务能力。 隔离性 云开发数据库事务过程中采用的快照隔离级别(snapshot),在事务期间,读操作返回的是对象的快照,而非实际数据,事务期间写操作执行时: 改变快照,保证接下来的读的一致性; 给对象加上事务锁 事务锁 数据对象存在事务锁对数据写入的影响: 其它事务的写入会直接失败; 普通的更新操作会被阻塞,直到事务锁释放或者超时事务提交后,操作完毕的快照会被原子性地写入数据库中 单记录操作 云开发数据库事务中不支持批量操作,只支持单记录操作比如(collection.doc, collection.add),单记录操作可避免大量锁冲突、保证运行效率,并且大多数情况下单记录操作足够满足需求,因为在事务中是可以对多个单个记录进行操作的,也就是可以在一个事务中同时对集合 A 的记录 x 和 y 两个记录操作、又对集合 B 的记录 z 操作,接下来会通过小示例来进行演示。 事务 API 云开发数据库事务提供两种操作风格的接口,一个是简易的、带有冲突自动重试的runTransaction接口,一个是流程自定义控制的startTransaction接口。 使用小示例 假设有以下场景: 某仓库有1000箱医用口罩,A医院需要800箱、B医院需要300箱并提交申请,仓库的管理模式是先收到提交申请在进行库存商品确认完毕后,进行领用。 在无事务的情况下伪代码自上而下执行 [代码]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) => { // 医院 await db.collection('resource').doc('A'||'B') .update({ data: { resource: _.inc(-800||-300) }, }) // 仓库 await db.collection('store').doc('store') .update({ data: { resource: _.inc(+800||+300), }, }) } // 判断是否满足要求 if('仓库库存' >'领用数量' ){ await db.collection('store').doc('store') .update({ data: { count:_inc(-800||-300), }, }) }eles{ '回退的业务逻辑' } } [代码] 根据以上的代码执行结果来看: A/B医院提交了领用口罩的申请; 仓库接收了B医院提交的申请; 判断是否符合数量要求 执行到3时候发现仓库库存,并不能满足医院的领取要求时,需要将提交申请退还给医院,并处理一些退回的逻辑。 该情况下需要处理操作量大、复杂度高、在高并发的执行情况下会导致一些具体的操作没有完成比如: 医院提交了申请,仓库并没有收到; 医院提交了申请,仓库收到申请,并没有执行发放,也没有退还给医院; 事务的情况下伪代码自上而下执行 [代码]const cloud = require('wx-server-sdk') cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV }) const db = cloud.database({ throwOnNotFound: false, }) const _ = db.command exports.main = async (event) => { try { const result = await db.runTransaction(async transaction => { const resource = await transaction.collection('resource').doc('A'||'B').get() const store = await transaction.collection('store').doc('store').get() const updateResource = await transaction.collection('resource').doc('A'||'B').update({ data: { resource: _.inc(-800||-300) } }) const updateStoreResource = await transaction.collection('store').doc('store').update({ data: { resource: _.inc(+800||+300), } }) if(store.data.count > 800||300){ const updateStoreCount = await transaction.collection('store').doc('store').update({ data: { count:_inc(-800||-300), } }) // 会作为 runTransaction resolve 的结果返回 return { resourceAccount: resource.data.count + 800||300, } }else{ // 会作为 runTransaction reject 的结果出去 await transaction.rollback('领取失败') } }) return { success: true, resourceAccount: result.resourceAccount, } } catch (e) { console.error(`transaction error`, e) return { success: false, error: e } } } [代码] 根据以上的代码执行结果来看: 1.首先读取了A/B医院与仓库的记录快照; 2.医院提交申请,减少对应的数量; 3.仓库接收到医院的提交申请; 4.判断仓库中的数量是否满足本次领取的数量; 执行到4时候发现仓库库存,并不能满足医院的领取要求时,事务会将所有更改的记录还原到读取记录快照时的数据,也就是说这些执行步骤[代码]要不就都成功,要不就都失败,数据回滚,不需要过多的回退逻辑[代码] 未使用事务 VS 使用事务 未使用事务 由于操作量大,复杂度高,在加上出现高并发的情况就会有数据不一致的情况出现; 回退逻辑复杂; 使用事务 事务由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,保证了数据一致性; 在执行事务之后保留了数据对象的快照,执行中出现任何问题可直接回滚; 总结 在使用云开发数据库中,如果仅仅是涉及单记录的修改,完全可以使用如 inc、mul、addToSet)等原子性操作符号,涉及到跨集合以及多个记录同时修改并需要保证一致性的情况,那事务功能将是最好的选择。
2020-09-14 - swiper设置圆角在真机上不显示
在模拟器中的效果: [图片] 在真机上面的效果: [图片]
2018-07-09 - 「笔记」订阅消息体验踩坑
前言 10月12日夜晚社区发了公告小程序模板消息能力调整通知,正式发布了 一次性订阅消息 这一能力,所以第一时间进行了体验。 本文主要是补充一下官方未提供的使用方法,和使用中与模板消息用法的不同。 文档地址 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/subscribe-message.html 使用方法 [代码]wx.requestSubscribeMessage({ tmplIds: ["模板id1","模板id2"], success: function (res) { //成功 }, fail(err) { //失败 console.error(err); } }) [代码] 第一个坑 如果不勾选红色方框内的内容,用户每次触发订阅消息功能都会弹出授权窗口,如果用户勾选了则不会出现弹窗。 [图片] 第二个坑 目前开发者工具(v1.02.191012)不支持调试,只能通过真机调试。 [图片] 第三个坑 微信不会为开发者保存订阅次数,需要自己在后台记录用户触发的次数。 超过次数调用接口下发订阅消息会返回失败。 [图片] 第四个坑 发送模板格式和原来的模板消息格式不一致,特别是data内的内容,订阅消息的字段key是和数据类型有关,value的参数需要严格按照设置的类型提交,具体使用参考后台的模板详情。 模板消息的格式: [代码]"data": { "keyword1": { "value": "内容", "color": "#000" }, "keyword2": { "value": "内容", "color": "#000" } } [代码] 订阅消息的格式: [代码]"data": { "thing1": { "value": "内容" }, "number2": { "value": 20 } [代码] 第五个坑 订阅消息申请模板的时候,需要选择所属类目,而且只能是自己小程序相关类目,模板消息是不需要选择对应类目的。 如果删除小程序类目,则会把订阅消息模板一起删除,需谨慎操作。 [图片] 第六个坑 长期订阅消息只针对特定行业开放,所以普通开发者并无法使用。 结束 暂时就先总结这些,有其它坑再补充。
2019-10-13 - 小程序内用户帐号登录规范调整和优化建议
为更好地保护用户隐私信息,优化用户体验,平台将会对小程序内的帐号登录功能进行规范。本公告所称“帐号登录功能”是指开发者在小程序内提供帐号登录功能,包括但不限于进行的手机号登录,getuserinfo形式登录、邮箱登录等形式。具体规范要求如下: 1.服务范围开放的小程序 对于用户注册流程是对外开放、无需验证特定范围用户,且注册后即可提供线上服务的小程序,不得在用户清楚知悉、了解小程序的功能之前,要求用户进行帐号登录。 包括但不限于打开小程序后立即跳转提示登录或打开小程序后立即强制弹窗要求登录,都属于违反上述要求的情况; 以下反面示例,在用户打开小程序后立刻弹出授权登录页; [图片] 建议修改为如下正面示例形式:在体验小程序功能后,用户主动点击登录按钮后触发登录流程,且为用户提供暂不登录选项。 [图片] 2.服务范围特定的小程序 对于客观上服务范围特定、未完全开放用户注册,需通过更多方式完成身份验证后才能提供服务的小程序,可以直接引导用户进行帐号登录。例如为学校系统、员工系统、社保卡信息系统等提供服务的小程序; 下图案例为正面示例:校友管理系统,符合规范要求。 [图片] 3.仅提供注册功能小程序 对于线上仅提供注册功能,其他服务均需以其他方式提供的小程序,可在说明要求使用帐号登录功能的原因后,引导用户进行帐号注册或帐号登录。如ETC注册申请、信用卡申请; 如下反面示例,用户在进入时未获取任何信息,首页直接强制弹框要求登录注册ETC,这是不符合规范的。 [图片] 建议修改为如下正面示例所示形式:允许在首页说明注册功能后,提供登录或注册按钮供用户主动选择点击登录。 [图片] 4.提供可取消或拒绝登录选项 任何小程序调用帐号登录功能,应当为用户清晰提供可取消或拒绝的选项按钮,不得以任何方式强制用户进行帐号登录。 如下图所示反面示例,到需要登录环节直接跳转登录页面,用户只能选择点击登录或退出小程序,这不符合登录规范要求。 [图片] 建议修改为下图正面示例形式,在需帐号登录的环节,为用户主动点击登录,并提供可取消按钮,不强制登录。 [图片] 针对以上登录规范要求,平台希望开发者们能相应地调整小程序的帐号登录功能。如未满足登录规范要求,从2019年9月1日开始,平台将会在后续的代码审核环节进行规则提示和修改要求反馈。
2019-07-20