简体   繁体   English

停止自定义函数自动刷新/定期调用外部 API

[英]Stop custom function from auto refreshing/periodically calling external API

I am using Google Apps Script and a custom function to call an external API to verify phone numbers.我正在使用 Google Apps 脚本和自定义函数来调用外部 API 来验证电话号码。

Below is the code for my function.下面是我的函数的代码。

/**
 * This CUSTOM FUNCTION uses the numVerify API to validate 
 * a phone number based on the input from JotForm and a 
 * country code which is derived from the JotForm country
 *
 * Numverify website: https://numverify.com/dashboard (account via LastPass)
 * Numverify docs: https://numverify.com/documentation
 */
function PHONE_CHECK(number, country){
  
  if(country == "")
    return [["", "country_not_set"]]
  
  // check the API result has already been retrieved
  var range = SpreadsheetApp.getActiveSheet().getActiveRange()
  var apires = range.offset(0, 1).getValue()
  if(apires.length > 0)
    return range.offset(0, 0, 1, 2).getValues()
    
    
  var url = 'http://apilayer.net/api/validate'
  + '?access_key=' + NUMVERIFY_KEY
  + '&number=' + encodeURIComponent(number)
  + '&country_code=' + encodeURIComponent(country)
  + '&format=1';

  var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
  var json = response.getContentText();
  var data = JSON.parse(json);
  
  if(data.valid !== undefined){
    if(data.valid){
      return [[data.international_format, "OK"]]
    }else{
      return [["", "invalid_number"]] // overflows data to the next column (API Error) while keeping the phone field clear for import into TL
    }
  }else if(data.success !== undefined){
    if(data.error.type.length > 0){
      return [[number, data.error.type]]
    }else{
      return [[number, "no_error_type"]]
    }
  }else{
    return [[number, "unexpected_error"]] // this generally shouldn't happen...
  }
}

Given this formula, which takes a phone number and country code, it will then check the phone number against the numverify API and return the result in the cell and overflow to the cell to the right of it.给定这个公式,它需要一个电话号码和国家/地区代码,然后它会根据 numverify API 检查电话号码,并将结果返回到单元格中并溢出到它右侧的单元格。 The overflow is used to indicate whether the API was called successfully and to check if the result was already retrieved .溢出用于指示 API 是否被成功调用并检查是否已经检索到结果。

Example: =PHONE_CHECK("+32123456789", "BE")示例: =PHONE_CHECK("+32123456789", "BE")

Note that the first cell is empty because the API returns an 'invalid phone number' code.请注意,第一个单元格为空,因为 API 返回“无效电话号码”代码。 Because of privacy, I won't put any real phone numbers here.由于隐私,我不会在这里放任何真实的电话号码。 In case I would've used a real phone number, the first cell would contain the phone number formatted in the international number format.如果我使用真实的电话号码,第一个单元格将包含以国际号码格式格式化的电话号码。

示例自定义函数输出

Since I'm using the free plan, I don't want to rerun the function every time if I already know what the result is , as I don't want to run up against the rate limit.由于我使用的是免费计划,如果我已经知道结果是什么我不想每次都重新运行该函数,因为我不想遇到速率限制。 Unfortunately, this doesn't seem to work and periodically (it looks like once every day), it will refresh the results for each row in the sheet.不幸的是,这似乎不起作用并且定期(它看起来像每天一次),它会刷新工作表中每一行的结果。

So two questions:所以两个问题:

  1. Is something wrong with my logic in checking the API result and then just exiting the function?我在检查 API 结果然后退出函数时的逻辑有问题吗? (see below for the code) (代码见下文)
  2. If the logic is right, why does Google Sheets seem to periodically ignore (or refresh?) the values in that second column and call the external API anyhow?如果逻辑是正确的,为什么 Google Sheets 似乎会定期忽略(或刷新?)第二列中的值并无论如何调用外部 API?
  var range = SpreadsheetApp.getActiveSheet().getActiveRange() // get the cell from which the function is called
  var apires = range.offset(0, 1).getValue() // get the values directly to the right of the cell
  if(apires.length > 0) // check if there's anything there...
    return range.offset(0, 0, 1, 2).getValues() // return an array that basically just resets the same values, effectively stopping the script from running

