google.script.run là một API JavaScript không đồng bộ phía máy khách, cho phép các trang dịch vụ HTML gọi các hàm Apps Script phía máy chủ. Ví dụ sau đây cho thấy chức năng cơ bản nhất
của google.script.run – gọi một hàm trên
máy chủ từ JavaScript
phía máy khách.
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>Nếu triển khai tập lệnh này dưới dạng một ứng dụng web và truy cập vào URL của ứng dụng, bạn sẽ không thấy gì cả. Tuy nhiên, nếu xem nhật ký, bạn sẽ thấy rằng hàm doSomething trên máy chủ đã được gọi.
Các lệnh gọi phía máy khách đến các hàm phía máy chủ là không đồng bộ: sau khi trình duyệt yêu cầu máy chủ chạy hàm doSomething, trình duyệt sẽ tiếp tục ngay lập tức đến dòng mã tiếp theo mà không cần chờ phản hồi. Điều này có nghĩa là các lệnh gọi hàm máy chủ có thể không thực thi theo thứ tự bạn mong đợi. Nếu bạn thực hiện hai lệnh gọi hàm cùng một lúc, thì không có cách nào để biết hàm nào chạy trước; kết quả có thể khác nhau mỗi khi bạn tải trang. Trong trường hợp này,
trình xử lý thành công và trình xử lý lỗi
sẽ giúp kiểm soát luồng mã của bạn.
API google.script.run cho phép 10 lệnh gọi đồng thời đến các hàm máy chủ. Nếu bạn thực hiện lệnh gọi thứ 11 trong khi 10 lệnh gọi vẫn đang chạy, thì hàm máy chủ sẽ bị trì hoãn cho đến khi một trong 10 vị trí được giải phóng. Trên thực tế, bạn hiếm khi phải nghĩ đến hạn chế này, đặc biệt là vì hầu hết các trình duyệt đều đã giới hạn số lượng yêu cầu đồng thời đến cùng một máy chủ ở mức thấp hơn 10.
Ví dụ: trong Firefox, giới hạn là 6. Tương tự, hầu hết các trình duyệt đều trì hoãn các yêu cầu máy chủ dư thừa cho đến khi một trong các yêu cầu hiện có hoàn tất.
Tham số và giá trị trả về
Gọi một hàm máy chủ có các tham số từ máy khách. Tương tự, một hàm máy chủ có thể trả về một giá trị cho máy khách dưới dạng tham số được truyền đến một trình xử lý thành công.
Các tham số và giá trị trả về hợp lệ là các kiểu dữ liệu nguyên thuỷ của JavaScript như Number, Boolean, String hoặc null, cũng như các đối tượng và mảng JavaScript được tạo thành từ các kiểu dữ liệu nguyên thuỷ, đối tượng và mảng. Phần tử form trong trang cũng hợp lệ dưới dạng tham số, nhưng phải là tham số duy nhất của hàm và không hợp lệ dưới dạng giá trị trả về. Yêu cầu sẽ không thành công nếu bạn cố gắng truyền một Date, Function, phần tử DOM ngoài form hoặc loại bị cấm khác, bao gồm cả các loại bị cấm bên trong đối tượng hoặc mảng. Các đối tượng tạo tham chiếu vòng tròn cũng không thành công và các trường không xác định trong mảng sẽ trở thành null.
Xin lưu ý rằng một đối tượng được truyền đến máy chủ sẽ trở thành bản sao của đối tượng gốc. Nếu một hàm máy chủ nhận được một đối tượng và thay đổi các thuộc tính của đối tượng đó, thì các thuộc tính trên máy khách sẽ không bị ảnh hưởng.
Trình xử lý thành công
Vì các lệnh gọi google.script.run là không đồng bộ, nên mã phía máy khách sẽ tiếp tục đến dòng tiếp theo mà không cần chờ phản hồi. Để chỉ định một hàm gọi lại chạy khi máy chủ phản hồi, hãy sử dụng
withSuccessHandler(function).
Nếu hàm máy chủ trả về một giá trị, thì API sẽ truyền giá trị đó đến hàm callback dưới dạng tham số.
Ví dụ sau đây hiển thị một cảnh báo của trình duyệt khi máy chủ phản hồi. Mã mẫu này yêu cầu cấp quyền vì hàm phía máy chủ truy cập vào tài khoản Gmail của bạn. Để cấp quyền cho tập lệnh, hãy chạy hàm getUnreadEmails theo cách thủ công từ trình chỉnh sửa tập lệnh một lần trước khi bạn tải trang. Ngoài ra, khi bạn
triển khai ứng dụng web để
thực thi dưới dạng "người dùng truy cập vào ứng dụng web," bạn sẽ được nhắc cấp quyền
khi tải ứng dụng.
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>Trình xử lý lỗi
Nếu máy chủ không phản hồi hoặc gửi một lỗi, withFailureHandler(function) cho phép bạn chỉ định một trình xử lý lỗi để chạy thay cho trình xử lý thành công.
Nếu xảy ra lỗi, API sẽ truyền đối tượng
Error
dưới dạng đối số đến trình xử lý lỗi.
Theo mặc định, nếu bạn không chỉ định trình xử lý lỗi, thì các lỗi sẽ được ghi vào bảng điều khiển JavaScript. Để ghi đè hành vi này, hãy gọi withFailureHandler(null) hoặc cung cấp một trình xử lý lỗi không làm gì cả.
Cú pháp cho trình xử lý lỗi gần giống với trình xử lý thành công, như ví dụ này cho thấy.
Code.gs
function doGet() {
return HtmlService.createHtmlOutputFromFile('Index');
}
function getUnreadEmails() {
// 'got' instead of 'get' throws 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>Đối tượng người dùng
Để sử dụng lại cùng một trình xử lý thành công hoặc trình xử lý lỗi cho nhiều lệnh gọi đến máy chủ, hãy gọi
withUserObject(object)
để chỉ định một đối tượng được truyền đến trình xử lý dưới dạng tham số thứ hai.
"Đối tượng người dùng" này (không được nhầm lẫn với lớp
User) cho phép bạn phản hồi ngữ cảnh
mà máy khách liên hệ với máy chủ. Vì các đối tượng người dùng không được gửi đến máy chủ, nên chúng có thể là hầu hết mọi thứ, bao gồm cả hàm và phần tử DOM, mà không có các hạn chế về tham số và giá trị trả về cho các lệnh gọi máy chủ. Các đối tượng người dùng không thể là các đối tượng được tạo bằng toán tử new.
Trong ví dụ này, việc nhấp vào một trong hai nút sẽ cập nhật nút đó bằng một giá trị từ máy chủ trong khi để nguyên nút còn lại, mặc dù chúng dùng chung một trình xử lý thành công. Bên trong trình xử lý onclick, từ khoá this đề cập đến chính 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>Biểu mẫu
Nếu bạn gọi một hàm máy chủ có phần tử form làm tham số, thì biểu mẫu sẽ trở thành một đối tượng duy nhất có tên trường làm khoá và giá trị trường làm giá trị. Tất cả các
giá trị đều được chuyển đổi thành chuỗi, ngoại trừ nội dung của các trường nhập tệp, sẽ trở thành Blob đối tượng.
Ví dụ này xử lý một biểu mẫu, bao gồm cả trường nhập tệp, mà không cần tải lại trang; nó tải tệp lên Google Drive rồi in URL cho tệp đó trong trang phía máy khách. Bên trong trình xử lý onsubmit, từ khoá this đề cập đến chính biểu mẫu. Xin lưu ý rằng khi tải, tất cả các biểu mẫu trong trang đều bị vô hiệu hoá hành động gửi mặc định bằng preventFormSubmit. Điều này ngăn trang chuyển hướng đến một URL không chính xác trong trường hợp ngoại lệ.
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>Trình chạy tập lệnh
Hãy coi google.script.run là một trình tạo cho "trình chạy tập lệnh". Nếu bạn thêm trình xử lý thành công, trình xử lý lỗi hoặc đối tượng người dùng vào trình chạy tập lệnh, thì bạn không thay đổi trình chạy hiện có; thay vào đó, bạn sẽ nhận lại một trình chạy tập lệnh mới có hành vi mới.
Sử dụng bất kỳ tổ hợp và thứ tự nào của withSuccessHandler, withFailureHandler và withUserObject. Ngoài ra, hãy gọi bất kỳ hàm sửa đổi nào trên trình chạy tập lệnh đã đặt giá trị. Giá trị mới sẽ ghi đè giá trị trước đó.
Ví dụ này đặt một trình xử lý lỗi chung cho cả ba lệnh gọi máy chủ, nhưng có hai trình xử lý thành công riêng biệt:
var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);
myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();
Hàm riêng tư
Các hàm máy chủ có tên kết thúc bằng dấu gạch dưới được coi là riêng tư.
google.script không thể gọi các hàm này và tên của chúng không bao giờ được gửi đến máy khách. Bạn có thể sử dụng chúng để ẩn các chi tiết triển khai cần được giữ bí mật trên máy chủ. google.script cũng không thể nhìn thấy
các hàm trong thư viện hoặc các hàm không
được khai báo ở cấp cao nhất của tập lệnh.
Trong ví dụ này, hàm getBankBalance có sẵn trong mã máy khách; người dùng kiểm tra mã nguồn của bạn có thể phát hiện ra tên của hàm này ngay cả khi bạn không gọi hàm đó. Tuy nhiên, các hàm deepSecret_ và obj.objectMethod hoàn toàn không hiển thị cho máy khách.
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>Thay đổi kích thước hộp thoại trong các ứng dụng Google Workspace
Bạn có thể thay đổi kích thướchộp thoại tuỳ chỉnh trong Google Tài liệu,
Google Trang tính hoặc Biểu mẫu bằng cách gọi các
google.script.host phương thức
setWidth(width) hoặc
setHeight(height) trong
mã phía máy khách. (Để đặt kích thước ban đầu của hộp thoại, hãy sử dụng các HtmlOutput
phương thức
setWidth(width)
và
setHeight(height).)
Xin lưu ý rằng hộp thoại không căn giữa lại trong cửa sổ mẹ khi được thay đổi kích thước và
không thể thay đổi kích thước thanh bên.
Đóng hộp thoại và thanh bên trong Google Workspace
Nếu bạn sử dụng dịch vụ HTML để hiển thị hộp thoại hoặc
thanh bên trong Google Tài liệu, Trang tính,
hoặc Biểu mẫu, thì bạn không thể đóng giao diện bằng cách gọi
window.close. Thay vào đó, bạn phải gọi
google.script.host.close.
Để xem ví dụ, hãy xem phần về việc phân phát HTML dưới dạng giao diện người dùng Google Workspace
user
interface.
Di chuyển tiêu điểm của trình duyệt trong Google Workspace
Để chuyển tiêu điểm trong trình duyệt của người dùng từ hộp thoại hoặc thanh bên trở lại trình chỉnh sửa
Google Tài liệu, Trang tính hoặc Biểu mẫu, hãy gọi
phương thức
google.script.host.editor.focus.
Phương thức này đặc biệt hữu ích khi kết hợp với các phương thức của dịch vụ Tài liệu Document.setCursor(position)
và
Document.setSelection(range).