質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.30%
Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

1回答

322閲覧

【GAS】グローバル変数を使用してサイドバーに実行ログを表示したい

nksr_mart

総合スコア1

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

1クリップ

投稿2024/03/12 12:24

編集2024/03/12 12:36

実現したいこと

Google Apps Scriptにて
処理の途中でグローバル変数の値を変更することで、
関数の実行状況をサイドバーに表示したい

  • グローバル変数を定義する
  • サイドバーを表示する
  • メインの関数の中で一定の処理ごとにグローバル変数に値を再代入する
  • サイドバー(html)側から、受け渡し用の関数を呼びだして変更したグローバル変数の値を受け取る
  • 実行ログとして表示させる

(特定のセルに値を保存して呼び出すことも考えましたが、
できるだけシートへの干渉は減らしたいと思っています)

発生している問題・エラーメッセージ

グローバル変数の値が更新されないため

以下のコードを実行すると
foo
foo
...
というような結果になってしまいます

(first
second
...
という結果が得たいです)

私がわからない部分は以下の2点です

  • グローバル変数はただしく更新(再代入)できているのか
  • getProgress内でreturnをする前に何らかの処理が必要なのか

つたない質問で申し訳ないのですが、教えていただけると幸いです。
どうぞよろしくお願いいたします。

該当のソースコード

コード.gs

js

1// グローバル変数を定義 2var progress = "foo"; 3 4// htmlから呼び出して最新のprogressを返したい 5function getProgress() { 6 return progress; 7} 8 9// スタート 10function start() { 11 // サイドバーを表示 12 const html = HtmlService.createHtmlOutputFromFile("サイドバー"); 13 SpreadsheetApp.getUi().showSidebar(html); 14 // 実行 15 myFunction(); 16} 17 18function myFunction(){ 19 progress = "first"; 20 // なにかの処理 21 Utilities.sleep(1000); 22 23 progress = "second"; 24 Utilities.sleep(1000); 25 26 progress = "third"; 27 Utilities.sleep(1000); 28 29 progress = "finish"; 30}

