2

スプレッドシートから行データを取得してそれらをループし、行のデータが特定の条件 (たとえば、電話番号があり、まだ送信されていない) を満たしている場合に SMS を送信する関数を呼び出すスクリプトを作成しました。

しかし、約600行を追加した後、スクリプトの実行時間が制限を超えました.私の調査によると、それは5分であるようです. JavaScript オブジェクトを使用してデータを読み取り、for ループを使用して行を反復処理しています。

より速くすることが可能かどうか、誰でも教えてもらえますか? 私はプログラミングに非常に慣れていませんが、これはすべての計算能力に対して非常に軽いタスクのように思え、なぜそんなに時間がかかるのか理解できません

前もって感謝します!

私が使用している関数のコードは次のとおりです。

// Will send SMS on the currently active sheet
function sendSms() {

  // Use the send sms menu to trigger reconcile
  var user = ScriptProperties.getProperty(PROPERTY_USER_RECONCILE);
  if (user == null)
    reconcileUser();

  // The sheets
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Registo");
  var settingsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");

  // Fetch values for each row in the Range.
  var startRow = 2;
  var apiKey = settingsSheet.getRange("B2").getValue();
  var apiSecret = settingsSheet.getRange("B3").getValue();
  var prefix = settingsSheet.getRange("B4").getValue();
  var numRows = sheet.getMaxRows() - 1;
  var numCols = 16;
  var statusColNum = 15;  // IMPT: To keep track status in col 15
  var dataRange = sheet.getRange(startRow, 1, numRows, numCols);

  // Make sure there is API key and secret
  if (apiKey == "" || apiSecret == "") {
    Browser.msgBox("You MUST fill in your API key and secret in Settings sheet first!");
    return;
  }

  // Create one JavaScript object per row of data.
  var objects = getRowsData(sheet, dataRange);

  var totalSent = 0;

  for (var i = 0; i < objects.length; ++i) {
    // Get a row object
    var rowData = objects[i];
    var ss = SpreadsheetApp.getActiveSpreadsheet();
    var templateSheet = ss.getSheetByName("SMS Modelo");
    var template = templateSheet.getRange("A1").getValue();

    // jump loop iteration if conditions not satisied
    if (rowData.resolv == "x" || rowData.contactoUtente == null || rowData.contactoUtente == "" || rowData.reserv == null || rowData.reserv == "" || rowData.cont == "x" || rowData.sms !== null) continue;
      var message = fillInTemplateFromObject(template, rowData);
      var senderName = "Farm Cunha"
      var mobile = rowData.contactoUtente;
      // Send via Nexmo API
      var response = nexmoSendSms(apiKey, apiSecret,"+351" + mobile, message, senderName);
      if (response.getResponseCode() == 200) {
        var object = JSON.parse(response.getContentText());
        if (object.messages[0]['status'] == "0") {
          // Set to QUEUE status - We assumed SENT, as we don't handle delivery status.
          //sheet.getRange(startRow + i, statusColNum).setValue(STATUS_QUEUE);
          sheet.getRange(startRow + i, statusColNum).setValue(STATUS_SENT);
          // Set the reference id
          sheet.getRange(startRow + i, 19).setValue(object.messages[0]['message-id']);
          // sheet.getRange(startRow + i, statusColNum+3).setValue(new Date()); linha pode ser activada para fazer timestamp do envio
          totalSent++;
          }
        else {
          // If status is not 0, then it is an error.
          // Set status to the error text
          sheet.getRange(startRow + i, statusColNum).setValue(object.messages[0]['error-text']);
        }
      }
      else {
        // Non 200 OK response
        sheet.getRange(startRow + i, statusColNum).setValue("Error Response Code: " + response.getResponseCode);
      }
      SpreadsheetApp.flush();
      // Need a wait. Need to throttle else will have "Route Busy" error.
      Utilities.sleep(2000);
  }

  // Update total sent
  var lastTotalSent = parseInt(ScriptProperties.getProperty(PROPERTY_SMS_SENT_FOR_RECONCILE));
  if (isNaN(lastTotalSent)) lastTotalSent = 0;
  ScriptProperties.setProperty(PROPERTY_SMS_SENT_FOR_RECONCILE, (lastTotalSent + totalSent).toString());
  Logger.log("Last sent: " + lastTotalSent + "  now sent: " + totalSent);
  reconcileApp();
}
4

2 に答える 2

5

ループには時間がかかりすぎるものがいくつかあります: スプレッドシートの読み取りと API 呼び出し + 2 秒のスリープ!.

これらをループから外すことをお勧めします (特に、テンプレート シートの読み取りは常に同じです!)。考えられる解決策は、行オブジェクトから条件を確認し、有効なエントリを配列に保存することです...次に、この配列で反復処理して API を呼び出します。

これでも長すぎる場合は、小さなバッチで処理を進め、部分反復の終了位置をスクリプト プロパティに保存し、完了するまで 5 分ごとにプロセスを続行するタイマー トリガーを使用します (最後にトリガーを強制終了します)。

このフォーラムには、この種の「メカニズム」の例がいくつかあります。私が提案した最近の例の 1 つをここに示します(ドラフトに似ていますが、アイデアはそこにあります)。

于 2013-03-08T22:10:35.570 に答える
4

わかりました、Serge(ありがとう)が私に言ったように、これらの3行をループから外して解決しました:

 var ss = SpreadsheetApp.getActiveSpreadsheet();
    var templateSheet = ss.getSheetByName("SMS Modelo");
    var template = templateSheet.getRange("A1").getValue();

どうしてそれを見なかったのかわからないほど単純です。

この単純な変更により、スクリプトが大幅に高速化されました。たとえば、600 行を処理するには 5 分以上かかります。現在、5000 行を超える行は数秒しかかかりません。

于 2013-03-12T12:47:54.000 に答える