HTML Hizmeti: Sunucu İşlevleri ile İletişim

google.script.run, HTML hizmet sayfalarının sunucu tarafı Apps Komut Dosyası işlevlerini çağırmasına olanak tanıyan, istemci tarafında çalışan eşzamansız bir JavaScript API'sidir. Aşağıdaki örnekte, google.script.run'ün en temel işlevi olan istemci tarafı JavaScript'den sunucudaki bir işlevi çağırma gösterilmektedir.

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>

Bu komut dosyasını web uygulaması olarak dağıtır ve URL'sini ziyaret ederseniz hiçbir şey görmezsiniz ancak günlükleri görüntülerseniz doSomething() sunucu işlevinin çağrıldığını görürsünüz.

Sunucu tarafı işlevlere istemci tarafında yapılan çağrılar eşzamansızdır: Tarayıcı, sunucunun doSomething() işlevini çalıştırmasını istedikten sonra yanıt beklemeden hemen bir sonraki kod satırına geçer. Bu, sunucu işlevi çağrılarının beklediğiniz sırada yürütülemeyeceği anlamına gelir. Aynı anda iki işlev çağrısı yaparsanız hangi işlevin önce çalışacağını bilmenin bir yolu yoktur. Sonuç, sayfayı her yüklediğinizde farklı olabilir. Bu durumda, başarı işleyicileri ve başarısızlık işleyicileri, kodunuzun akışını kontrol etmenize yardımcı olur.

google.script.run API, sunucu işlevlerine 10 eşzamanlı çağrı yapılmasına olanak tanır. 10 çağrı devam ederken 11. çağrıyı yaparsanız sunucu işlevi, 10 yerden biri boşalana kadar ertelenir. Uygulamada, özellikle de çoğu tarayıcı aynı sunucuya yapılan eşzamanlı istek sayısını 10'dan düşük bir sayıyla sınırlandırdığı için bu kısıtlamayı nadiren düşünmeniz gerekir. Örneğin, Firefox'ta sınır 6'dır. Çoğu tarayıcı, mevcut isteklerden biri tamamlanana kadar aşırı sunucu isteklerini benzer şekilde geciktirir.

Parametreler ve döndürülen değerler

İstemciden parametrelerle bir sunucu işlevi çağırabilirsiniz. Benzer şekilde, bir sunucu işlevi, başarı işleyicisine iletilen bir parametre olarak istemciye bir değer döndürebilir.

Geçerli parametreler ve döndürülen değerler, Number, Boolean, String veya null gibi JavaScript ilkellerinin yanı sıra ilkellerden, nesnelerden ve dizilerden oluşan JavaScript nesneleri ve dizileridir. Sayfadaki bir form öğesi de parametre olarak yasaldır ancak işlevin tek parametresi olmalıdır ve dönüş değeri olarak yasal değildir. form dışında bir Date, Function, DOM öğesi veya nesne ya da dizilerdeki yasaklanmış türler de dahil olmak üzere başka bir yasaklanmış tür iletmeye çalışırsanız istekler başarısız olur. Döngüsel referans oluşturan nesneler de başarısız olur ve dizilerdeki tanımlanmamış alanlar null olur.

Sunucuya iletilen bir nesnenin orijinal nesnenin kopyası haline geldiğini unutmayın. Bir sunucu işlevi bir nesne alır ve nesne özelliklerini değiştirirse istemcideki özellikler bundan etkilenmez.

Başarı işleyicileri

İstemci tarafı kod, sunucu çağrısının tamamlanmasını beklemeden bir sonraki satıra devam ettiğinden withSuccessHandler(function), sunucu yanıt verdiğinde çalışacak bir istemci tarafı geri çağırma işlevi belirtmenize olanak tanır. Sunucu işlevi bir değer döndürürse API, değeri yeni işleve parametre olarak iletir.

Aşağıdaki örnekte, sunucu yanıt verdiğinde bir tarayıcı uyarısı gösterilmektedir. Sunucu tarafı işlevi Gmail hesabınıza eriştiği için bu kod örneğinin yetkilendirme gerektirdiğini unutmayın. Komut dosyasını yetkilendirmenin en basit yolu, sayfayı yüklemeden önce getUnreadEmails() işlevini komut dosyası düzenleyicisinden manuel olarak bir kez çalıştırmaktır. Alternatif olarak, web uygulamasını dağıtırken "web uygulamasına erişen kullanıcı" olarak çalıştırmayı seçebilirsiniz. Bu durumda, uygulamayı yüklerken yetkilendirme istenir.

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>

Hata işleyiciler

Sunucu yanıt vermezse veya hata verirse withFailureHandler(function), başarı işleyici yerine bir hata işleyici belirtmenize olanak tanır. Bu durumda Error nesnesi (varsa) bağımsız değişken olarak iletilir.

Varsayılan olarak, hata işleyici belirtmezseniz hatalar JavaScript konsoluna kaydedilir. Bunu geçersiz kılmak için withFailureHandler(null) işlevini çağırın veya hiçbir şey yapmayan bir hata işleyici sağlayın.

Bu örnekte gösterildiği gibi, hata işleyicilerin söz dizimi başarı işleyicilerle neredeyse aynıdır.

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>

Kullanıcı nesneleri

