google.script.run
是非同步的用戶端 JavaScript API,可讓 HTML 服務網頁呼叫伺服器端 Apps Script 函式。以下範例顯示 google.script.run
最基本的功能:從用戶端 JavaScript 呼叫伺服器上的函式。
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function doSomething() { Logger.log('I was called!'); }
Index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <script> google.script.run.doSomething(); </script> </head> </html>
如果您將這個指令碼部署為網路應用程式並前往其網址,不會看到任何內容,但如果查看記錄,會發現系統已呼叫伺服器函式 doSomething()
。
對伺服器端函式的用戶端呼叫是非同步的:瀏覽器要求伺服器執行 doSomething()
函式後,瀏覽器會立即繼續執行下一行程式碼,不必等待回應。也就是說,伺服器函式呼叫可能不會按照預期順序執行。如果您同時進行兩次函式呼叫,系統無法判斷哪個函式會先執行;每次載入網頁時,結果可能都會不同。在這種情況下,成功處理常式和失敗處理常式可協助控管程式碼流程。
google.script.run
API 最多可同時呼叫 10 個伺服器函式。如果 10 個呼叫仍在執行中,您發出第 11 個呼叫時,伺服器函式會延遲執行,直到其中一個呼叫完成為止。實際上,您很少需要考慮這項限制,特別是大多數瀏覽器已將對同一伺服器的並行要求數量限制在 10 以下。舉例來說,Firefox 的上限為 6 個。同樣地,大多數瀏覽器都會延遲處理過多的伺服器要求,直到現有要求完成為止。
參數和傳回值
您可以從用戶端呼叫含有參數的伺服器函式。同樣地,伺服器函式可以將值傳回給用戶端,做為傳遞至成功處理常式的參數。
合法參數和傳回值是 JavaScript 原始型別,例如 Number
、Boolean
、String
或 null
,以及由原始型別、物件和陣列組成的 JavaScript 物件和陣列。網頁中的 form
元素也可以做為參數,但必須是函式的唯一參數,且不得做為傳回值。如果您嘗試傳遞 form
以外的 Date
、Function
、DOM 元素或其他禁止使用的類型,包括物件或陣列中的禁止類型,要求就會失敗。建立循環參照的物件也會失敗,且陣列中的未定義欄位會變成 null
。
請注意,傳遞至伺服器的物件會成為原始物件的副本。如果伺服器函式收到物件並變更其屬性,用戶端上的屬性不會受到影響。
成功處理常式
由於用戶端程式碼會繼續執行下一行,不會等待伺服器呼叫完成,因此 withSuccessHandler(function)
可讓您指定伺服器回應時要執行的用戶端回呼函式。如果伺服器函式傳回值,API 會將該值做為參數傳遞至新函式。
以下範例會在伺服器回應時顯示瀏覽器快訊。請注意,這個程式碼範例需要授權,因為伺服器端函式會存取您的 Gmail 帳戶。如要授權指令碼,最簡單的方法是在載入網頁前,先從指令碼編輯器手動執行 getUnreadEmails()
函式一次。或者,您也可以在部署網路應用程式時,選擇以「存取網路應用程式的使用者」身分執行,這樣在載入應用程式時,系統就會提示您授權。
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function getUnreadEmails() { return GmailApp.getInboxUnreadCount(); }
Index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <script> function onSuccess(numUnread) { var div = document.getElementById('output'); div.innerHTML = 'You have ' + numUnread + ' unread messages in your Gmail inbox.'; } google.script.run.withSuccessHandler(onSuccess) .getUnreadEmails(); </script> </head> <body> <div id="output"></div> </body> </html>
失敗處理常式
如果伺服器無法回應或擲回錯誤,withFailureHandler(function)
可讓您指定失敗處理常式,而非成功處理常式,並將 Error
物件 (如有) 做為引數傳遞。
如未指定失敗處理常式,系統會預設將失敗記錄到 JavaScript 控制台。如要覆寫這項行為,請呼叫 withFailureHandler(null)
或提供不會執行任何動作的失敗處理常式。
失敗處理常式的語法與成功處理常式幾乎相同,如下例所示。
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function getUnreadEmails() { // 'got' instead of 'get' will throw an error. return GmailApp.gotInboxUnreadCount(); }
Index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <script> function onFailure(error) { var div = document.getElementById('output'); div.innerHTML = "ERROR: " + error.message; } google.script.run.withFailureHandler(onFailure) .getUnreadEmails(); </script> </head> <body> <div id="output"></div> </body> </html>
使用者物件
您可以呼叫 withUserObject(object)
,為多個伺服器呼叫重複使用相同的成功或失敗處理常式,藉此指定要傳遞至處理常式的物件做為第二個參數。這個「使用者物件」與 User
類別不同,可讓您回應用戶端與伺服器通訊時的環境。由於使用者物件不會傳送至伺服器,因此幾乎可以是任何項目,包括函式、DOM 元素等,不受伺服器呼叫的參數和傳回值限制。不過,使用者物件不能是使用 new
運算子建構的物件。
在本例中,點選任一按鈕都會以伺服器的值更新該按鈕,但另一個按鈕不會變更,即使兩個按鈕共用一個成功處理常式也一樣。在 onclick
處理常式中,關鍵字 this
是指 button
本身。
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function getEmail() { return Session.getActiveUser().getEmail(); }
Index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <script> function updateButton(email, button) { button.value = 'Clicked by ' + email; } </script> </head> <body> <input type="button" value="Not Clicked" onclick="google.script.run .withSuccessHandler(updateButton) .withUserObject(this) .getEmail()" /> <input type="button" value="Not Clicked" onclick="google.script.run .withSuccessHandler(updateButton) .withUserObject(this) .getEmail()" /> </body> </html>
表單
如果您使用 form
元素做為參數呼叫伺服器函式,表單會變成單一物件,欄位名稱為鍵,欄位值為值。除了檔案輸入欄位的內容會變成 Blob
物件,其他值都會轉換為字串。
這個範例會處理表單 (包括檔案輸入欄位),且不會重新載入網頁;它會將檔案上傳至 Google 雲端硬碟,然後在用戶端網頁中列印檔案的網址。在 onsubmit
處理常式中,關鍵字 this
是指表單本身。請注意,載入頁面時,所有表單的預設提交動作都會遭到停用。preventFormSubmit
這樣一來,發生例外狀況時,網頁就不會重新導向至不正確的網址。
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function processForm(formObject) { var formBlob = formObject.myFile; var driveFile = DriveApp.createFile(formBlob); return driveFile.getUrl(); }
Index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <script> // Prevent forms from submitting. function preventFormSubmit() { var forms = document.querySelectorAll('form'); for (var i = 0; i < forms.length; i++) { forms[i].addEventListener('submit', function(event) { event.preventDefault(); }); } } window.addEventListener('load', preventFormSubmit); function handleFormSubmit(formObject) { google.script.run.withSuccessHandler(updateUrl).processForm(formObject); } function updateUrl(url) { var div = document.getElementById('output'); div.innerHTML = '<a href="' + url + '">Got it!</a>'; } </script> </head> <body> <form id="myForm" onsubmit="handleFormSubmit(this)"> <input name="myFile" type="file" /> <input type="submit" value="Submit" /> </form> <div id="output"></div> </body> </html>
指令碼執行者
您可以將 google.script.run
視為「指令碼執行器」的建構工具。如果將成功處理常式、失敗處理常式或使用者物件新增至指令碼執行器,您不會變更現有的執行器,而是會取得具有新行為的新指令碼執行器。
您可以任意組合及排序 withSuccessHandler()
、withFailureHandler()
和 withUserObject()
。您也可以在已設定值的指令碼執行器上,呼叫任何修改函式。新值會直接覆寫先前的值。
這個範例會為所有三項伺服器呼叫設定一般失敗處理常式,但有兩個不同的成功處理常式:
var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);
myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();
私人函式
名稱結尾為底線的伺服器函式會視為私有函式。
google.script
無法呼叫這些函式,且系統絕不會將函式名稱傳送給用戶端。因此,您可以使用這些函式隱藏需要在伺服器上保密的實作詳細資料。google.script
也無法查看程式庫中的函式,以及未在指令碼頂層宣告的函式。
在本範例中,用戶端程式碼提供 getBankBalance()
函式;即使您未呼叫該函式,檢查原始碼的使用者仍可發現其名稱。不過,用戶端完全看不到 deepSecret_()
和 obj.objectMethod()
函式。
Code.gs
function doGet() { return HtmlService.createHtmlOutputFromFile('Index'); } function getBankBalance() { var email = Session.getActiveUser().getEmail() return deepSecret_(email); } function deepSecret_(email) { // Do some secret calculations return email + ' has $1,000,000 in the bank.'; } var obj = { objectMethod: function() { // More secret calculations } };
Index.html
<!DOCTYPE html> <html> <head> <base target="_top"> <script> function onSuccess(balance) { var div = document.getElementById('output'); div.innerHTML = balance; } google.script.run.withSuccessHandler(onSuccess) .getBankBalance(); </script> </head> <body> <div id="output">No result yet...</div> </body> </html>
在 Google Workspace 應用程式中調整對話方塊大小
在 Google 文件、試算表或表單中,您可以呼叫用戶端程式碼中的 google.script.host
方法 setWidth(width)
或 setHeight(height)
,調整自訂對話方塊的大小。(如要設定對話方塊的初始大小,請使用 HtmlOutput
方法 setWidth(width)
和 setHeight(height)
)。請注意,對話方塊不會在調整大小後重新置中於父項視窗,且無法調整側欄大小。
在 Google Workspace中關閉對話方塊和側邊欄
如果您使用 HTML 服務在 Google 文件、試算表或表單中顯示對話方塊或側欄,就無法呼叫 window.close()
關閉介面。而是必須呼叫 google.script.host.close()
。如需範例,請參閱「將 HTML 做為 Google Workspace 使用者介面提供服務」一節。
在 Google Workspace中移動瀏覽器焦點
如要將使用者瀏覽器中的焦點從對話方塊或側欄切換回 Google 文件、試算表或表單編輯器,只要呼叫 google.script.host.editor.focus()
方法即可。這個方法特別適合與 Document 服務方法 Document.setCursor(position)
和 Document.setSelection(range)
搭配使用。