Service Worker'a geçin

Arka plan veya etkinlik sayfalarını bir hizmet çalışanıyla değiştirme

Service Worker, arka plan kodunun ana iş parçacığı dışında kalmasını sağlamak için uzantının arka planını veya etkinlik sayfasını değiştirir. Bu, uzantıların yalnızca gerektiğinde çalıştırılmasını sağlayarak kaynaklardan tasarruf edilmesini sağlar.

Arka plan sayfaları, kullanıma sunulmalarından bu yana uzantıların temel bir bileşeni olmuştur. Basitçe ifade etmek gerekirse arka plan sayfaları, diğer pencere veya sekmelerden bağımsız olarak çalışan bir ortam sağlar. Bu sayede uzantılar, etkinlikleri gözlemleyip olaylara göre hareket edebilir.

Bu sayfada, arka plan sayfalarını uzantı hizmet çalışanlarına dönüştürme görevleri açıklanmaktadır. Uzantı hizmeti çalışanları hakkında genel olarak daha fazla bilgi edinmek için Hizmet çalışanları ile etkinlikleri işleme eğitimine ve Uzantı hizmeti çalışanları hakkında bölümüne göz atın.

Arka plan komut dosyaları ile uzantı hizmet çalışanları arasındaki farklar

Bazı bağlamlarda, "arka plan komut dosyaları" adı verilen uzantı hizmeti çalışanları görürsünüz. Uzantı hizmeti çalışanları arka planda çalışıyor olsa da, aynı işlevleri ima ederek arka plan komut dosyalarını çağırmak biraz yanıltıcıdır. Farklılıklar aşağıda açıklanmıştır.

Arka plan sayfalarından değişiklikler

Service Worker'lar, arka plan sayfalarıyla bazı farklılıklar gösterir.

  • Bunlar ana ileti dizisinden yararlanır, yani uzantı içeriğine müdahale etmezler.
  • Uzantının kaynağında, araç çubuğu pop-up'ında olduğu gibi getirme etkinliklerine müdahale etme gibi özel işlevleri vardır.
  • İstemciler arayüzü aracılığıyla diğer bağlamlarla iletişim kurabilir ve etkileşimde bulunabilirler.

Yapmanız gereken değişiklikler

Arka plan komut dosyaları ve Service Worker'ların çalışma biçimleri arasındaki farkları çözmek için birkaç kod ayarlaması yapmanız gerekir. Öncelikle, manifest dosyasında bir hizmet çalışanının belirtilme şekli, arka plan komut dosyalarının belirtilmesinden farklıdır. Ayrıca:

  • DOM veya window arayüzüne erişemediği için bu tür çağrıları farklı bir API'ye veya ekran dışı bir dokümana taşımanız gerekir.
  • Etkinlik işleyiciler, döndürülen vaatlere veya etkinlik içi geri çağırmalara yanıt olarak kaydedilmemelidir.
  • XMLHttpRequest() ile geriye dönük uyumlu olmadıkları için bu arayüze yapılan aramaları fetch() çağrılarıyla değiştirmeniz gerekir.
  • Kullanılmadıkları zaman sona erdiklerinden, genel değişkenlere bel bağlamak yerine uygulama durumlarını korumanız gerekir. Ayrıca, hizmet çalışanlarının sonlandırılması, zamanlayıcılar tamamlanmadan önce de sonlandırılabilir. Bunları alarmlarla değiştirmeniz gerekiyor.

Bu sayfada bu görevler ayrıntılı olarak açıklanmaktadır.

Manifest'teki "arka plan" alanını güncelleme

Manifest V3'te arka plan sayfalarının yerini hizmet çalışanı alır. Manifest değişiklikleri aşağıda listelenmiştir.

  • manifest.json bölümünde "background.scripts" yerine "background.service_worker" koyun. "service_worker" alanının bir dize dizisi değil, bir dize aldığına dikkat edin.
  • "background.persistent" hesabını manifest.json görünümünden kaldırın.
