Komut dosyalarını V8 çalışma zamanına taşıma

Rhino çalışma zamanı, 31 Ocak 2026 itibarıyla kullanımdan kaldırılacak. Rhino çalışma zamanını kullanan mevcut bir komut dosyanız varsa bu komut dosyasını V8'e taşımanız gerekir.

Genellikle V8 söz dizimi ve özelliklerini bir komut dosyasına eklemenin tek ön koşulu V8 çalışma zamanını etkinleştirmektir. Ancak, V8 çalışma zamanında bir komut dosyasının başarısız olmasına veya beklenmedik şekilde davranmasına neden olabilecek küçük bir uyumsuzluk ve diğer farklılıklar kümesi vardır. Bir komut dosyasını V8 kullanacak şekilde taşırken komut dosyası projesinde bu sorunları aramanız ve bulduğunuz sorunları düzeltmeniz gerekir.

V8'e taşıma prosedürü

Bir komut dosyasını V8'e taşımak için şu prosedürü uygulayın:

  1. Komut dosyası için V8 çalışma zamanını etkinleştirin. runtimeVersion, Apps Komut Dosyası projesinin manifest dosyası kullanılarak kontrol edilebilir.
  2. Aşağıdaki uyumsuzlukları dikkatlice inceleyin. Uyumsuzluklardan herhangi birinin mevcut olup olmadığını belirlemek için komut dosyanızı inceleyin. Bir veya daha fazla uyumsuzluk varsa sorunu gidermek ya da önlemek için komut dosyası kodunuzu düzenleyin.
  3. Aşağıdaki diğer farklılıkları dikkatlice inceleyin. Listelenen farklılıklardan herhangi birinin kodunuzun davranışını etkileyip etkilemediğini belirlemek için komut dosyanızı inceleyin. Davranışı düzeltmek için komut dosyanızı ayarlayın.
  4. Tespit edilen uyumsuzlukları veya diğer farklılıkları düzelttikten sonra kodunuzu V8 söz dizimini ve diğer özellikleri kullanacak şekilde güncellemeye başlayabilirsiniz.
  5. Kod düzenlemelerinizi tamamladıktan sonra, komut dosyanızın beklendiği gibi çalıştığından emin olmak için komut dosyanızı kapsamlı bir şekilde test edin.
  6. Komut dosyanız bir web uygulamasıysa veya yayınlanmış bir eklentiyse, V8 düzenlemelerini içeren komut dosyasının yeni bir sürümünü oluşturmanız ve dağıtımı yeni oluşturulan sürüme yönlendirmeniz gerekir. V8 sürümünü kullanıcıların kullanımına sunmak için komut dosyasını bu sürümle yeniden yayınlamanız gerekir.
  7. Komut dosyanız kitaplık olarak kullanılıyorsa komut dosyanızın yeni bir sürüm oluşturulmuş dağıtımını oluşturun. Bu yeni sürümü, kitaplığınızı kullanan tüm komut dosyalarına ve kullanıcılara ileterek V8 özellikli sürüme güncellemelerini isteyin. Kitaplığınızın Rhino tabanlı eski sürümlerinin artık etkin olarak kullanılmadığını veya erişilebilir olmadığını doğrulayın.
  8. Komut dosyanızın hiçbir örneğinin eski Rhino çalışma zamanında çalışmadığını doğrulayın. Tüm dağıtımların V8 sürümünde olan bir sürümle ilişkilendirildiğini doğrulayın. Eski dağıtımları arşivleyin. Tüm sürümleri inceleyin ve V8 çalışma zamanını kullanmayan sürümleri silin.

Uyumsuzluklar

Orijinal Rhino tabanlı Apps Komut Dosyası çalışma zamanı maalesef birkaç standart dışı ECMAScript davranışına izin veriyordu. V8 standartlara uygun olduğundan bu davranışlar taşıma işleminden sonra desteklenmez. Bu sorunların düzeltilmemesi, V8 çalışma zamanı etkinleştirildikten sonra hatalara veya komut dosyası davranışının bozulmasına neden olur.