サイドバー.html

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <base target="_top" /> 5 6 <script> 7 function run() { 8 // 0.5秒ごとにgetProgressを実行 9 id = setInterval(function() { 10 // getProgressの返り値をresponceで受けてサイドバーに表示 11 google.script.run.withSuccessHandler(function(response) { 12 // 最後まで到達したらタイマー処理を終了 13 if(response === "finish"){ 14 clearInterval(id); 15 document.getElementById("progress").insertAdjacentHTML('beforeend', `<div>終了しました<div>`); 16 } else { 17 document.getElementById("progress").insertAdjacentHTML('beforeend', `<div>${response}<div>`); 18 } 19 }).getProgress(); 20 }, 500); 21 } 22 </script> 23 </head> 24 25 <body onload="run()"> 26 <span id="progress"></span> 27 </body> 28</html>

試したこと

グローバル変数について調べてみたものの、
問題の原因がわからず、他の実装を考えてみました

1. 受け渡し用関数に直接引数を渡すように変更してみました
以下の結果になり、うまくいきませんでした
null
null
...

diff

1-function getProgress() { 2- return progress; 3-} 4+function getProgress(progress) { 5+ return progress; 6+} 7 8~~~ 9 10- progress = "first"; 11+ getProgress("first");

2. 次に、プロパティサービスを利用する方法を考えました
この方法では望むものに近い結果が得られましたが、値の反映まで多少のラグがあるような気がしました

diff

1-function getProgress() { 2- return progress; 3-} 4+function getProgress(progress) { 5+ var progress = PropertiesService.getScriptProperties().getProperty("progress"); 6+ return progress; 7+} 8 9~~~ 10 11- progress = "first"; 12+ PropertiesService.getScriptProperties().setProperty("progress","first");

補足情報(FW/ツールのバージョンなど)

参考にしたサイト
公式リファレンス
https://developers.google.com/apps-script/guides/html/reference/run?hl=ja
☆『GASとJSを使ってサイドバーで進行状況や途中結果を表示させる』
https://qiita.com/bonotake/items/f5f99e7b67460be356ac
『JavaScriptでのグローバル変数の宣言方法』
https://uxmilk.jp/11598
『プロパティサービスを使ってGASで秘密情報を管理する』
https://note.com/crefil/n/n2b68b3c4aa6b

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

YAmaGNZ

2024/03/12 21:43

参考にされている『GASとJSを使ってサイドバーで進行状況や途中結果を表示させる』というページに https://qiita.com/bonotake/items/f5f99e7b67460be356ac#%E5%95%8F%E9%A1%8C%E7%82%B9%E3%81%A8%E3%81%8B%E3%83%8F%E3%83%9E%E3%82%8A%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%A8%E3%81%8B google.script.runで叩かれる関数は別プロセスで走ります。つまり、GAS側と同じコードを叩いてもGAS側の計算途中の状態をgoogle.script.runで叩いても直接読み取ることはできません。 とあります。 なのでstartを呼び出すプロセスとサイドバーで呼び出すプロセスが別となりグローバル変数も別物になるのではないでしょうか。
nksr_mart

2024/03/13 00:00

回答ありがとうございます。 そういった仕組みなんですね。 取得したい値はコード.gsの外側に 逃がしてあげないといけないということですよね…
guest

回答1

0

YAmaGNZさんがコメントしていただいているように、
直接グローバル変数を参照するのは難しいと思います。

そこまでリアルタイム性を求めないのであれば
プロパティサービスを利用する方法でも問題ないのかなと思いました。

また一時的な情報であればキャッシュサービスを利用するのもよいかと思います。
時間がたてば消えてくれますし、レスポンスも多少良くなるかと思います。
Class CacheService  |  Apps Script  |  Google for Developers

例えば下記のようなコードにすればキャッシュサービスで動きます。

javascript

1function getProgress() { 2 return CacheService.getScriptCache().get("progress"); 3} 4 5function setProgress(value) { 6 CacheService.getScriptCache().put("progress", value, 3600); // 3600秒 = 1時間 7}

直接的なグローバル変数の質問への回答ではないですが、
代替案としては、処理が分かれているのであれば、
それぞれ別々に呼び出すという方法も考えられます。

処理が分けられるのであれば、下記のように分けておきます。
(キャッシュサービスを利用しない場合は修正してください。)

javascript

1 2// 処理を開始する関数 3function start() { 4 const html = HtmlService.createHtmlOutputFromFile("サイドバー"); 5 SpreadsheetApp.getUi().showSidebar(html); 6} 7 8// 進捗を更新する関数 9function updateProgress(progress) { 10 CacheService.getScriptCache().put("progress", progress, 3600); 11 return progress; // 結果をクライアントに返す 12} 13 14// 各処理を分割して定義 15function processStep1() { 16 updateProgress("first"); 17 Utilities.sleep(1000); 18 return "first"; 19} 20 21function processStep2() { 22 updateProgress("second"); 23 Utilities.sleep(1000); 24 return "second"; 25} 26 27function processStep3() { 28 updateProgress("third"); 29 Utilities.sleep(1000); 30 return "third"; 31} 32 33function processFinish() { 34 updateProgress("finish"); 35 return "finish"; 36}

その後HTML側で順に呼び出すようにすれば、
余計な呼び出しも減らせるかなと思います。

html

1<!DOCTYPE html> 2<html> 3 <head> 4 <base target="_top" /> 5 <script> 6 function run() { 7 // 各ステップの処理を順番に実行 8 google.script.run.withSuccessHandler(handleProgress).processStep1(); 9 } 10 11 // 各ステップの結果を処理し、次のステップを呼び出す 12 function handleProgress(response) { 13 document.getElementById("progress").insertAdjacentHTML('beforeend', `<div>${response}<div>`); 14 15 if (response === "first") { 16 google.script.run.withSuccessHandler(handleProgress).processStep2(); 17 } else if (response === "second") { 18 google.script.run.withSuccessHandler(handleProgress).processStep3(); 19 } else if (response === "third") { 20 google.script.run.withSuccessHandler(handleProgress).processFinish(); 21 } else if (response === "finish") { 22 document.getElementById("progress").insertAdjacentHTML('beforeend', `<div>終了しました<div>`); 23 } 24 } 25 </script> 26 </head> 27 <body onload="run()"> 28 <span id="progress"></span> 29 </body> 30</html>

投稿2024/10/22 03:47

dadadaiiiiiii

総合スコア56

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問