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>
หากทำให้สคริปต์นี้ใช้งานได้เป็นเว็บแอปและไปที่ URL ของสคริปต์ก็จะไม่เห็นอะไรเลย แต่หากดูบันทึก คุณจะเห็นว่ามีการเรียกใช้ฟังก์ชัน doSomething()
ของเซิร์ฟเวอร์
การเรียกฝั่งไคลเอ็นต์ไปยังฟังก์ชันฝั่งเซิร์ฟเวอร์จะเป็นแบบไม่พร้อมกัน หลังจากที่เบราว์เซอร์ขอให้เซิร์ฟเวอร์เรียกใช้ฟังก์ชัน doSomething()
เบราว์เซอร์จะไปยังโค้ดบรรทัดถัดไปทันทีโดยไม่รอการตอบกลับ ซึ่งหมายความว่าการเรียกใช้ฟังก์ชันของเซิร์ฟเวอร์อาจไม่ดำเนินการตามลำดับที่คุณคาดหวังไว้ หากคุณเรียกใช้ฟังก์ชัน 2 ครั้งพร้อมกัน ก็จะไม่มีทางรู้ว่าฟังก์ชันใดจะทำงานก่อน ผลลัพธ์อาจแตกต่างกันไปในแต่ละครั้งที่คุณโหลดหน้าเว็บ ในสถานการณ์นี้เครื่องจัดการสำเร็จและเครื่องจัดการความล้มเหลวจะช่วยควบคุมการทำงานของโค้ด
google.script.run
API อนุญาตให้มีการเรียกฟังก์ชันของเซิร์ฟเวอร์พร้อมกัน 10 ครั้ง หากคุณเรียกใช้เป็นครั้งที่ 11 ในขณะที่จำนวน 10 ยังคงทำงานอยู่ ฟังก์ชันของเซิร์ฟเวอร์จะล่าช้าจนกว่าหนึ่งใน 10 ตำแหน่งนี้จะว่าง ในทางปฏิบัติ คุณไม่ควรคำนึงถึงข้อจำกัดนี้ โดยเฉพาะอย่างยิ่งเนื่องจากเบราว์เซอร์ส่วนใหญ่จำกัดจำนวนคำขอที่ทำงานพร้อมกันในเซิร์ฟเวอร์เดียวกันอยู่แล้วโดยจะน้อยกว่า 10 คำขอ
เช่น ใน Firefox ขีดจํากัดคือ 6 ในทำนองเดียวกัน เบราว์เซอร์ส่วนใหญ่จะหน่วงเวลาคำขอที่เกินมา
ของเซิร์ฟเวอร์จนกว่าคำขอที่มีอยู่รายการหนึ่งจะเสร็จสมบูรณ์
พารามิเตอร์และค่าที่ส่งคืน
คุณสามารถเรียกใช้ฟังก์ชันของเซิร์ฟเวอร์ด้วยพารามิเตอร์จากไคลเอ็นต์ได้ ในทำนองเดียวกัน ฟังก์ชันของเซิร์ฟเวอร์จะแสดงผลค่าให้กับไคลเอ็นต์เป็นพารามิเตอร์ที่ส่งไปยังเครื่องจัดการสำเร็จได้
พารามิเตอร์ทางกฎหมายและค่าที่แสดงผลคือ JavaScript แบบพื้นฐาน เช่น Number
, Boolean
, String
หรือ null
รวมถึงออบเจ็กต์และอาร์เรย์ JavaScript ที่ประกอบด้วยไพรม์ อ็อบเจกต์ และอาร์เรย์ องค์ประกอบ form
ภายในหน้าเว็บถือว่าเป็นพารามิเตอร์ทางกฎหมายด้วย แต่ต้องเป็นพารามิเตอร์เดียวของฟังก์ชัน และไม่ใช่ค่าที่ถูกต้องตามกฎหมายสำหรับแสดงผล คำขอล้มเหลวหากคุณพยายามส่ง Date
, Function
, องค์ประกอบ DOM นอกเหนือจาก form
หรือประเภทที่ไม่อนุญาตอื่นๆ รวมถึงประเภทที่ไม่อนุญาตภายในออบเจ็กต์หรืออาร์เรย์ นอกจากนี้ ออบเจ็กต์ที่สร้างการอ้างอิงแบบวนจะล้มเหลวและฟิลด์ที่ไม่ได้กำหนดภายในอาร์เรย์จะกลายเป็น null
โปรดทราบว่าออบเจ็กต์ที่ส่งผ่านไปยังเซิร์ฟเวอร์จะกลายเป็นสำเนาของต้นฉบับ หากฟังก์ชันของเซิร์ฟเวอร์ได้รับออบเจ็กต์และเปลี่ยนแปลงพร็อพเพอร์ตี้ พร็อพเพอร์ตี้ในไคลเอ็นต์จะไม่ได้รับผลกระทบ
ตัวจัดการความสำเร็จ
เนื่องจากโค้ดฝั่งไคลเอ็นต์ไปยังบรรทัดถัดไปโดยไม่ต้องรอให้การเรียกใช้เซิร์ฟเวอร์เสร็จสิ้น withSuccessHandler(function)
จึงช่วยให้คุณระบุฟังก์ชัน Callback ฝั่งไคลเอ็นต์ที่จะเรียกใช้เมื่อเซิร์ฟเวอร์ตอบสนองได้ หากฟังก์ชันเซิร์ฟเวอร์แสดงผลค่า API จะส่งค่าไปยังฟังก์ชันใหม่เป็นพารามิเตอร์
ตัวอย่างต่อไปนี้จะแสดงการแจ้งเตือนของเบราว์เซอร์เมื่อเซิร์ฟเวอร์ตอบสนอง โปรดทราบว่าตัวอย่างโค้ดนี้ต้องมีการให้สิทธิ์ เนื่องจากฟังก์ชันฝั่งเซิร์ฟเวอร์กำลังเข้าถึงบัญชี Gmail ของคุณ วิธีที่ง่ายที่สุดในการให้สิทธิ์สคริปต์คือเรียกใช้ฟังก์ชัน getUnreadEmails()
ด้วยตนเองจากเครื่องมือแก้ไขสคริปต์ 1 ครั้งก่อนที่จะโหลดหน้า หรือเมื่อคุณทำให้เว็บแอปใช้งานได้ คุณจะเลือกเรียกใช้เป็น "ผู้ใช้ที่เข้าถึงเว็บแอป" ได้ ซึ่งในกรณีนี้ก็จะได้รับข้อความแจ้งให้ให้สิทธิ์เมื่อโหลดแอป
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)
เพื่อระบุออบเจ็กต์ที่จะส่งไปยังเครื่องจัดการเป็นพารามิเตอร์ที่ 2
"ออบเจ็กต์ผู้ใช้" นี้ (ไม่ใช่ความสับสนกับคลาส User
) นี้จะช่วยให้คุณตอบสนองต่อบริบทที่ไคลเอ็นต์ติดต่อกับเซิร์ฟเวอร์ได้ เนื่องจากออบเจ็กต์ผู้ใช้ไม่ได้ส่งไปยังเซิร์ฟเวอร์ จึงอาจเป็นได้เกือบทุกอย่าง ซึ่งรวมถึงฟังก์ชัน องค์ประกอบ DOM ฯลฯ โดยไม่มีข้อจำกัดเกี่ยวกับพารามิเตอร์และแสดงผลค่าสำหรับการเรียกเซิร์ฟเวอร์ แต่ออบเจ็กต์ผู้ใช้จะเป็นออบเจ็กต์ที่สร้างขึ้นด้วยโอเปอเรเตอร์ new
ไม่ได้
ในตัวอย่างนี้ การคลิกปุ่มใดปุ่มหนึ่งจาก 2 ปุ่มจะอัปเดตปุ่มนั้นด้วยค่าจากเซิร์ฟเวอร์และปล่อยอีกปุ่มหนึ่งไว้ตามเดิม แม้ว่าปุ่มเหล่านั้นจะแชร์เครื่องจัดการสำเร็จเพียงปุ่มเดียว ภายในเครื่องจัดการ 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 ไดรฟ์ แล้วพิมพ์ URL ของไฟล์ในหน้าฝั่งไคลเอ็นต์ ภายในเครื่องจัดการ onsubmit
คีย์เวิร์ด this
จะหมายถึงฟอร์มนั้นเอง โปรดทราบว่า preventFormSubmit
จะปิดใช้การส่งตามค่าเริ่มต้นเมื่อโหลดแบบฟอร์มทั้งหมด เพื่อป้องกันไม่ให้หน้าเว็บเปลี่ยนเส้นทางไปยัง URL ที่ไม่ถูกต้องในกรณีที่มีข้อยกเว้น
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()
คุณยังเรียกใช้ฟังก์ชันการแก้ไขใดๆ ในโปรแกรมเรียกใช้สคริปต์ที่มีการตั้งค่าไว้แล้วได้ด้วย ค่าใหม่จะลบล้างค่าก่อนหน้าเท่านั้น
ตัวอย่างนี้ตั้งค่าเครื่องจัดการความล้มเหลวที่พบบ่อยสำหรับการเรียกใช้เซิร์ฟเวอร์ทั้ง 3 รายการ แต่มีเครื่องจัดการความสำเร็จ 2 รายการแยกกัน ได้แก่
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.setCursor(position)
และ Document.setSelection(range)