什么是kintone.Promise

aki发表于:2019年10月08日 13:00:31更新于:2023年03月29日 12:08:33

关于kintone.Promise的常见写法请参考kintone上使用Promise时的基本写法

                                                                                                                       (著者:武井 琢治)

我想有不少kintone自定义初学者看到本篇文章是因为冥思苦想之后网上到处查,最后查到这里的。
本篇就是针对这样的初学者,精简地总结了Promise的重点。

结论:什么是kintone.Promise

当处理怎么都不能按照设想的顺序执行时、
或者不知道为什么处理就是没有被执行时,用kintone.Promise或许能帮你解决问题。

用在哪里?

0015d9e9a08337e9227797dbf49da77

如上图,在kintone的记录保存事件中使用的比较多。

使用范例

0015d9fde808d07ec5953606e045f84

本次要创建的系统如上图,添加销售记录后,会立即更新库存数量。

准备应用

准备以下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个!”。

流程如下:
0015d9fde65c5609cdb9234062f2a7d

代码范例

(() => {
  '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自定义上要是能助大家一臂之力,我倍感荣幸。


附件:kintone.Promise入门.zip • 2.87KB • 下载