Aşağıdaki bölümlerde bu davranışların her biri ve V8'e geçiş sırasında komut dosyası kodunuzu düzeltmek için atmanız gereken adımlar açıklanmaktadır.

for each(variable in object) kullanmaktan kaçının

for each (variable in object) ifadesi JavaScript 1.6'ya eklendi ve for...of lehine kaldırıldı.

Komut dosyanızı V8'e taşırken for each (variable in object) ifadelerini kullanmaktan kaçının.

Bunun yerine for (variable in object) kullanın:

// Rhino runtime
var obj = {a: 1, b: 2, c: 3};

// Don't use 'for each' in V8
for each (var value in obj) {
  Logger.log("value = %s", value);
}
      
// V8 runtime
var obj = {a: 1, b: 2, c: 3};

for (var key in obj) {  // OK in V8
  var value = obj[key];
  Logger.log("value = %s", value);
}
      

Date.prototype.getYear() kullanmaktan kaçının

Orijinal Rhino çalışma zamanında, Date.prototype.getYear() 1900-1999 yılları için iki haneli yıllar, diğer tarihler için ise dört haneli yıllar döndürür. Bu, JavaScript 1.2 ve önceki sürümlerdeki davranıştı.

V8 çalışma zamanında, Date.prototype.getYear() ECMAScript standartlarının gerektirdiği şekilde yıl eksi 1900 değerini döndürür.

Komut dosyanızı V8'e taşırken her zaman Date.prototype.getFullYear() kullanın. Bu işlev, tarihten bağımsız olarak dört haneli bir yıl döndürür.

Ayrılmış anahtar kelimeleri ad olarak kullanmaktan kaçının

ECMAScript, işlev ve değişken adlarında belirli ayrılmış anahtar kelimelerin kullanılmasını yasaklar. Rhino çalışma zamanı bu kelimelerin çoğuna izin veriyordu. Bu nedenle, kodunuzda bu kelimeler kullanılıyorsa işlevlerinizi veya değişkenlerinizi yeniden adlandırmanız gerekir.

Komut dosyanızı V8'e taşırken değişkenleri veya işlevleri ayrılmış anahtar kelimelerden birini kullanarak adlandırmayın. Anahtar kelime adını kullanmamak için herhangi bir değişkeni veya işlevi yeniden adlandırın. Anahtar kelimelerin ad olarak yaygın kullanımları class, import ve export'dir.

const değişkenlerini yeniden atamaktan kaçının

Orijinal Rhino çalışma zamanında, const kullanarak bir değişken bildirebilirsiniz. Bu, sembolün değerinin asla değişmediği ve sembole gelecekteki atamaların yoksayıldığı anlamına gelir.

Yeni V8 çalışma zamanında const anahtar kelimesi standartlara uygundur ve const olarak tanımlanan bir değişkene atama yapılması TypeError: Assignment to constant variable çalışma zamanı hatasına neden olur.

Komut dosyanızı V8'e taşırken const değişkeninin değerini yeniden atamaya çalışmayın:

// Rhino runtime
const x = 1;
x = 2;          // No error
console.log(x); // Outputs 1
      
// V8 runtime
const x = 1;
x = 2;          // Throws TypeError
console.log(x); // Never executed
      

XML değişmezlerinden ve XML nesnesinden kaçının

ECMAScript'in bu standart dışı uzantısı, Apps Komut Dosyası projelerinin doğrudan XML söz dizimini kullanmasına olanak tanır.

Komut dosyanızı V8'e taşırken doğrudan XML değişmezleri veya XML nesnesi kullanmaktan kaçının.

Bunun yerine, XML'yi ayrıştırmak için XmlService'i kullanın:

// V8 runtime
var incompatibleXml1 = <container><item/></container>;             // Don't use
var incompatibleXml2 = new XML('<container><item/></container>');  // Don't use

