Есть ли лучший способ для скрипта применить группировку к каждому листу?

#google-apps-script #google-sheets

#google-apps-script #google-sheets

Вопрос:

Я написал несколько сценариев, которые помогут мне очистить / сбросить рабочий лист, который мы используем каждую неделю. Идея в том, что у нас есть ~ 50 человек, которые используют это, и из-за сочетания злого умысла и невежества они часто находят способы обойти наши разрешения и редактировать то, что мы не хотим, чтобы они делали. В последнее время этот рабочий лист стал настолько большим, что время ожидания моих плохо написанных сценариев истекает до достижения конца. (В настоящее время у нас ~ 250 листов.) Я смог переписать большинство из них и значительно сократил время выполнения. Однако один шаг продолжает меня замедлять: удаление и повторное применение полос к определенному диапазону (A5: H27) на каждой странице.

Есть ли способ, которым я могу сделать этот код более эффективным и сократить время выполнения с ~ 12 минут для этого шага?

 function fixBanding(){
  var spreadsheet = SpreadsheetApp.getActive();
  var allSheets = spreadsheet.getSheets();
  
  allSheets.forEach(function(sheet){
    if(sheet.getSheetName() !== "HelperSheet"){
      sheet.getRange('A5:H27').activate();
      sheet.getRange("A5:H27").getBandings().forEach(banding => banding.remove());
      sheet.getRange("A5:H27").applyRowBanding()
        .setHeaderRowColor('white')
        .setFirstRowColor('#cbcbcb') //med grey
        .setSecondRowColor('white');
    }
  })
}
 

Ответ №1:

Я считаю, что ваша цель заключается в следующем.

  • Ваш скрипт работает нормально. И вы хотите снизить стоимость обработки вашего скрипта.

В этом случае, как насчет использования Sheets API? Когда используется API Sheets, стоимость процесса может быть немного снижена. Когда в вашем скрипте используется API Sheets, это выглядит следующим образом.

Модифицированный скрипт:

Перед использованием этого скрипта, пожалуйста, включите Sheets API в расширенных сервисах Google.

 function myFunction() {
  // Retrieve sheet IDs and andedRange IDs.
  const ss = SpreadsheetApp.getActive();
  const spreadsheetId = ss.getId();
  const { sheetIds, bandedRangeIds } = Sheets.Spreadsheets.get(spreadsheetId, { fields: "sheets(properties(sheetId,title),bandedRanges(bandedRangeId))" }).sheets.reduce((o, { properties: { sheetId, title }, bandedRanges }) => {
    if (title != "HelperSheet") {
      o.sheetIds.push(sheetId);
      o.bandedRangeIds = [...o.bandedRangeIds, ...bandedRanges.map(({ bandedRangeId }) => bandedRangeId)];
    }
    return o;
  }, { sheetIds: [], bandedRangeIds: [] });
  
  // Create the request body for Sheets API.
  const firstBandColor = { red: 0.79, green: 0.79, blue: 0.79 };
  const secondBandColor = { red: 1, green: 1, blue: 1 };
  const headerColor = { red: 1, green: 1, blue: 1 };
  const requests = [...bandedRangeIds.map(id => ({ deleteBanding: { bandedRangeId: id } })), ...sheetIds.map(sheetId => ({ addBanding: { bandedRange: { rowProperties: { headerColor, firstBandColor, secondBandColor }, range: { sheetId, startRowIndex: 4, endRowIndex: 27, startColumnIndex: 0, endColumnIndex: 8 } } } }))
  ];
  
  // Request to Sheets API using the created request body.
  Sheets.Spreadsheets.batchUpdate({ requests }, spreadsheetId);

  // If you want to activate 'A5:H27' in each sheet, please use the following script.
  // SpreadsheetApp.flush();
  // ss.getSheets().forEach(sheet => {
  //   if (sheet.getSheetName() !== "HelperSheet") sheet.getRange('A5:H27').activate();
  // });
}
 

Ссылки:

Комментарии:

1. ооооочень да! Держу пари, это ускорит процесс. Я раньше не играл с API Sheets. Спасибо!

2. @JD03 Спасибо за ответ. Когда используется API Sheets, есть случай, когда стоимость процесса может быть снижена. Кроме того, я подумал, что в вашем вопросе это можно использовать.

Ответ №2:

Похоже, ваш код достаточно оптимизирован, я думаю, вы можете разделить запуск на несколько запусков:
1) В начале цикла инициализируйте переменную date для хранения текущего времени
2) при циклическом просмотре листов продолжайте проверять общее время, прошедшее с момента запуска
3) если общее времяболее 80% от общего доступного времени выполнения скрипта (6 минут), затем запустите новое расписание запуска после, скажем, 20-секундного устанавливаемого триггера
4) а также сохранить номер или имя листа, до которого вы уже выполнили обработку, в новом листе Excel (скажем, config)
5) при запуске триггера код должен принимать имя / номер листа с листа «config», который является листом, до которого вы уже выполнили обработку.обработка уже выполнена, и начните обработку после этого номера листа.

Комментарии:

1. ооооо! Мне нравятся эти предложения. Спасибо!