javascript - Google 脚本/将执行时间减少到执行时间限制以下

标签 javascript google-apps-script google-sheets

编辑#2:

我决定尝试对所有电子邮件发出后运行的复制粘贴操作进行批处理。在之前发布的代码中,在每个循环的最后几行中,我将每个采购订单(“电子邮件”表)中的项目复制并粘贴到另一个(“AsignRec”)中。现在,我想做的是将每个循环中“Email”表中的项目存储到 Javascript 数组中,然后将所有内容粘贴到最后的“AsignRec”中,只需一次。

但是,我还是没有做对。我陷入了最后的粘贴/setValues()。我相信该数组的格式正确,因为它的长度为 49,这是发送给 vendor 的唯一 SKU 的数量。尽管如此,在 setValues([OCitems]) 第 185 行,我收到错误“范围高度不正确,为 1,但应该为 49(第 185 行,文件“TestArrayMultiple4”)”。

我认为这意味着目标/输出范围与数组/输入(称为 OCitems)的大小不同。但我不明白为什么,因为我使用 OCitems.length 定义了输出范围的长度。我错过了一些东西,但不确定是什么。

这是代码的重要部分,完整代码如下。与之前相同的 GDocs 链接,脚本文件 TestArrayMultiple4,第 160-185 行。 https://docs.google.com/spreadsheets/d/1yzvMTh0VYhRhiexNzQPIjTwz1FCMq4XnbpGvCF1FYu8/edit#gid=436022027

    /// Get Range we want to change to creating Javascript array and paste at end only

var OcNoHeader = sheet.getRange("B9:J" + MaxTableRow).getValues(); // get items to send to supplier from "Email Sheet"

// if supplier number is 1, create array "OCitems" by storing OcNoHeader. If not supplier #1, then append to existing array "OCitems"

  if(y == 1){
    var OCitems = OcNoHeader}
    else
      {for(j=0;j<OcNoHeader.length;j++){
      OCitems.push(OcNoHeader[j]);
  }}


  Logger.log(OCitems);
  Logger.log("OCitems length = " + OCitems.length)

  debugger;

i++; // after firing email, y+1 to go to next supplier
Logger.log("i++ IF =" + 1);

Logger.log("new i ELSE =" + 1)

debugger;

} // only do while x = max number of suppliers reached
  while (i < x);  

  sheet3.getRange(3, 3, OCitems.length, 9).setValues([OCitems]); // paste operation, NumRows set equal to length of array

==========================

编辑#1:致力于使用多个单元格的 getValues 来提高性能,而不是多次执行单独的 getValue() 。 不幸的是,这并没有以稳定或明显的方式减少执行时间(有时在 6 分钟前完成,有时则不然)。

在下面发布代码(您可以在下面共享的新工作表中的脚本文件“TestArrayMultiple2”中访问它):

使用执行记录,我发现虽然之前花费很长时间的 getValue() 行的执行时间基本上已减少到零,但其他代码行现在花费更多时间并消除了批处理所获得的 yield 其他 getValue()。

特定单元格上仍然有 4-5 个“单独”getValue()(比以前少得多),但我不明白为什么它们会花费这么长时间。如此看来,即使我去掉了剩下的“个别”getValue(),如果只剩下一个的话,需要的时间会更长。

在我看来,它与缓存有关(我确信我没有完全理解这个概念),原因如下: 1) 循环中的第一个 getValue() 总是花费最长的时间。 2)我尝试走不同的路线,通过更改所有电子邮件发送后发生的复制/粘贴操作的代码(“TestArrayMultiple2”脚本文件中的第150行)。我基本上尝试创建一个数组,该数组在每个循环(追加/推送方法)中获取更多数据,但不会在每个循环中粘贴 - 这个想法是在完成循环后将所有数据粘贴到最后。我仍然不正确(第二个脚本文件是最后一个,“TestArrayMultiple3”),但我可以看到电子邮件的发送速度要快得多。

再次感谢您的帮助。

> // version with 1 getDataRange array which stores for supplier ID, name, email, MaxTableRow for PO email, email subject all from Dashboard sheet