var xml3 = XmlService.parse('<container><item/></container>');     // OK
      

__iterator__ kullanarak özel yineleyici işlevler oluşturmayın.

JavaScript 1.7, bir sınıfın prototipinde __iterator__ işlevi tanımlayarak herhangi bir sınıfa özel yineleyici eklemeye olanak tanıyan bir özellik ekledi. Bu özellik, geliştiricilerin rahatlığı için Apps Komut Dosyası'nın Rhino çalışma zamanına da eklendi. Ancak bu özellik hiçbir zaman ECMA-262 standardının bir parçası olmadı ve ECMAScript uyumlu JavaScript motorlarında kaldırıldı. V8 kullanan komut dosyaları bu yineleyici yapısını kullanamaz.

Komut dosyanızı V8'e taşırken __iterator__ işlevini kullanaraközel yineleyiciler oluşturmaktan kaçının. Bunun yerine ECMAScript 6 yineleyicilerini kullanın.

Aşağıdaki dizi yapısını inceleyin:

// Create a sample array
var myArray = ['a', 'b', 'c'];
// Add a property to the array
myArray.foo = 'bar';

// The default behavior for an array is to return keys of all properties,
//  including 'foo'.
Logger.log("Normal for...in loop:");
for (var item in myArray) {
  Logger.log(item);            // Logs 0, 1, 2, foo
}

// To only log the array values with `for..in`, a custom iterator can be used.
      

Aşağıdaki kod örneklerinde, Rhino çalışma zamanında bir yineleyicinin nasıl oluşturulabileceği ve V8 çalışma zamanında nasıl yedek yineleyici oluşturulacağı gösterilmektedir:

// Rhino runtime custom iterator
function ArrayIterator(array) {
  this.array = array;
  this.currentIndex = 0;
}

ArrayIterator.prototype.next = function() {
  if (this.currentIndex
      >= this.array.length) {
    throw StopIteration;
  }
  return "[" + this.currentIndex
    + "]=" + this.array[this.currentIndex++];
};

// Direct myArray to use the custom iterator
myArray.__iterator__ = function() {
  return new ArrayIterator(this);
}


Logger.log("With custom Rhino iterator:");
for (var item in myArray) {
  // Logs [0]=a, [1]=b, [2]=c
  Logger.log(item);
}
      
// V8 runtime (ECMAScript 6) custom iterator
myArray[Symbol.iterator] = function() {
  var currentIndex = 0;
  var array = this;

  return {
    next: function() {
      if (currentIndex < array.length) {
        return {
          value: "[${currentIndex}]="
            + array[currentIndex++],
          done: false};
      } else {
        return {done: true};
      }
    }
  };
}

Logger.log("With V8 custom iterator:");
// Must use for...of since
//   for...in doesn't expect an iterable.
for (var item of myArray) {
  // Logs [0]=a, [1]=b, [2]=c
  Logger.log(item);
}
      

Koşullu yakalama ifadelerinden kaçının

V8 çalışma zamanı, standartlara uygun olmadıkları için catch..if koşullu yakalama ifadelerini desteklemez.

Komut dosyanızı V8'e taşırken tüm yakalama koşullarını catch gövdesinin içine taşıyın:

// Rhino runtime

try {
  doSomething();
} catch (e if e instanceof TypeError) {  // Don't use
  // Handle exception
}
      
// V8 runtime
try {
  doSomething();
} catch (e) {
  if (e instanceof TypeError) {
    // Handle exception
  }
}

Object.prototype.toSource() kullanmaktan kaçının

JavaScript 1.3, hiçbir zaman ECMAScript standardının parçası olmayan bir Object.prototype.toSource() yöntemi içeriyordu. V8 çalışma zamanında desteklenmez.

Komut dosyanızı V8'e taşırken kodunuzda Object.prototype.toSource() kullanımını kaldırın.

