GASのflush()でスプレッドシートの
書き込みを即時反映する方法
setValueしたのに画面がすぐ変わらない、書き込んだ値を読み直すと古いまま——GASでよくあるこのつまずきは、SpreadsheetApp.flush()で解決できます。保留中の変更を今すぐ反映させる仕組みと、進捗表示・途中保存への使い方、多用で遅くならないコツを動くコードで解説します。
Table of Contents
flush()とは何か
SpreadsheetApp.flush()は、それまでにコードで行ったsetValueなどの「保留中の変更」を、その場でスプレッドシートに書き込ませるメソッドです。GASは高速化のため書き込みをいったんためて後でまとめて反映しますが、flush()を呼ぶとそこまでの変更が確定します(flush=ためた変更を「押し流す」イメージ)。
使い方は簡単で、引数も戻り値もありません。反映させたい場所でSpreadsheetApp.flush();と1行書くだけです。
flush() が向く場面
処理の途中で進捗を画面に見せたい/書き込んだ値をすぐ読み直したい/制限時間の前に途中まで保存したい。
flush() が不要な場面
関数の最後にまとめて書くだけ/getValues・setValuesで一括読み書きするだけ。終了時に自動で反映される。
なぜsetValueはすぐ反映されないのか
GASのスプレッドシート操作は、実行するたびにGoogleのサーバーとやり取りします。1回ずつ通信すると遅いため、GASは書き込みを「バッチ(まとめ処理)」にして、必要になったタイミングまで反映を遅らせます。だからsetValueを呼んでも、その瞬間には画面が変わらないことがあります。
function whyDelayed() {
const sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange("A1").setValue("開始");
Utilities.sleep(5000); // この5秒間、画面のA1はまだ空のことがある
sheet.getRange("A2").setValue("終了"); // GASは書き込みをためて後でまとめて反映するため
// 途中でどうしても反映させたいときだけ、その場所でflushを呼ぶ
// SpreadsheetApp.flush();
}この「まとめ処理」は、関数が終了するときや、次に値を読むメソッド(getValueなど)が呼ばれたときに自動で反映されます。つまり、ほとんどの場合はflush()を書かなくても結果は正しく残ります。あえて途中で反映させたい場面だけ、明示的に呼び出すと考えてください。
進捗をtoastで見せながら書き込む
flush()が最も役立つのが、時間のかかる処理の「進捗表示」です。toast()(画面右下に数秒だけ出る通知)と組み合わせ、一定件数ごとにflush()で反映すれば、「今どこまで進んだか」をリアルタイムで見せられます。
function importWithProgress() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName("進捗");
const total = 50;
for (let i = 1; i <= total; i++) {
sheet.getRange(i, 1).setValue("処理中: " + i + "行目");
// 10件ごとに反映して、途中経過を画面に見せる
if (i % 10 === 0) {
SpreadsheetApp.flush(); // 保留中の書き込みをシートに反映
ss.toast(i + " / " + total + " 件完了", "進捗", 3);
}
}
SpreadsheetApp.flush();
ss.toast("完了しました", "進捗", 5); // 右下に3〜5秒だけ出る通知
}毎行flushすると遅くなるので、i % 10 === 0のように「10件ごと」など間隔を空けて呼ぶのがコツです。toast()自体は保留中の書き込みを反映しないため、直前にflush()を入れると画面のセルと通知が揃います。
書き込み直後に読み直すときのflush
数式をコードで入れて、その計算結果をすぐ読みたいときは注意が必要です。setFormulaの直後にgetValueを呼ぶと、まだ計算されていない古い値(空など)を読んでしまうことがあります。あいだにflush()を挟めば、反映後の正しい結果を取得できます。
function readAfterFormula() {
const sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange("B1").setFormula("=A1*10");
SpreadsheetApp.flush(); // これが無いと古い(空)の結果を読むことがある
const result = sheet.getRange("B1").getValue();
Logger.log(result); // 反映後の計算結果が取れる
}単純な値をsetValueして同じ値を読むだけなら、GASが自動で反映するため通常はflush()不要です。数式・チェックボックス・条件付き書式など「書き込みの結果が別の場所に波及する」ケースで、読み直しの前にflush()を入れると安全です。
長い処理を途中コミットして守る
GASには1回の実行が約6分で止まる制限があります。大量の行を1件ずつ処理する場合、途中でエラーや時間切れになると、それまでの結果がまとめて反映されず失われることがあります。一定件数ごと、そして制限時間の手前でflush()を呼び、「ここまでは確定」と保存しておくと安全です。
function processInChunks() {
const sheet = SpreadsheetApp.getActive().getSheetByName("台帳");
const values = sheet.getDataRange().getValues();
const startedAt = new Date().getTime();
for (let i = 1; i < values.length; i++) {
// ... 1行ずつ時間のかかる処理(外部API呼び出しなど) ...
sheet.getRange(i + 1, 5).setValue("済");
if (i % 20 === 0) {
SpreadsheetApp.flush(); // ここまでの結果を確定させる
}
// 6分制限の手前(約5分)で安全に中断し、途中まで保存しておく
if (new Date().getTime() - startedAt > 5 * 60 * 1000) {
SpreadsheetApp.flush();
Logger.log(i + "行目まで処理して中断。次回は続きから。");
break;
}
}
SpreadsheetApp.flush();
}経過時間はnew Date().getTime()の差で測り、5分を超えたらflush()してbreakします。どの行まで終わったかを別セルやPropertiesServiceに残しておけば、次回のトリガー実行で続きから再開できます。flush()は制限時間を延ばすものではないため、あくまで「途中結果を守る」ための使い方です。
flush()の多用は遅い|一括書き込みとの使い分け
flush()は処理を速くするメソッドではありません。むしろ逆で、呼ぶたびにサーバーと往復するため、ループの中で毎回flush()すると極端に遅くなります。速度を上げたいときの正解は、setValuesで範囲をまとめて一括書き込みすることです。
// 悪い例: 1行ごとにflushすると毎回サーバーと往復して極端に遅い
function slowFlush() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getRange("A1:A1000").getValues();
data.forEach((row, i) => {
sheet.getRange(i + 1, 2).setValue(row[0]);
SpreadsheetApp.flush(); // ← 1000回のflushで数分かかることも
});
}
// 良い例: 一括setValuesならflushは基本不要。まとめて1回で書き込む
function fastBatch() {
const sheet = SpreadsheetApp.getActiveSheet();
const data = sheet.getRange("A1:A1000").getValues();
const out = data.map((row) => [row[0]]);
sheet.getRange(1, 2, out.length, 1).setValues(out);
}一括setValuesなら書き込み回数が1回で済み、flush()を意識する必要もほぼありません。flush()を使うのは「途中で反映させたい明確な理由があるとき」だけ、と覚えておくと迷いません。
onEditトリガーでは基本いらない
onEditのように短時間で終わる関数では、最後にまとめて反映されるためflush()はほぼ不要です。「反映されない」と感じる原因の多くは、flush不足ではなく対象セルや範囲の指定ミスなので、まずそこを確認してください。
排他制御と組み合わせるとき
採番や在庫更新など、複数実行が重なると困る処理では、LockServiceでロックを取り、書き込み後にflush()で確定してからロックを解放すると、確実に反映された状態で次の処理へ渡せます。
まとめ
SpreadsheetApp.flush()は、ためられた書き込みを今すぐ反映させる1行です。使いどころは「進捗をtoastで見せたい」「数式の結果をすぐ読み直したい」「制限時間の前に途中まで保存したい」の3つが中心。逆に、速度を上げる目的では使わず、そこはsetValuesの一括書き込みに任せます。「なぜ反映されないのか」の仕組みを押さえておけば、flush()を入れる場所も、入れなくてよい場所も自然に判断できます。
よくある質問
flush()は、それまでにコード内で行ったsetValueなどの保留中の変更を、その場でスプレッドシートに書き込ませるメソッドです。GASは高速化のため書き込みをためて後でまとめて反映しますが、flush()を呼ぶとそこまでの変更が確定します。引数も戻り値もなく、SpreadsheetApp.flush()と書くだけです。
GASがスプレッドシートへの書き込みをまとめて処理するためです。1回ずつサーバーとやり取りすると遅くなるので、変更はいったんためられ、関数の終了時などにまとめて反映されます。処理の途中で必ず反映させたいときにflush()を使います。
数式をsetFormulaで入れて、その計算結果をすぐgetValueで読む場合などは必要です。flush()を挟まないと、反映前の古い値(空など)を読んでしまうことがあります。単純な値をsetValueして同じ値を読むだけなら通常は不要です。迷ったら読み直しの直前にflush()を入れると確実です。
速くなりません。むしろ多用すると遅くなります。flush()はそのたびにサーバーとやり取りするため、ループの中で毎回呼ぶと極端に遅くなります。高速化したいときはflush()ではなく、getValues/setValuesで範囲をまとめて一括読み書きするのが基本です。
使えます。処理が制限に近づいたらflush()でそこまでの結果を確定させてから中断すれば、途中まで書いた内容が失われません。次回はその続きから再開する設計にします。ただしflush()自体は制限時間を延ばすものではない点に注意してください。
GAS開発・業務Webシステムを
相談する。
進捗表示付きの一括処理や、大量データを途中保存しながら回すバッチ処理など、実務で止まらないGAS開発をご相談いただけます。