Manifest V2
{
  ...
  "background": {
    "scripts": [
      "backgroundContextMenus.js",
      "backgroundOauth.js"
    ],
    "persistent": false
  },
  ...
}
Manifest V3
{
  ...
  "background": {
    "service_worker": "service_worker.js",
    "type": "module"
  }
  ...
}

"service_worker" alanı tek bir dize alır. "type" alanına yalnızca ES modülleri kullanıyorsanız (import anahtar kelimesini kullanarak) ihtiyacınız olacaktır. Bu değerin değeri her zaman "module" olur. Daha fazla bilgi için Uzantı hizmeti çalışanıyla ilgili temel bilgiler başlıklı makaleyi inceleyin

DOM ve pencere çağrılarını ekran dışı bir dokümana taşıma

Bazı uzantıların, görsel olarak yeni bir pencere veya sekme açmadan DOM ve pencere nesnelerine erişmesi gerekir. Outscreen API'si, uzantıyla paket halinde sunulan gösterilmeyen dokümanları kullanıcı deneyimini kesintiye uğratmadan açıp kapatarak bu kullanım alanlarını destekler. Ekran dışı dokümanlar, mesaj iletme hariç olmak üzere diğer uzantı bağlamlarıyla API'leri paylaşmaz, ancak uzantıların etkileşimde bulunacağı tam web sayfaları işlevi görür.

Offscreen API'yi kullanmak için hizmet çalışanından ekran dışı bir doküman oluşturun.

chrome.offscreen.createDocument({
  url: chrome.runtime.getURL('offscreen.html'),
  reasons: ['CLIPBOARD'],
  justification: 'testing the offscreen API',
});

Ekran dışındaki dokümanda, önceden bir arka plan komut dosyasında çalıştıracağınız tüm işlemleri gerçekleştirin. Örneğin, ana makine sayfasında seçilen metni kopyalayabilirsiniz.

let textEl = document.querySelector('#text');
textEl.value = data;
textEl.select();
document.execCommand('copy');

İleti iletmeyi kullanarak ekran dışındaki dokümanlar ile uzantı hizmeti çalışanları arasında iletişim kurun.

localStorage'ı başka bir türe dönüştürme

Web platformunun Storage arayüzü (window.localStorage adresinden erişilebilir) Service Worker'da kullanılamaz. Bu sorunu gidermek için aşağıdaki iki işlemden birini yapın. Öncelikle, bunu başka bir depolama mekanizmasına yapılan çağrılarla değiştirebilirsiniz. chrome.storage.local ad alanı çoğu kullanım alanını sunar ancak başka seçenekler de kullanılabilir.

Aramaları ekran dışındaki bir dokümana da taşıyabilirsiniz. Örneğin, daha önce localStorage içinde depolanan verileri başka bir sisteme taşımak için:

  1. Dönüşüm rutini ve runtime.onMessage işleyicisi ile ekran dışı bir doküman oluşturun.
  2. Ekran dışı dokümana bir dönüşüm rutini ekleyin.
  3. Uzantı hizmet çalışanında, verilerinizi chrome.storage kontrol edin.
  4. Verileriniz bulunamazsa ekran dışı bir belge oluşturun ve dönüşüm rutinini başlatmak için runtime.sendMessage() numaralı telefonu arayın.
  5. Ekran dışı dokümana eklediğiniz runtime.onMessage işleyicide, dönüşüm rutinini çağırın.

Web depolama API'lerinin uzantılarda çalışma şekliyle ilgili bazı nüanslar da vardır. Depolama Alanı ve Çerezler bölümünde daha fazla bilgi edinebilirsiniz.

İşleyicileri eşzamanlı olarak kaydetme

Dinleyiciyi eşzamansız olarak kaydetme (ör. bir söz veya geri arama içinde) Manifest V3'te çalışacağı garanti edilmez. Aşağıdaki kodu kullanabilirsiniz.

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.browserAction.setBadgeText({ text: badgeText });
  chrome.browserAction.onClicked.addListener(handleActionClick);
});