Diğer farklılıklar

Komut dosyası hatalarına neden olabilecek yukarıdaki uyumsuzluklara ek olarak, düzeltilmediği takdirde beklenmedik V8 çalışma zamanı komut dosyası davranışına yol açabilecek birkaç farklılık daha vardır.

Aşağıdaki bölümlerde, bu tür beklenmedik durumlarla karşılaşmamak için komut dosyası kodunuzu nasıl güncelleyeceğiniz açıklanmaktadır.

Yerel ayara özgü tarih ve saat biçimlendirmesini ayarlama

Date yöntemleri toLocaleString(), toLocaleDateString(), ve toLocaleTimeString() V8 çalışma zamanında Rhino'ya kıyasla farklı şekilde davranır.

Rhino'da varsayılan biçim uzun biçimdir ve iletilen tüm parametreler yoksayılır.

V8 çalışma zamanında varsayılan biçim kısa biçimdir ve iletilen parametreler ECMA standardına göre işlenir (ayrıntılar için toLocaleDateString() dokümanlarına bakın).

V8'e geçiş yaparken kodunuzun yerel ayara özgü tarih ve saat yöntemlerinin çıkışıyla ilgili beklentilerini test edin ve ayarlayın:

// Rhino runtime
var event = new Date(
  Date.UTC(2012, 11, 21, 12));

// Outputs "December 21, 2012" in Rhino
console.log(event.toLocaleDateString());

// Also outputs "December 21, 2012",
//  ignoring the parameters passed in.
console.log(event.toLocaleDateString(
    'de-DE',
    { year: 'numeric',
      month: 'long',
      day: 'numeric' }));
// V8 runtime
var event = new Date(
  Date.UTC(2012, 11, 21, 12));

// Outputs "12/21/2012" in V8
console.log(event.toLocaleDateString());

// Outputs "21. Dezember 2012"
console.log(event.toLocaleDateString(
    'de-DE',
    { year: 'numeric',
      month: 'long',
      day: 'numeric' }));
      

Error.fileName ve Error.lineNumber kullanmaktan kaçının

V8 çalışma zamanında, standart JavaScript Error nesnesi, oluşturucu parametreleri veya nesne özellikleri olarak fileName ya da lineNumber değerlerini desteklemez.

Komut dosyanızı V8'e taşırken, Error.fileName ve Error.lineNumber bağımlılıklarını kaldırın.

Alternatif olarak Error.prototype.stack simgesini kullanabilirsiniz. Bu yığın da standart dışıdır ancak V8'de desteklenir. İki platform tarafından oluşturulan yığın izinin biçimi biraz farklıdır:

// Rhino runtime Error.prototype.stack
// stack trace format
at filename:92 (innerFunction)
at filename:97 (outerFunction)
// V8 runtime Error.prototype.stack
// stack trace format
Error: error message
at innerFunction (filename:92:11)
at outerFunction (filename:97:5)
      

Dizeleştirilmiş enum nesnelerinin işlenmesini ayarlama

Orijinal Rhino çalışma zamanında, bir enum nesnesinde JavaScript JSON.stringify() yöntemini kullanmak yalnızca {} değerini döndürür.

V8'de, aynı yöntemi bir enum nesnesinde kullanmak enum adını döndürür.

V8'e geçiş yaparken, kodunuzun JSON.stringify() numaralandırılmış nesnelerdeki çıkışıyla ilgili beklentilerini test edin ve ayarlayın:

// Rhino runtime
var enumName =
  JSON.stringify(Charts.ChartType.BUBBLE);

// enumName evaluates to {}
// V8 runtime
var enumName =
  JSON.stringify(Charts.ChartType.BUBBLE);

// enumName evaluates to "BUBBLE"

Tanımlanmamış parametrelerin işlenmesini ayarlama

Orijinal Rhino çalışma zamanında, bir yönteme parametre olarak undefined iletildiğinde bu yönteme "undefined" dizesi iletiliyordu.