function TestArrayMultiple2() {

  var ss = SpreadsheetApp.getActiveSpreadsheet ();
  var sheet = ss.getSheetByName("Email"); 
  var sheet1 = ss.getSheetByName("Pedido email");
  var sheet2 = ss.getSheetByName("Dashboard");
  var sheet3 = ss.getSheetByName("AsignRec");
  var sheet4 = ss.getSheetByName("ListadoProductos");
  var sheet5 = ss.getSheetByName("Registro-Consolid");
  var sheet6 = ss.getSheetByName("Registro-Unico");

  var x = ss.getSheetByName("Dashboard").getRange("C4").getValue();
  Logger.log("x = " + x)

  var offsetV = 4; // number of rows of offset for email status to be inserted in Dashboard sheet 

  var OffSetColProv = 1; // column in Dashboard sheet with supplier name
  var OffsetColMaxPOrows = 3; // Number of unique SKUs or rows in PO. Replace MaxTableRow formula in Email Sheet
  var OffSetColPzas = 4; // column in Dashboard sheet with number of items in supplier purchase order. 
  var OffSetColEmail = 5; // column in Dashboard sheet with supplier email
  var OffSetColCC = 13; // column in Dashboard sheet with supplier email CC
  var OffSetColSubject = 14; // column in Dashboard sheet with supplier email Subject

  var colStatus = 11; // column in Dashboard sheet where send status of email inserted -----> LEAVE AS IS FOR NOW, not an offset, is fixed, col. K = 11
  var OffsetEmailRows = 8 // number of rows in Email sheet before the items in PO are shown

  var ProvNumEmail = sheet.getRange(1,2); // Supplier number in email sheet used to refresh products in purchase order email via FILTER formula

  var StatusRange = sheet2.getRange("K5:K100");
  Logger.log("StatusRange = " + StatusRange)

  var currentTime =  new Date();
  var timestamp = Utilities.formatDate(currentTime,'GMT-0600','dd/MM/yyyy HH:mm:ss');
  Logger.log("timestamp = " + timestamp);

  var ProvArray = sheet2.getRange("E5:S100");
  var DashValues = ProvArray.getValues();

  i = 0;

  do {


  var y = DashValues[i][0];
  Logger.log("y = " + y)

  ProvNumEmail.setValue(y);   // set value of next supplier in Email sheet to load next purchase order products


    // emails var here in order to update email value in IF email = ERROR condition and skip to else

  var Prov = DashValues[i][OffSetColProv];
  Logger.log("Prov = " + Prov);

  var EmailSubject = DashValues[i][OffSetColSubject];
  Logger.log("EmailSubject = " + EmailSubject)

  var MaxTableRow = DashValues[i][OffsetColMaxPOrows] + OffsetEmailRows;
  Logger.log("MaxTableRow = " + MaxTableRow)

  var EmailTo = DashValues[i][OffSetColEmail];
  Logger.log("EmailTo = " + EmailTo)

  var EmailCC = DashValues[i][OffSetColCC];
  Logger.log("EmailCC = " + EmailCC)

  var Piezas = DashValues[i][OffSetColPzas];
  Logger.log("Piezas = " + Piezas)

  SpreadsheetApp.flush();

  var name = "Petsy Compras - Juan Carlos León";
  var ReplyToEmail = "compras@petsy.mx";
  var email = EmailTo;
  var subject = EmailSubject;
  var name = name;
  var replyTo = ReplyToEmail;
  var Emailcc = EmailCC;
  var schedRange = sheet.getRange("B7:J"+MaxTableRow);
  var body = '<div>';            
    body += "Estimados," +'<br>' + '<br>';
    body += "Envío la orden de compra, por un total de " + '<b>' + Piezas + " piezas." + '</b>' +'<br>' + '<br>';
    body += "Favor de confirmar las existencias lo más rápidamente posible, dentro del mismo correo y"+ '<b><a style="color:#FF0000">'+ " enviar factura a: "+ '</a></b>' + "facturasproveedores@petsy.mx." +'<br>' + '<br>';
    body += "Al dar " +'<b><a style="color:#FF0000"> '+ "RESPONDER A TODOS" + '</a></b>' +" la tabla con los productos pedidos se hace editable: favor de marcar por cada item si será faltante." +'<br>' + '<br>';
    body += "Cualquier duda avísenme por favor." +'<br>' + '<br>';
    body += "Un saludo" +'<br>' + '<br>';
    body += '<b>'     + "Juan Carlos León" + '<b>' + '<br>';
    body += "Petsy Compras"+'<br>';
    body += "Mapa aquí: "+'<br>';
    body += "Fijo directo 1: (55) 68 12 07 97 / Fijo directo 2: (55) 68 12 07 99 / Cel y Whatsapp: 55 32 23 57 17"+'<br>' + '<br>';
    body += "" +'<br>' + '<br>';
    body += getHtmlTable(schedRange);
    body += '</div>';


  // variables for error email

  var emailERR = 'oscialom@petsy.mx'
  var subjectERR = 'ERROR ENVIO OC' + ' // ' + Prov + ' ' + timestamp


  if(email == 'ERROR' || MaxTableRow == 0) // skip condition to go begin loop with y+1

{

// if above skip condition is true, y+1 to move to next purchase order

  Logger.log("y = " + y);
  Logger.log("IF");
  sheet2.getRange(y + offsetV,colStatus).setValue('NOT_SENT'); // set email send status next to supplier in Dashboard sheet
  {
     GmailApp.sendEmail(emailERR, subjectERR, "Requires HTML", 
                { 
                    'name':name, 
                    'replyTo':replyTo,
                    'htmlBody':'', 
                    'cc':''});
        }


  i++;

  Logger.log("new i IF =" + 1);
  continue

}
else
{

  // if skip condition is false, fire current supplier purchase order email email

  Logger.log("i = " + i);
  Logger.log("y = " + y);
  Logger.log("ELSE");

  GmailApp.sendEmail(email, subject, "Requires HTML", 
                { 
                    'name':name, 
                    'replyTo':replyTo,
                    'htmlBody':body, 
                    'cc':EmailCC});
        }        

sheet2.getRange(y + offsetV,colStatus).setValue('OK'); // set email send status next to supplier in Dashboard sheet



// START copy-paste Asign-Rec

var MaxTableRowASIGN = sheet3.getRange("A1").getValue();
Logger.log("MaxTableRowASIGN = " + MaxTableRowASIGN)


/// Get Range we want to change to creating Javascript array and paste at end only

  debugger; // stop debugger at this point !! REMOVE OR PLACE AT CORRECT LINE IF USING DEBUGGER

var OcNoHeader = sheet.getRange("B9:J" + MaxTableRow);
var ConsolAsignRec = sheet3.getRange("B3:K" + MaxTableRow);
var ProvOC = sheet.getRange("B2").getValue();
Logger.log("ProvOC = " + ProvOC)

var MaxRowB = sheet3.getRange("C1").getValue() + 1;
Logger.log("MaxRowB = " + MaxRowB);

var NextRowB = MaxRowB + 1;
Logger.log("NextRowB = " + NextRowB);

OcNoHeader.copyTo(sheet3.getRange(MaxTableRowASIGN + 1,3),{contentsOnly:true});
var NumRowsProv = OcNoHeader.getNumRows();

var ProvOCcolumn = sheet3.getRange(MaxRowB, 2, NumRowsProv)
Logger.log("ProvOCcolumn = " + ProvOCcolumn);

ProvOCcolumn.setValue(ProvOC);

// END copy-paste Asign-Rec

i++; // after firing email, y+1 to go to next supplier
Logger.log("i++ IF =" + 1);



Logger.log("new i ELSE =" + 1)



} // only do while x = max number of suppliers reached
  while (y<x);  

  // set y = 1 to reset value again after finishing loop 

  sheet.getRange(1,2).setValue(1); // reset ProvNumber = 1 to start again next time script is fired.

  var EmailsSent = sheet2.getRange("C10").getValue(); // set values
  Logger.log("EmailsSent = " + EmailsSent)

  var EmailErrors = sheet2.getRange("C11").getValue();
  Logger.log("EmailErrors = " + EmailErrors)

  var MaxTableRowEND = sheet2.getRange("C9").getValue();
  var schedRange = sheet2.getRange("E4:K" + MaxTableRowEND);
  var emailEND = "oscialom@petsy.mx";
  var subjectEND = 'OCs Inbound enviadas' + ' ' + timestamp + " (errores " +  EmailErrors + " / enviados " + EmailsSent + ")";
  var EmailCCEND = "";
  var bodyEND = getHtmlTable(schedRange);

   GmailApp.sendEmail(emailEND, subjectEND, "Requires HTML", 
                { 
                    'name':name, 
                    'replyTo':replyTo,
                    'htmlBody':bodyEND, 
                    'cc':EmailCCEND});

StatusRange.clearContent();


/// START RecordTimestamp code

  var Avals = sheet4.getRange("A1:A").getValues();
  var lastrow1 = Avals.filter(String).length;
  Logger.log('lastrow1 =' + lastrow1)

  var Avals2 = sheet5.getRange("A1:A").getValues();
  var lastrow2 = Avals2.filter(String).length;
  Logger.log('lastrow2 =' + lastrow2)

    sheet4.getRange("B2:B" + lastrow1).copyTo(sheet5.getRange(lastrow2 + 1, 1)) // copy order-items to Registro sheet, after last filled row

    sheet4.getRange("K2:K" + lastrow1).copyTo(sheet5.getRange(lastrow2 + 1, 2)) // copy Prov1 to Registro sheet, after last filled row


  var Avals3 = sheet5.getRange("C1:C").getValues();
  var lastrow2c = Avals3.filter(String).length;
  Logger.log('lastrow2c =' + lastrow2c);


  if(lastrow2 == 1)
  { sheet5.getRange(lastrow2c + 1, 3, lastrow1 - 1).setValue(timestamp)
    Logger.log('IF')

    }

    else
    {
    sheet5.getRange(lastrow2c + 1, 3, lastrow1 - 1).setValue(timestamp)
    Logger.log('ELSE')
    }

var MaxTableRowEMAIL = sheet6.getRange("G5").getValue()

var subject = "Items pedidos en OC automatizada " + timestamp
var email = "oscialom@petsy.mx";
var EmailCC = "";
var EmailBCC;
var name = "Petsy Compras";
var ReplyToEmail = "compras@petsy.mx"
var schedRange = sheet6.getRange("A1:C" + MaxTableRowEMAIL);
var body = getHtmlTable(schedRange);  


{
     GmailApp.sendEmail(email, subject, "Requires HTML", 
                { 
                    'name':name, 
                    'replyTo':ReplyToEmail,
                    'htmlBody':body, 
                    'cc':''});
        }

/// END RecordTimestamp code


Logger.log("MaxTableRowASIGN " + MaxTableRowASIGN);

var endtime = new Date();
Logger.log("timestamp end " + timestamp);
Logger.log("endtime " + Utilities.formatDate(endtime,'GMT-0600','dd/MM/yyyy HH:mm:ss'));

var scripttime = (endtime - currentTime);
Logger.log("scripttime original" + scripttime);

// strip the ms
scripttime /= 1000;
Logger.log("scripttime / 1000" + scripttime);

// get seconds (Original had 'round' which incorrectly counts 0:28, 0:29, 1:30 ... 1:59, 1:0)
var seconds = Math.round(scripttime % 60);
Logger.log("scripttime % 60" + scripttime);

// remove seconds from the date
scripttime = Math.floor(scripttime / 60);
Logger.log("scripttime / 60" + scripttime);

// Browser.msgBox("Script completado en " + seconds + " segundos",Browser.Buttons.OK_CANCEL); // removed MsgBox to measure real execution time
Logger.log("seconds " + seconds)

}  