Sayfa sürekli olarak çalıştığından ve hiçbir zaman yeniden başlatılmadığından bu özellik kalıcı bir arka plan sayfasıyla çalışır. Manifest V3'te, etkinlik gönderildiğinde hizmet çalışanı yeniden başlatılır. Bu, etkinlik tetiklendiğinde işleyicilerin (eşzamansız olarak eklendiklerinden) kaydedilmeyeceği ve etkinliğin atlanacağı anlamına gelir.

Bunun yerine, etkinlik işleyici kaydını komut dosyanızın en üst düzeyine taşıyın. Bu, uzantınızın başlangıç mantığını yürütmeyi tamamlamamış olsa bile Chrome'un işleminizin tıklama işleyicisini hemen bulup çağırabilmesini sağlar.

chrome.action.onClicked.addListener(handleActionClick);

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.action.setBadgeText({ text: badgeText });
});

XMLHttpRequest() işlevini global fetch() ile değiştirin

XMLHttpRequest() hizmet çalışanı, uzantı veya başka bir yerden çağrılamaz. Arka plan komut dosyanızdan XMLHttpRequest() öğesine yapılan çağrıları global fetch() çağrılarıyla değiştirin.

XMLHttpRequest()
const xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.readyState);

xhr.open('GET', '/api', true);
console.log('OPENED', xhr.readyState);

xhr.onload = () => {
    console.log('DONE', xhr.readyState);
};
xhr.send(null);
fetch()
const response = await fetch('https://www.example.com/greeting.json'')
console.log(response.statusText);

Eyaletleri koru

Service Worker'lar geçicidir. Yani bir kullanıcının tarayıcı oturumunda hizmet çalışanları sürekli olarak başlatılır, çalışır ve sonlandırılır. Bu durum, önceki bağlam kullanımdan kaldırıldığı için verilerin genel değişkenlerde hemen kullanılamayacağı anlamına da gelir. Bu sorunu gidermek için veri kaynağı olarak depolama API'lerini kullanın. Bir örnek bunun nasıl yapılacağını gösterir.

Aşağıdaki örnekte bir adı depolamak için genel değişken kullanılmaktadır. Service Worker'larda bu değişken, kullanıcının tarayıcı oturumu boyunca birden çok kez sıfırlanabilir.

Manifest V2 arka plan komut dosyası
let savedName = undefined;

chrome.runtime.onMessage.addListener(({ type, name }) => {
  if (type === "set-name") {
    savedName = name;
  }
});

chrome.browserAction.onClicked.addListener((tab) => {
  chrome.tabs.sendMessage(tab.id, { name: savedName });
});

Manifest V3'te, genel değişkeni Storage API çağrısıyla değiştirin.

Manifest V3 hizmet çalışanı
chrome.runtime.onMessage.addListener(({ type, name }) => {
  if (type === "set-name") {
    chrome.storage.local.set({ name });
  }
});

chrome.action.onClicked.addListener(async (tab) => {
  const { name } = await chrome.storage.local.get(["name"]);
  chrome.tabs.sendMessage(tab.id, { name });
});

Zamanlayıcıları alarmlara dönüştürün

setTimeout() veya setInterval() yöntemleri kullanılarak geciken veya periyodik işlemler yaygın olarak kullanılır. Bununla birlikte, hizmet çalışanı sonlandırıldığında zamanlayıcılar iptal edildiği için bu API'ler hizmet çalışanlarında başarısız olabilir.

Manifest V2 arka plan komut dosyası
// 3 minutes in milliseconds
const TIMEOUT = 3 * 60 * 1000;
setTimeout(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
}, TIMEOUT);

Bunun yerine Alarms API'yi kullanın. Diğer dinleyicilerde olduğu gibi alarm dinleyiciler de senaryonuzun en üst düzeyinde kayıtlı olmalıdır.

Manifest V3 hizmet çalışanı
async function startAlarm(name, duration) {
  await chrome.alarms.create(name, { delayInMinutes: 3 });
}

chrome.alarms.onAlarm.addListener(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
});

Hizmet çalışanını canlı tutun