withUserObject(object) işlevini çağırarak, ikinci parametre olarak işleyiciye iletilecek bir nesne belirterek aynı başarı veya başarısızlık işleyicisini sunucuya yapılan birden fazla çağrı için yeniden kullanabilirsiniz. User sınıfıyla karıştırılmaması gereken bu "kullanıcı nesnesi", istemcinin sunucuyla iletişim kurduğu bağlama yanıt vermenizi sağlar. Kullanıcı nesneleri sunucuya gönderilmediğinden, sunucu çağrıları için parametreler ve döndürülen değerlerle ilgili kısıtlamalar olmadan işlevler, DOM öğeleri vb. dahil olmak üzere neredeyse her şey olabilirler. Ancak kullanıcı nesneleri, new operatörüyle oluşturulan nesneler olamaz.

Bu örnekte, iki düğmeden herhangi biri tıklandığında, bu düğme sunucudaki bir değerle güncellenirken diğer düğme aynı kalır. Ancak her iki düğme de aynı başarı işleyiciyi paylaşır. onclick işleyicisinde this anahtar kelimesi button'yi ifade eder.

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>

Formlar

Bir sunucu işlevini parametre olarak form öğesi ile çağırırsanız form, anahtar olarak alan adlarını ve değer olarak alan değerlerini içeren tek bir nesne haline gelir. Dosya girişi alanlarının içeriği hariç tüm değerler dize olarak dönüştürülür. Dosya girişi alanlarının içeriği ise Blob nesnesi olur.

Bu örnekte, sayfayı yeniden yüklemeden dosya giriş alanı da dahil olmak üzere bir form işlenir. Dosya Google Drive'a yüklenir ve ardından istemci tarafındaki sayfada dosyanın URL'si yazdırılır. onsubmit işleyicisinde this anahtar kelimesi formun kendisini ifade eder. Sayfadaki tüm formların yüklendikten sonra varsayılan gönderme işleminin preventFormSubmit tarafından devre dışı bırakıldığını unutmayın. Bu sayede, sayfanın istisna durumunda yanlış bir URL'ye yönlendirilmesi önlenir.

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>

Komut dosyası çalıştırıcıları

google.script.run'ü "komut dosyası çalıştırıcı" için bir oluşturucu olarak düşünebilirsiniz. Bir komut dosyası çalıştırıcıya başarı işleyici, hata işleyici veya kullanıcı nesnesi eklerseniz mevcut çalıştırıcıyı değiştirmezsiniz. Bunun yerine, yeni davranışa sahip yeni bir komut dosyası çalıştırıcı alırsınız.

withSuccessHandler(), withFailureHandler() ve withUserObject() öğelerini dilediğiniz şekilde ve sırada kullanabilirsiniz. Değiştirme işlevlerinden herhangi birini, zaten bir değeri ayarlanmış bir komut dosyası çalıştırıcısında da çağırabilirsiniz. Yeni değer, önceki değeri geçersiz kılar.

Bu örnekte, üç sunucu çağrısı için ortak bir hata işleyici, ancak iki ayrı başarı işleyici ayarlanmıştır:

var myRunner = google.script.run.withFailureHandler(onFailure);
var myRunner1 = myRunner.withSuccessHandler(onSuccess);
var myRunner2 = myRunner.withSuccessHandler(onDifferentSuccess);

myRunner1.doSomething();
myRunner1.doSomethingElse();
myRunner2.doSomething();

Özel işlevler

Adları alt çizgiyle biten sunucu işlevleri gizli olarak kabul edilir. Bu işlevler google.script tarafından çağrılamaz ve adları hiçbir zaman istemciye gönderilmez. Bu nedenle, sunucu üzerinde gizli tutulması gereken uygulama ayrıntılarını gizlemek için bunları kullanabilirsiniz. google.script, kitaplıklardaki işlevleri ve komut dosyasının en üst düzeyinde tanımlanmayan işlevleri de göremez.

Bu örnekte, getBankBalance() işlevi istemci kodunda mevcuttur. Kaynak kodunuzu inceleyen bir kullanıcı, işlevi çağırmasanız bile adını keşfedebilir. Ancak deepSecret_() ve obj.objectMethod() işlevleri istemci tarafından tamamen görünmez.

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 Uygulamalardaki iletişim kutularını yeniden boyutlandırma

Google Dokümanlar, E-Tablolar veya Formlar'daki özel iletişim kutuları, istemci tarafı kodda google.script.host yöntemleri setWidth(width) veya setHeight(height) çağrılarak yeniden boyutlandırılabilir. (Bir iletişim kutusunun ilk boyutunu ayarlamak için HtmlOutputsetWidth(width) ve setHeight(height) yöntemlerini kullanın.) İletişim kutularının yeniden boyutlandırıldığında ana pencerede yeniden merkezlenmediğini ve yan çubukların yeniden boyutlandırılamadığını unutmayın.

Google Workspace'te iletişim kutularını ve kenar çubuklarını kapatma

Google Dokümanlar, E-Tablolar veya Formlar'da ileti kutusu veya kenar çubuğu görüntülemek için HTML hizmetini kullanıyorsanız window.close() çağrısı yaparak arayüzü kapatamazsınız. Bunun yerine google.script.host.close() numaralı telefonu aramanız gerekir. Örnek için HTML'yi kullanıcı arayüzü olarak sunma Google Workspace başlıklı bölüme bakın.

Tarayıcı odağını Google Workspaceiçinde taşıma

Kullanıcının tarayıcısında odak noktasını bir iletişim kutusundan veya kenar çubuğundan Google Dokümanlar, E-Tablolar ya da Formlar düzenleyicisine geri döndürmek için google.script.host.editor.focus() yöntemini çağırmanız yeterlidir. Bu yöntem özellikle Belge hizmeti yöntemleri Document.setCursor(position) ve Document.setSelection(range) ile birlikte kullanıldığında yararlıdır.