======================

原帖

我编写了一个 Google 脚本来自动执行多个 vendor 的采购订单流程。该流程获取产品列表(来自工作表 ListaProductos),将产品信息格式化为电子邮件格式(工作表“电子邮件”),发送电子邮件,然后进行一些复制/粘贴到同一电子表格的其他工作表中。 但是,我总是遇到脚本执行时间在 75% 左右的情况。我对此还很陌生,一直在阅读,但坦率地说,我不知道下一步该尝试什么。

最佳答案

我在这部分代码中看到了问题:

do { 
  // read info from the sheet
  range.getValue();
  // more code here...

} // only do while x = max number of suppliers reached
  while (y<x)

操作getValue需要很长时间才能运行。最佳实践是使用整个范围:

var data = sheet.getDataRange().getValuses();

然后使用数据作为进一步计算的来源。

在此处查看更多信息:

https://developers.google.com/apps-script/best_practices

关于javascript - Google 脚本/将执行时间减少到执行时间限制以下,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43108046/

相关文章:

google-apps-script - 如何使用谷歌应用脚​​本重置谷歌表单计数器值

javascript - Google Apps 脚本内连接范围

google-apps-script - 如何将 Google 表格文件转换为 Excel 文件 (XLSX)

javascript - 单词搜索游戏。如何搜索网格并突出显示结果?

google-apps-script - Google Apps 脚本通过电子表格发送电子邮件

php - 选定的下拉列表项 - 调用/获取数据

HTML 表格根据条件更改文本颜色

django - 在网页中嵌入可编辑的 Google 文档电子表格

javascript - 如何从跨度内的类中检索数据?

javascript - 主干模型 urlroot