Your Aim:你的目标:

You want a custom function, AKA a formula to only run once, or as many times as is necessary to produce a certain result.你想要一个自定义函数,也就是一个公式,它只运行一次,或者运行多少次以产生特定结果。 You want the same formula to write a value to the another cell, for example the adjacent cell, that will tell the formula in future, if it should be run again or not.您希望相同的公式将值写入另一个单元格,例如相邻的单元格,这将在将来告诉公式,是否应该再次运行。

Short Answer:简答:

I'm afraid that values that are evaluated from custom functions AKA formulas are transient, and what you want to accomplish is not possible with them.恐怕从自定义函数 AKA 公式计算的值是瞬态的,并且您想要完成的事情用它们是不可能的。

Explanation:解释:

You can run a quick test with this custom function:您可以使用此自定义函数运行快速测试:

function arrayTest() {
  return [[1, 2, 3, 4 ,5]]
}

If you put this in a cell as below:如果你把它放在一个单元格中,如下所示:

arrayTest 公式演示

You will see that if you delete the formula in the original cell, the overflow values also dissapear.您将看到,如果删除原始单元格中的公式,溢出值也会消失。

Therefore something like the following code will almost always produce the same value:因此,类似于以下代码的内容几乎总是会产生相同的值:

function checkTest() {
  var cell = SpreadsheetApp.getActiveRange()
  var status = cell.offset(0, 1).getValue();
  
  if (status != "") {
    return "already executed" // in your case without calling API
  } else {
    return [["OK","executed"]] // in your case making API call - will happen ~90% of the time.
  }
}

// OUTPUT [["OK","executed"]]

Here I am inserting a row and deleting it to force re-calculation of the formulas.在这里,我插入一行并删除它以强制重新计算公式。

checkTest() 演示

The first thing that Sheets does before re-calculating a formula is that it clears the previous values populated by formula.表格在重新计算公式之前所做的第一件事是清除由公式填充的先前值 Since the conditional statment depends on the value of its previous execution, it will always evaluate to the same result.由于条件语句取决于其先前执行的值,因此它始终会评估为相同的结果。 In your case, it will almost always make the API call .在您的情况下,它几乎总是会进行 API 调用

Confusingly, this is not 100% reliable!令人困惑的是,这不是 100% 可靠的! You will find that sometimes , it will work as you intend.您会发现有时,它会按您的意愿工作。 Though in my tests, this only happened around 1 times out of 10, and most often when the formulas updated when saving changes to the script editor.尽管在我的测试中,这仅发生了大约 10 次中的 1 次,而且最常见的是在将更改保存到脚本编辑器时更新公式。

Ideally, though not possible, you would want to be able to write something like this:理想情况下,虽然不可能,但您希望能够编写如下内容:

function checkTest() {
  var cell = SpreadsheetApp.getActiveRange();
  var cellValue = cell.getValue();
  var adjacentCell = cell.offset(0, 1);
  var status = adjacentCell.getValue();
  
  if (status == "") {
    cell.setValue(cellValue)
    adjacentCell.setValue("executed")
  }
}

Which would clear the formula once it has run, alas, setValue() is disabled for formulas !一旦它运行,这将清除公式,唉,对于公式setValue()禁用 If you wanted to use setValue() you would need to run your script from a menu, trigger or the script editor.如果您想使用setValue()您需要从菜单、触发器或脚本编辑器运行您的脚本。 In which case it would no longer make sense as a formula.z在这种情况下,它作为公式将不再有意义。z

References参考

https://developers.google.com/apps-script/guides/sheets/functions https://developers.google.com/apps-script/guides/sheets/functions

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM