【问题标题】:Prevent custom functions from executing in Google Spreadsheets Google Apps Script阻止自定义函数在 Google 电子表格 Google Apps 脚本中执行
【发布时间】:2018-02-10 19:40:41
【问题描述】:

在编写要在电子表格单元格中使用的自定义函数时,工作表的默认行为是在编辑时重新计算,即添加列或行将导致自定义函数更新。

这是一个问题,如果自定义函数调用付费 API 并使用积分,用户将自动消耗 API 积分。

我想不出办法来防止这种情况发生,所以我决定使用UserCache 将结果缓存任意 25 分钟,并在用户碰巧重复相同的函数调用时将其返回给用户.它绝对不是防弹的,但我想它总比没有好。显然是cache can hold 10mb,但这是正确的方法吗?我可以做一些更聪明的事情吗?

  var _ROOT = {

  cache : CacheService.getUserCache(),
  cacheDefaultTime: 1500,

  // Step 1 -- Construct a unique name for function call storage using the 
  // function name and arguments passed to the function
  // example: function getPaidApi(1,2,3) becomes "getPaidApi123"

  stringifyFunctionArguments : function(functionName,argumentsPassed) {
    var argstring = ''
    for (var i = 0; i < argumentsPassed.length; i++) {
      argstring += argumentsPassed[i]
    }

    return functionName+argstring

  },

  //Step 2 -- when a user calls a function that uses a paid api, we want to 
  //cache the results for 25 minutes

  addToCache : function (encoded, returnedValues) { 

    var values = {
      returnValues : returnedValues
    }
    Logger.log(encoded)
    this.cache.put(encoded, JSON.stringify(values), this.cacheDefaultTime)

  }

  //Step 3 -- if the user repeats the exact same function call with the same 
  //arguments, we give them the cached result
  //this way, we don't consume API credits as easily. 

  checkCache : function(encoded) {

    var cached = this.cache.get(encoded);

    try {
      cached = JSON.parse(cached)
      return cached.returnValues
    } catch (e) {
      return false;
    }
  }

}

【问题讨论】:

    标签: caching google-apps-script google-sheets custom-function


    【解决方案1】:

    Google 表格已经缓存了自定义函数的值,并且只有在 a) 函数的输入发生更改或 b) 电子表格在长时间关闭后被打开时才会再次运行它们。我无法复制您在添加和删除列时提到的重新计算。这是我用来测试的一个简单示例函数:

    function rng() {
      return Math.random();
    }
    

    一般来说,您为昂贵的查询使用额外缓存的方法看起来不错。我建议使用DocumentCache 而不是UserCache,因为文档的所有用户都可以并且应该看到相同的单元格值。

    我还建议对函数签名进行更健壮的编码,因为您当前的实现能够区分参数[1, 2][12]。您可以对输入进行字符串化,然后对其进行 base64 编码以实现紧凑性:

    function encode(functionName, argumentsPassed) {
      var data = [functionName].concat(argumentsPassed);
      var json = JSON.stringify(data);
      return Utilities.base64Encode(json);
    }
    

    【讨论】:

    • 这是添加新列或行时自定义函数更新的视频 (youtube.com/watch?v=t677lw2TeGQ)。如果函数将单元格引用作为参数并且该单元格被移动(添加了列或行),则自定义函数会更新。此外,如果包含自定义函数的单元格添加了行/列,它也会更新。理想情况下,我会阻止该自定义函数更新。
    • YouTube 不会加载视频,说它不可用。你能检查 ACL 吗?
    • 应该没问题,只是再次将其更改为未列出。感谢您抽出宝贵时间。
    最近更新 更多