Service Worker'lar, doğası gereği etkinliğe dayalıdır ve etkin olmadığında sonlandırılır. Bu şekilde Chrome, uzantınızın performansını ve bellek tüketimini optimize edebilir. Hizmet çalışanı yaşam döngüsü belgelerimizi inceleyerek daha fazla bilgi edinebilirsiniz. İstisnai durumlarda, bir hizmet çalışanının daha uzun süre hayatta kalmasını sağlamak için ek önlemler gerekebilir.

Uzun süreli bir işlem tamamlanana kadar hizmet çalışanını aktif tutma

Uzantı API'lerini çağırmayan uzun süreli hizmet çalışanı işlemleri sırasında hizmet çalışanı, çalışma sırasında kapanabilir. Örnekler:

  • Potansiyel olarak beş dakikadan uzun süren bir fetch() isteği (ör. zayıf olabilecek bir bağlantıda büyük bir indirme).
  • 30 saniyeden uzun süren karmaşık bir eşzamansız hesaplama.

Bu gibi durumlarda Service Worker'ın ömrünü uzatmak amacıyla, zaman aşımı sayacını sıfırlamak için düzenli aralıklarla basit bir uzantı API'si çağırabilirsiniz. Bunun yalnızca istisnai durumlar için olduğunu ve çoğu durumda aynı sonuca ulaşmak için genellikle daha iyi ve platform deyimsel bir yöntemi olduğunu unutmayın.

Aşağıdaki örnekte, belirli bir söz yerine geçene kadar hizmet çalışanınızı aktif tutan bir waitUntil() yardımcı işlevi gösterilmektedir:

async function waitUntil(promise) = {
  const keepAlive = setInterval(chrome.runtime.getPlatformInfo, 25 * 1000);
  try {
    await promise;
  } finally {
    clearInterval(keepAlive);
  }
}

waitUntil(someExpensiveCalculation());

Bir hizmet çalışanının aktif olmasını sağlayın

Nadir durumlarda, kullanım ömrünü süresiz olarak uzatmak gerekir. Kurumsal kullanım ile eğitimin en büyük kullanım alanları olduğunu belirledik. Bu kapsamda, özellikle bu tür kullanımlara izin veriyoruz, ancak genel olarak bu kullanımları desteklemiyoruz. Bu istisnai durumlarda, düzenli olarak önemsiz bir uzantı API'si çağırarak bir hizmet çalışanının aktif kalmasını sağlayabilirsiniz. Bu önerinin yalnızca kurumsal veya eğitim amaçlı kullanım alanları için yönetilen cihazlarda çalışan uzantılara yönelik olduğunu hatırlatmak isteriz. Diğer durumlarda buna izin verilmez ve Chrome uzantı ekibinin ileride bu uzantılarla ilgili işlem yapma hakkını saklı tutar.

Hizmet çalışanınızı canlı tutmak için aşağıdaki kod snippet'ini kullanın:

/**
 * Tracks when a service worker was last alive and extends the service worker
 * lifetime by writing the current time to extension storage every 20 seconds.
 * You should still prepare for unexpected termination - for example, if the
 * extension process crashes or your extension is manually stopped at
 * chrome://serviceworker-internals. 
 */
let heartbeatInterval;

async function runHeartbeat() {
  await chrome.storage.local.set({ 'last-heartbeat': new Date().getTime() });
}

/**
 * Starts the heartbeat interval which keeps the service worker alive. Call
 * this sparingly when you are doing work which requires persistence, and call
 * stopHeartbeat once that work is complete.
 */
async function startHeartbeat() {
  // Run the heartbeat once at service worker startup.
  runHeartbeat().then(() => {
    // Then again every 20 seconds.
    heartbeatInterval = setInterval(runHeartbeat, 20 * 1000);
  });
}

async function stopHeartbeat() {
  clearInterval(heartbeatInterval);
}

/**
 * Returns the last heartbeat stored in extension storage, or undefined if
 * the heartbeat has never run before.
 */
async function getLastHeartbeat() {
  return (await chrome.storage.local.get('last-heartbeat'))['last-heartbeat'];
}