บริการ HTML: สื่อสารกับฟังก์ชันของเซิร์ฟเวอร์

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() เบราว์เซอร์จะทำงานต่อ ไปยังบรรทัดถัดไปของโค้ดได้ทันทีโดยไม่ต้องรอการตอบกลับ ซึ่งหมายความว่า การเรียกฟังก์ชันของเซิร์ฟเวอร์อาจไม่ดำเนินการตามลำดับที่คุณคาดไว้ หากคุณให้ สองการเรียกใช้ฟังก์ชันพร้อมกัน จะไม่มีทางทราบว่าฟังก์ชันใดจะ แสดงก่อน ผลการค้นหาอาจแตกต่างกันในแต่ละครั้งที่คุณโหลดหน้าเว็บ ในกรณีนี้ เครื่องจัดการสำเร็จและเครื่องจัดการความล้มเหลว จะช่วยควบคุมโฟลว์ของโค้ด

google.script.run API อนุญาตให้มีการเรียกฟังก์ชันของเซิร์ฟเวอร์พร้อมกัน 10 ครั้ง ถ้า คุณเรียกครั้งที่ 11 ในขณะที่เลข 10 ยังทำงานอยู่ ฟังก์ชันของเซิร์ฟเวอร์จะ ล่าช้าจนกว่า 1 ใน 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) หรือSupply เครื่องจัดการความล้มเหลวที่ไม่ดำเนินการใดๆ

ไวยากรณ์สำหรับตัวจัดการความล้มเหลวแทบจะเหมือนกับเครื่องจัดการความสำเร็จ เนื่องจาก ตัวอย่างรายการ

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 ครั้ง แต่ เครื่องจัดการความสำเร็จแยกต่างหาก

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)