【问题标题】:Google Apps Script - How do I create a trigger for a function with a parameter? [duplicate]Google Apps 脚本 - 如何为带参数的函数创建触发器? [复制]
【发布时间】:2018-01-04 20:18:30
【问题描述】:

我正在为我的加密货币开发跟踪器。在以下函数中,我从 API 获取数据并放入单元格中。例如,当我想以美元计算比特币的价值时,我将公式 =getCryptodata("bitcoin", "price_usd") 放在一个单元格中,它会返回当前价格。

  function getCryptoData(coin, api) {

  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheets()[0];

  var url = 'https://api.coinmarketcap.com/v1/ticker/' + coin + '/';
  var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
  var json = response.getContentText();
  var data = JSON.parse(json);

  return parseFloat(data[0][api]);

  }

我希望价格每分钟更新一次,因此我为该功能设置了触发器。现在突然好像有问题了。每次触发该功能时,都会出现此错误(在我的邮箱中)。

TypeError:无法从未定义中读取属性“(class)@35c554a5”。

当我从脚本编辑器运行脚本时,我遇到了同样的问题。然后我想出了检查函数中的参数是否定义的想法,如果没有,则给它们一个通用值。谷歌似乎对未定义的参数有问题(尽管它们是在工作表中定义的)。所以我在函数中已有的行之前添加了这些行。

  if (typeof coin == 'undefined') {
    var coin = "bitcoin";
  }
  if (typeof api == 'undefined') {
    var api = "price_usd";
  } 
  else {

现在错误消失了,但是触发函数时值没有更新。

我错过了什么?

【问题讨论】:

    标签: google-apps-script


    【解决方案1】:

    所以这里发生了一些事情:

    • 您正在尝试加载一个活动的电子表格,但是当您触发一个脚本时,没有活动的电子表格。 (你为什么要加载这个电子表格?你似乎没有用它做任何事情)
    • 您的脚本返回一个值,但如果您的脚本是从计划触发的(因此不是从另一个函数触发的),则返回的值将返回为空。您需要将此值放在有用的地方。

    解决此问题的方法是直接将 API 中的值放入工作表中。为此,脚本需要稍作改动。

    例子:

    function getCryptoData(coin, api, target) {
    
      var ss = SpreadsheetApp.openById("YOUR-ID-HERE"); // The script has no active spreadsheet so make sure to acquire the spreadsheet by providing the ID
      var sheet = ss.getSheets()[0];
    
      var url = 'https://api.coinmarketcap.com/v1/ticker/' + coin + '/';
      var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
      var json = response.getContentText();
      var data = JSON.parse(json);
    
      SpreadsheetApp.getRange(target).setValue(parseFloat(data[0][api])); // Write the returned value directly to the range (e.g. A1) that was specified as an argument
    
    }
    

    因此,使用这样的函数,您可以创建另一个函数,每隔一段时间触发一次以更新您的值:

    function updateCryptoData() {
      getCryptodata("bitcoin", "price_usd", "B2");
      getCryptodata("bitcoin", "price_usd", "C2");
    }
    

    如果您选择使用这样的解决方案,则无需再在工作表中添加公式。

    注意:从性能的角度来看,此解决方案并不是最佳的。但是,我尝试对您自己的代码进行尽可能少的代码更改以使其正常工作。理想情况下,您只需为每种硬币类型调用一次 API。

    【讨论】:

    • 好的。谢谢!确实没有必要加载电子表格,但在您的版本中它是:) 所以您会说没有解决方案,我可以将公式放入工作表中,而无需在脚本中指定目标.因为那当然会更有效率。现在我必须为 API 的每次调用编写一行代码。我对此很陌生,所以也许我要求的是不可能的。但是没有一个函数可以返回调用它的单元格吗?比如:var target = currentCell();
    • 你指的是ActiveCell。但是,当您触发该功能时,没有这样的事情。如果您将其设为 onChange/onEdit 触发器,它就会出现。如果触发器是基于时间的而不是基于事件的,则不会有任何可用于活动工作表/范围/单元格的引用。您可以配置脚本以读取范围、读取值然后进行 api 调用。为此,您需要调整getCryptoData,以便从工作表中获取数据,遍历每一行,然后对该行执行 API 调用。
    【解决方案2】:

    使用 fetch 时,您应该注意每天可以从调用中返回的数据量有限制。因为您每分钟都在调用数据,所以很有可能您将/已经超过daily limit.

    【讨论】:

      【解决方案3】:

      这不需要重新加载电子表格。首先,您必须为特定硬币和定价创建触发器。

      function teste()
      {
       trigger_("bitcoin","price_usd","B2");
       trigger_("litecoin","price_usd","B3");
       trigger_("bitcoin","price_usd","B4");
      }
      

      存储触发器对应的数据,参考trigger_id。

      function trigger_(coin,api,target)
      {
       var new_trigger = ScriptApp.newTrigger(getCryptoData).timeBased().everyMinutes(1).create();
       var trigger_id = new_trigger.getUniqueId();
       PropertiesService.getUserProperties().setProperty(trigger_id, coin+","+api+","+target);
      }
      

      当触发器被触发时,它会获取调用 api 并更新目标单元格的相应数据(硬币、价格、目标)。

      function getCryptoData(event) 
      {
      
        var trig = ScriptApp.getProjectTriggers();
        for(var i =0; i<trig.length; i++)
        {
         if(trig[i].getUniqueId()== event.triggerUid )
         {
          var cryptoData = PropertiesService.getUserProperties().getProperty(event.triggerUid);
          cryptoData = cryptoData.split(",");
          var coin = cryptoData[0];
          var api = cryptoData[1];
          var target = cryptoData[2];
          var ss = SpreadsheetApp.openById("YOUR_SPEADSHEET_ID").getSheets(); // change accordingly
          var sheet = ss[0];  // change accordingly
          var url = 'https://api.coinmarketcap.com/v1/ticker/' + coin + '/';
          var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
          var json = response.getContentText();
          var data = JSON.parse(json);
          Logger.log(parseFloat(data[0][api]));
          ss[0].getRange(target).setValue(parseFloat(data[0][api]));
         }
        }
      }
      

      注意:普通用户每天运行触发器的限制为 90 分钟/天 app script quota

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-08
        • 1970-01-01
        • 2021-12-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多