V8'de yöntemlere undefined iletmek, null iletmeye eş değerdir.

Komut dosyanızı V8'e taşırken, kodunuzun undefined parametreleriyle ilgili beklentilerini test edin ve ayarlayın:

// Rhino runtime
SpreadsheetApp.getActiveRange()
    .setValue(undefined);

// The active range now has the string
// "undefined"  as its value.
      
// V8 runtime
SpreadsheetApp.getActiveRange()
    .setValue(undefined);

// The active range now has no content, as
// setValue(null) removes content from
// ranges.

Global this işleme yöntemini ayarlayın

Rhino çalışma zamanı, kendisini kullanan komut dosyaları için örtülü bir özel bağlam tanımlar. Komut dosyası kodu, gerçek global this'dan farklı olarak bu örtülü bağlamda çalışır. Bu, kodda "global this" referanslarının aslında yalnızca komut dosyasında tanımlanan kodu ve değişkenleri içeren özel bağlam olarak değerlendirildiği anlamına gelir. Yerleşik Apps Komut Dosyası hizmetleri ve ECMAScript nesneleri, this kullanımının kapsamı dışındadır. Bu durum, aşağıdaki JavaScript yapısına benziyordu:

// Rhino runtime

// Apps Script built-in services defined here, in the actual global context.
var SpreadsheetApp = {
  openById: function() { ... }
  getActive: function() { ... }
  // etc.
};

function() {
  // Implicit special context; all your code goes here. If the global this
  // is referenced in your code, it only contains elements from this context.

  // Any global variables you defined.
  var x = 42;

  // Your script functions.
  function myFunction() {
    ...
  }
  // End of your code.
}();

V8'de örtülü özel bağlam kaldırılır. Komut dosyasında tanımlanan genel değişkenler ve işlevler, yerleşik Apps Komut Dosyası hizmetlerinin ve Math ile Date gibi ECMAScript yerleşiklerinin yanında genel bağlama yerleştirilir.

Komut dosyanızı V8'e taşırken kodunuzun, genel bağlamda this kullanımına ilişkin beklentilerini test edin ve ayarlayın. Çoğu durumda, farklılıklar yalnızca kodunuz genel this nesnesinin anahtarlarını veya özellik adlarını inceliyorsa belirgindir:

// Rhino runtime
var myGlobal = 5;

function myFunction() {

  // Only logs [myFunction, myGlobal];
  console.log(Object.keys(this));

  // Only logs [myFunction, myGlobal];
  console.log(
    Object.getOwnPropertyNames(this));
}





      
// V8 runtime
var myGlobal = 5;

function myFunction() {

  // Logs an array that includes the names
  // of Apps Script services
  // (CalendarApp, GmailApp, etc.) in
  // addition to myFunction and myGlobal.
  console.log(Object.keys(this));

  // Logs an array that includes the same
  // values as above, and also includes
  // ECMAScript built-ins like Math, Date,
  // and Object.
  console.log(
    Object.getOwnPropertyNames(this));
}

Kitaplıklarda instanceof ile ilgili işlemleri ayarlama

Başka bir projedeki bir işlevde parametre olarak iletilen bir nesne üzerindeki bir kitaplıkta instanceof kullanmak yanlış negatif sonuçlar verebilir. V8 çalışma zamanında, bir proje ve kitaplıkları farklı yürütme bağlamlarında çalıştırılır. Bu nedenle, farklı genel değişkenlere ve prototip zincirlerine sahiptirler.

Bu durumun yalnızca kitaplığınızda projenizde oluşturulmamış bir nesnede instanceof kullanılıyorsa geçerli olduğunu unutmayın. Projenizde oluşturulan bir nesnede (projenizdeki aynı veya farklı bir komut dosyasında) kullanıldığında beklendiği gibi çalışır.

