关于kintone.Promise的常见写法请参考kintone上使用Promise时的基本写法。
(著者:武井 琢治)
我想有不少kintone自定义初学者看到本篇文章是因为冥思苦想之后网上到处查,最后查到这里的。
本篇就是针对这样的初学者,精简地总结了Promise的重点。
结论:什么是kintone.Promise
当处理怎么都不能按照设想的顺序执行时、
或者不知道为什么处理就是没有被执行时,用kintone.Promise或许能帮你解决问题。
用在哪里?
如上图,在kintone的记录保存事件中使用的比较多。
使用范例
本次要创建的系统如上图,添加销售记录后,会立即更新库存数量。
准备应用
准备以下3个应用。
■商品管理
字段代码 | 字段类型 | 备注 |
---|---|---|
商品名称 | 单行文本框 | |
单价 | 数值 |
■销售管理
字段代码 | 字段类型 | 备注 |
---|---|---|
商品名称 | lookup | 要复制的字段为商品管理里的商品名称。 |
单价 | 数值 | 复制商品管理的单价。 |
销售数量 | 数值 | |
更新库存 | 单选框 | 未处理/已更新/错误 |
■库存管理
字段代码 | 字段类型 | 备注 |
---|---|---|
商品名称 | lookup | 要复制的字段为商品管理里的商品名称。 |
单价 | 数值 | 复制商品管理的单价。 |
库存 | 数值 | |
合计金额 | 计算 | 公式为“单价 * 库存” |
应用模板
下载kintone.Promise入门.zip,上传到环境。
关于应用模板的导入方法,请参考此处。
请视情况使用。(没有添加JavaScript文件)
准备JavaScript文件
在销售管理应用的“应用的设置 > 通过JavaScript / CSS自定义”页面,添加以下范例代码文件。
上传前,请把范例代码拷贝到编辑器,文件名保存为“sales.js”,文字编码为“UTF-8”。
※文件名任意,文件的扩展名为“js”。
(() => { 'use strict'; kintone.events.on('app.record.create.submit', (event) => { const record = event.record; // 库存管理应用的应用ID const zaikoAppId = 123; return new kintone.Promise((resolve, reject) => { // 获取商品名称一致的库存 kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: `商品名称 = "${record.商品名称.value}"`}, (resp) => { // 库存数量减去销售的数量 const zaiko = resp.records[0].库存.value - record.销售数量.value; if (zaiko < 0) { record.更新库存.value = '错误'; resolve(event); } else { const body = { 'id': resp.records[0].$id.value, 'app': zaikoAppId, 'record': { '库存': { 'value': zaiko } } }; kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => { record.更新库存.value = '已更新'; resolve(event); }); } }); }); }); })();
※第7行的“zaikoAppId”的值请更改为您环境中库存管理应用的ID。
程序代码解说
return new kintone.Promise((resolve, reject) => {
一般情况下,kintone事件中在处理结束后要“return event;”。
但这里是在处理开头return了kintone.Promise。
if (zaiko < 0) { record.更新库存.value = '错误'; resolve(event);
当库存少于销售数量时,在保存销售记录时,单选框会报错。
resolve是kintone.Promise使用时的法宝。
(具体是指成功时生成kintone.Promise对象并返回,
如果觉得不太好理解,那就理解为“存放在kintone.Promise最终地点的内容”。)
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => { record.更新库存.value = '已更新'; resolve(event); });
更新库存记录,并将销售记录里的单选框值改为“已更新”。
有了resolve这个法宝,就可以做到条条大路通罗马了。
常见失败场景
(() => { 'use strict'; kintone.events.on('app.record.create.submit', (event) => { const record = event.record; // 库存管理应用的应用ID const zaikoAppId = 123; kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: '商品名称 = "' + record.商品名称.value + '"'}, (resp) => { // 库存数量减去销售的数量 const zaiko = resp.records[0].库存.value - record.销售数量.value; if (zaiko < 0) { record.更新库存.value = '错误'; return event; } const body = { 'id': resp.records[0].$id.value, 'app': zaikoAppId, 'record': { '库存': { 'value': zaiko } } }; kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => { record.更新库存.value = '已更新'; return event; }); }); }); })();
使用kintone.Promise以外的方法进行一些处理时,通常是像上面的写法。
这种情况下,不会去更改销售记录的“record.更新库存.value”的值,而是保留“未处理”。
理由是:
kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: '商品名称 = "' + record.商品名称.value + '"'}, (resp) => {
以及
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => {
这两处处理执行之前,以下处理先结束了。
kintone.events.on('app.record.create.submit', (event) => {
就像上面这样,不按照顺序处理的这种处理方法叫着"异步处理"。
return new kintone.Promise((resolve, reject) => {
如果使用kintone.Promise,会等待在异步处理中不会依次处理的
kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: '商品名称 = "' + record.商品名称.value + '"'}, (resp) => {
及
kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => {
这两步处理结束。
“已经准备妥当,不用等我了”这样的信号靠的就是resolve的魔法。
其他用途
如下文所述,kintone.Promise还有其他各种各样的用途。
截至本篇撰稿时间2016年10月为止,上面的情况还没有找到更好的替代方法。因此掌握kintone.Promise非常重要。
下面是顺带介绍的一些信息,目的是为了让大家知道“还有这样的用法啊!”。
其他用途举例
在循环语句中使用了异步处理的函数,并且希望等所有的处理结束后再执行特定处理时。
要使用异步处理函数的返回值来做一些其他处理时。
在多种处理途径中,只要其中一种的kintone.Promise返回了resolve,就要执行某些处理时。
想回避使用then()的方法链中回调地狱时。
……等等。
等待多个kintone.Promise的范例
下面要介绍的例子是:在销售管理应用上编辑记录时,不仅要更新库存数据,还要在回复栏里填写“卖出了O个!”。
流程如下:
代码范例
(() => { 'use strict'; kintone.events.on('app.record.edit.submit', (event) => { const record = event.record; // 库存管理应用的应用ID const zaikoAppId = 123; // 更改库存管理的库存 const zaikoChange = new kintone.Promise((resolve, reject) => { // 获取商品名称一致的库存 kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: `商品名称 = "${record.商品名称.value}"`}, (resp) => { // 库存数量减去销售数量 const zaiko = resp.records[0].库存.value - record.销售数量.value; if (zaiko < 0) { resolve('错误'); } else { const body = { 'id': resp.records[0].$id.value, 'app': zaikoAppId, 'record': { '库存': { 'value': zaiko } } }; kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => { resolve('已更新'); }); } }); }); // 在同一条记录中填写回复 const comment = new kintone.Promise((resolve, reject) => { const body = { 'app': kintone.app.getId(), 'record': kintone.app.record.getId(), 'comment': { 'text': "已销售"+`${record.销售数量.value}个。` } }; kintone.api(kintone.api.url('/k/v1/record/comment', true), 'POST', body, () => { resolve(); }); }); return kintone.Promise.all([zaikoChange, comment]).then((results) => { alert('处理结束!'); if (results[0] === '已更新') { record.更新库存.value = '已更新'; } else { record.更新库存.value = '错误'; } return event; }); }); })();
代码解说
// 更改库存管理的库存 const zaikoChange = new kintone.Promise((resolve, reject) => { // 获取商品名称一致的库存 kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: `商品名称 = "${record.商品名称.value}"`}, (resp) => { // 库存数量减去销售数量 const zaiko = resp.records[0].库存.value - record.销售数量.value; if (zaiko < 0) { resolve('错误'); } else { const body = { 'id': resp.records[0].$id.value, 'app': zaikoAppId, 'record': { '库存': { 'value': zaiko } } }; kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body, () => { resolve('已更新'); }); } }); });
这里是和库存联动的处理。
和前面的范例不一样,这里是将kintone.Promise带入到kucunChange变量中。
其他处理基本上没有变,不过要留意最后是通过resolve()传递“错误”和“已更新”字符串。
// 在同一条记录中填写回复 const comment = new kintone.Promise((resolve, reject) => { const body = { 'app': kintone.app.getId(), 'record': kintone.app.record.getId(), 'comment': { 'text': "已销售"+ `${record.销售数量.value}个。` } }; kintone.api(kintone.api.url('/k/v1/record/comment', true), 'POST', body, () => { resolve(); }); });
以上是在要保存的销售额记录中填写回复的处理。
这里也是一样将kintone.Promise带入comment变量。
return kintone.Promise.all([zaikoChange, comment]).then((results) => { alert('处理结束!'); if (results[0] === '已更新') { record.更新库存.value = '已更新'; } else { record.更新库存.value = '错误'; } return event; });
这部分注意使用的是“kintone.Promise.all”。
使用了这个,可以等待[kucunChange(=库存联动处理), comment(=填写回复处理)]都处理结束。
等处理结束后,提示“处理结束”。
之后使用“results[0]”进行分支处理,
“results[0]”中带入了在库存处理中resolve()传回的字符串。
因此,可以使用传回的字符串来进行分支处理。
如果传回的字符串是"已更新",将销售记录的更新库存字段改为“已更新”,
如果传回的字符串是"错误",将销售记录的更新库存字段改为“错误”,处理结束。
※同样,等待处理也可以如下使用then()将处理连起来。
(() => { 'use strict'; kintone.events.on('app.record.edit.submit', (event) => { return new kintone.Promise((resolve, reject) => { const record = event.record; // 库存管理应用的应用ID const zaikoAppId = 123; // 更改库存管理的库存 // 获取商品名称一致的库存 kintone.api(kintone.api.url('/k/v1/records', true), 'GET', {app: zaikoAppId, query: `商品名称 = "${record.商品名称.value}"`}).then((resp) => { // 库存数量减去销售数量 const zaiko = resp.records[0].库存.value - record.销售数量.value; if (zaiko < 0) { resolve('错误'); } else { const body = { 'id': resp.records[0].$id.value, 'app': zaikoAppId, 'record': { '库存': { 'value': zaiko } } }; kintone.api(kintone.api.url('/k/v1/record', true), 'PUT', body).then(() => { // 在记录中填写回复 const param = { 'app': kintone.app.getId(), 'record': kintone.app.record.getId(), 'comment': { 'text': "已销售" + `${record.销售数量.value}个。` } }; kintone.api(kintone.api.url('/k/v1/record/comment', true), 'POST', param).then(() => { resolve('已更新'); }); }); } }); }).then((resp_) => { alert('处理结束!'); if (resp_ === '已更新') { event.record.更新库存.value = '已更新'; } else { event.record.更新库存.value = '错误'; } return event; }); }); })();
終后
上面非常简单粗略地介绍了kintone.Promise的要点。大家有何感想?
掌握了这些,以后不管您是想要更加灵活地使用kintone.Promise,还是要使用其他完全不一样的方法,可以说是给自己开拓了一条活路。
以上,在kintone自定义上要是能助大家一臂之力,我倍感荣幸。