【GAS】ランタイムエラー、タイムアウト対応(6分の壁)

コピペでできるGAS

GAS応用の一覧

ご訪問ありがとうございます。

Googleシートマスターのひろしです。

前回

【GAS】スプレッドシートから一気にデータを読み込む方法(2次元配列攻略)
  • GASでスプレッドシートから一気にデータを取得する方法がわかります。
  • チェックボックスのON/OFFで処理を変更する方法がわかります。
  • 今回は、とっても価値の高い方法をお伝えします。


    これを知ることであなたは、

    • GASで処理をスピードアップする方法がわかります。
    • タイムアウトする際の基本的な対処方法がわかります。

    なので、サクッとマスターして

    と答えてあげてください。

     

    ご質問

    いただいたご質問です。

    私の動画の通りやったらタイムアウトが発生したとのこと。

    では、改善策を考えてみましょう。

     

    動画はこちら

    シートはこちら

    *クリックすることでシートが開きます。(コピーしてお使いください)

     

    ポイント

    まず、GASには、サーバ側で実行されます。

    その際に、スプレッドシートの表示を伴う関数の場合、毎回
    パソコンとサーバとの通信が発生するので遅くなってしまいます。

    しかも、GASには6分でタイムアウトというルールがあるのです。

    今回の場合、以下のように

    a.行をチャックするたびに通信が発生
    b.行を削除するたびに通信が発生
    しかも行を削除する際は、再描画が必要となるのでかなり負荷がかかります。

    なので、これらをサーバ側で行えば、速度は改善するはずです。

     

     

    スクリプト

    案1。

    1行ずつパソコンからデータを取得するのではなく、D列のデータを
    一気に取得してやってみました。

    一応、1シート2分以内なので、3シートでもなんとかいけます。

    とはいえ、一応トリガーを使ってやってみました。

    トリガーを使う

    以下は、proA()を最初に起動します。

    ①proA()
    ②「プロジェクトA」シートに対する処理
    ③1分後にproB()を実行するようにトリガーを設定
    ④proB()
    ⑤「プロジェクトB」シートに対する処理
    ⑥1分後にproC()を実行するようにトリガーを設定
    ⑦「プロジェクトC」シートに対する処理

    となります。

    function setTrigger(function_name) {
      let triggers = ScriptApp.getScriptTriggers()
      for (let trigger of triggers) {
        if (trigger.getHandlerFunction() == function_name) {
          ScriptApp.deleteTrigger(trigger)
        }
      }
      // 1分後にトリガーをセット(1分 = 60秒 = 1秒*60 = 1000ミリ秒 * 60)
      ScriptApp.newTrigger(function_name).timeBased().after(1000 * 60).create();
    }
    
    
    
    function proA() {
      deletecompData('プロジェクトA')
      setTrigger('proB')
    }
    function proB() {
      deletecompData('プロジェクトB')
      setTrigger('proC')
    }
    function proC() {
      deletecompData('プロジェクトC')
      // setTrigger('proB')
    }
    
    
    function deletecompData(shname) {
      // const SH_NAME = ['プロジェクトA', 'プロジェクトB', 'プロジェクトC']
    
    
      // SH_NAME.forEach(shname => {
    
    
      // const shname = 'プロジェクトA のコピー'
      console.log(shname)
    
    
      const sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(shname)
      let buffs = sh.getRange("D4:D100").getValues()
      for (let i = buffs.length - 1; i >= 0; i--) {
        // console.log(buffs[i][0],"行番号 ",i+4)
        if (buffs[i][0] == "完了") {
          console.log("行番号 ", i + 4)
          sh.deleteRow(i + 4) //行の削除
        }
      }
      // })
    
    
    
    
    }
    シートまるまるコピペ

    案2.

    今度は、一気にすべて読み込んでやってみます。

    こんなイメージです。

    /**
     * シートのコピーと行の削除
     * 1.シートをコピーし
     * 2.データの読み込み
     * 3.ステータスが完了の行をバッファに入れる
     * 4.コピーしたシートの不要部分を削除
     * 5.バッファをシートに反映させる
     */
    function sheetCopyDelline() {
      const ss = SpreadsheetApp.getActiveSpreadsheet()
      const ssh = ss.getSheetByName('プロジェクトA')
    
    
      //1.コピー対象シートを同一のスプレッドシートにコピー
      let dsh = ssh.copyTo(ss);
      console.log(dsh.getSheetName())
    
    
    
      //2.チェックする範囲をすべて読み込む
      let buffs = ssh.getRange("A4:AI1003").getValues()
      // let buffs = ssh.getRange(4,1,ssh.getLastRow(),"A4:AI1000").getValues()
      let destbuffs = ssh.getRange("A4:AI4").getValues()    //ダミーで1行読み込む
      let delrows = 0 //削除する行数
    
    
      //3.完了以外のデータをバッファに格納する
      buffs.forEach(buff => {
        if (buff[3] == '完了') {
          delrows++
        }
        else {
          destbuffs.push(buff)
        }
      })
    
    
      console.log("delrows => ", delrows, " 完了 => ", destbuffs.length)
      destbuffs.shift()   //ダミーを削除する
    
    
      //4.コピー先シートの不要な行を削除する
      dsh.deleteRows(1003 - delrows + 1, delrows)
    
    
      //5.完了以外のデータ(destbuffs)をシートに反映させる
      dsh.getRange(4, 1, destbuffs.length, destbuffs[0].length).setValues(destbuffs)
    
    
    
    
    
    
    }
    
    

     

    あ、よく考えたらシートをコピペする必要はないですね。
    動画では、コピペしてやっていますが、うまくいくことが確認できれば、
    上記のシートのコピー処理および以下の処理は不要ですね。

    //シートのリネームと削除
    function renamesheet() {
      const ss = SpreadsheetApp.getActiveSpreadsheet()
      const ssh = ss.getSheetByName('プロジェクトA')
    
    
      //コピー対象シートを同一のスプレッドシートにコピー
      let dsh = ssh.copyTo(ss);
      dsh.setName("プロジェクトA ★")
    
    
    
      //シートの削除
      // ss.deleteSheet(ssh)
    }

     

    最後までご覧いただきありがとうございます。

    つぎはこちら

    【GAS】指定の数量数分セルをコピーする方法(Gスプレッドシート)
  • 2次元配列への格納方法がわかります。
  • setValuesの使い方がわかります。
  • GAS応用の一覧

    コメント

    タイトルとURLをコピーしました