V8 üzerinde çalışan bir proje, komut dosyanızı kitaplık olarak kullanıyorsa komut dosyanızın başka bir projeden geçirilecek bir parametrede instanceof kullanıp kullanmadığını kontrol edin. instanceof kullanımını ayarlayın ve kullanım alanınıza göre diğer uygun alternatifleri kullanın.

a instanceof b için bir alternatif, tüm prototip zincirinde arama yapmanız gerekmediği ve yalnızca oluşturucuyu kontrol etmeniz gereken durumlarda a oluşturucusunu kullanmaktır. Kullanım: a.constructor.name == "b"

Proje A'nın Proje B'yi kitaplık olarak kullandığı Proje A ve Proje B'yi ele alalım.

//Rhino runtime

//Project A

function caller() {
   var date = new Date();
   // Returns true
   return B.callee(date);
}

//Project B

function callee(date) {
   // Returns true
   return(date instanceof Date);
}

      
//V8 runtime

//Project A

function caller() {
   var date = new Date();
   // Returns false
   return B.callee(date);
}

//Project B

function callee(date) {
   // Incorrectly returns false
   return(date instanceof Date);
   // Consider using return (date.constructor.name ==
   // Date) instead.
   // return (date.constructor.name == Date) -> Returns
   // true
}

Başka bir alternatif olarak, ana projede instanceof değerini kontrol eden bir işlev sunulabilir ve bir kitaplık işlevi çağrılırken işlev diğer parametrelerle birlikte iletilebilir. Daha sonra, geçirilen işlev kitaplıkta instanceof değerini kontrol etmek için kullanılabilir.

//V8 runtime

//Project A

function caller() {
   var date = new Date();
   // Returns True
   return B.callee(date, date => date instanceof Date);
}

//Project B

function callee(date, checkInstanceOf) {
  // Returns True
  return checkInstanceOf(date);
}
      

Paylaşılmayan kaynakların kitaplıklara aktarılmasını ayarlama

Ana komut dosyasından kitaplığa paylaşılmayan bir kaynağın aktarılması, V8 çalışma zamanında farklı şekilde çalışır.

Rhino çalışma zamanında, paylaşılmayan bir kaynağın iletilmesi çalışmaz. Kitaplık bunun yerine kendi kaynağını kullanır.

V8 çalışma zamanında, paylaşılan olmayan bir kaynağı kitaplığa aktarmak mümkündür. Kitaplık, iletilen paylaşılmayan kaynağı kullanır.

Paylaşılmayan kaynakları işlev parametresi olarak iletmeyin. Paylaşılmayan kaynakları her zaman bunları kullanan aynı komut dosyasında bildirin.

Proje A'nın Proje B'yi kitaplık olarak kullandığı Proje A ve Proje B'yi ele alalım. Bu örnekte, PropertiesService paylaşılmayan bir kaynaktır.

// Rhino runtime
// Project A
function testPassingNonSharedProperties() {
  PropertiesService.getScriptProperties()
      .setProperty('project', 'Project-A');
  B.setScriptProperties();
  // Prints: Project-B
  Logger.log(B.getScriptProperties(
      PropertiesService, 'project'));
}

//Project B function setScriptProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-B'); } function getScriptProperties( propertiesService, key) { return propertiesService.getScriptProperties() .getProperty(key); }

// V8 runtime
// Project A
function testPassingNonSharedProperties() {
  PropertiesService.getScriptProperties()
      .setProperty('project', 'Project-A');
  B.setScriptProperties();
  // Prints: Project-A
  Logger.log(B.getScriptProperties(
      PropertiesService, 'project'));
}

// Project B function setProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-B'); } function getScriptProperties( propertiesService, key) { return propertiesService.getScriptProperties() .getProperty(key); }

Bağımsız komut dosyalarına erişimi güncelleme

V8 çalışma zamanında çalışan bağımsız komut dosyalarının tetikleyicilerinin düzgün çalışması için kullanıcılara komut dosyasına en az görüntüleme erişimi vermeniz gerekir.