অফলাইন কুকবুক

সার্ভিস ওয়ার্কার দিয়ে আমরা অফলাইনে সমাধান করার চেষ্টা ছেড়ে দিয়েছি, এবং ডেভেলপারদের চলমান অংশগুলি দিয়েছি যাতে তারা নিজেরাই সমাধান করতে পারে। এটি আপনাকে ক্যাশিং এবং কীভাবে অনুরোধগুলি পরিচালনা করা হয় তার উপর নিয়ন্ত্রণ দেয়। এর মানে আপনি আপনার নিজস্ব নিদর্শন তৈরি করতে পাবেন। আসুন বিচ্ছিন্নভাবে কয়েকটি সম্ভাব্য নিদর্শন দেখে নেওয়া যাক, তবে বাস্তবে আপনি সম্ভবত ইউআরএল এবং প্রসঙ্গের উপর নির্ভর করে সেগুলির অনেকগুলি ব্যবহার করবেন।

এই ধরনের কিছু প্যাটার্নের কাজের ডেমোর জন্য, প্রশিক্ষিত-থেকে-থ্রিল দেখুন, এবং এই ভিডিওটি কর্মক্ষমতার প্রভাব দেখাচ্ছে।

ক্যাশে মেশিন - কখন সম্পদ সংরক্ষণ করতে হবে

পরিষেবা কর্মী আপনাকে ক্যাশিং থেকে স্বাধীনভাবে অনুরোধগুলি পরিচালনা করতে দেয়, তাই আমি তাদের আলাদাভাবে প্রদর্শন করব। প্রথম আপ, ক্যাশিং, কখন এটি করা উচিত?

ইনস্টলে - একটি নির্ভরতা হিসাবে

ইনস্টলে - একটি নির্ভরতা হিসাবে।
ইনস্টলে - একটি নির্ভরতা হিসাবে।

পরিষেবা কর্মী আপনাকে একটি install ইভেন্ট দেয়। আপনি স্টাফ প্রস্তুত করতে এটি ব্যবহার করতে পারেন, অন্যান্য ইভেন্টগুলি পরিচালনা করার আগে অবশ্যই প্রস্তুত থাকতে হবে৷ এটি ঘটলেও আপনার সার্ভিস ওয়ার্কারের পূর্ববর্তী সংস্করণটি এখনও চলছে এবং পৃষ্ঠাগুলি পরিবেশন করছে, তাই আপনি এখানে যা করবেন তা অবশ্যই এটিকে ব্যাহত করবে না।

এর জন্য আদর্শ: CSS, ইমেজ, ফন্ট, JS, টেমপ্লেট... মূলত যেকোন কিছু যা আপনি আপনার সাইটের "সংস্করণ" থেকে স্ট্যাটিক বিবেচনা করবেন।

এগুলি এমন জিনিস যা আপনার সাইটটিকে সম্পূর্ণরূপে অকার্যকর করে তুলবে যদি সেগুলি আনতে ব্যর্থ হয়, একটি সমতুল্য প্ল্যাটফর্ম-নির্দিষ্ট অ্যাপ প্রাথমিক ডাউনলোডের অংশ করে।

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open('mysite-static-v3').then(function (cache) {
      return cache.addAll([
        '/css/whatever-v3.css',
        '/css/imgs/sprites-v6.png',
        '/css/fonts/whatever-v8.woff',
        '/js/all-min-v4.js',
        // etc.
      ]);
    }),
  );
});

event.waitUntil ইনস্টলের দৈর্ঘ্য এবং সাফল্য নির্ধারণ করার প্রতিশ্রুতি নেয়। প্রতিশ্রুতি প্রত্যাখ্যান করলে, ইনস্টলেশনটি একটি ব্যর্থতা হিসাবে বিবেচিত হবে এবং এই পরিষেবা কর্মীকে পরিত্যক্ত করা হবে (যদি একটি পুরানো সংস্করণ চলছে, এটি অক্ষত রাখা হবে)। caches.open() এবং cache.addAll() ফেরত দেওয়ার প্রতিশ্রুতি। কোনো সম্পদ আনতে ব্যর্থ হলে, cache.addAll() কল প্রত্যাখ্যান করে।

প্রশিক্ষিত-থেকে-থ্রিলে আমি স্ট্যাটিক সম্পদ ক্যাশে করতে এটি ব্যবহার করি।

ইনস্টলে - নির্ভরতা হিসাবে নয়

ইনস্টলে - নির্ভরতা হিসাবে নয়।
ইনস্টলে - নির্ভরতা হিসাবে নয়।

এটি উপরের মতই, তবে ইনস্টলেশন সম্পূর্ণ করতে দেরি করবে না এবং ক্যাশে ব্যর্থ হলে ইনস্টলেশন ব্যর্থ হবে না।

এর জন্য আদর্শ: বড় সম্পদ যা সরাসরি প্রয়োজন হয় না, যেমন একটি গেমের পরবর্তী স্তরের জন্য সম্পদ।

self.addEventListener('install', function (event) {
  event.waitUntil(
    caches.open('mygame-core-v1').then(function (cache) {
      cache
        .addAll
        // levels 11–20
        ();
      return cache
        .addAll
        // core assets and levels 1–10
        ();
    }),
  );
});

উপরের উদাহরণটি 11-20 লেভেলের জন্য cache.addAll প্রতিশ্রুতি পাস event.waitUntil না। অবশ্যই, আপনাকে সেই স্তরগুলির সম্ভাব্য অনুপস্থিতি পূরণ করতে হবে এবং সেগুলি অনুপস্থিত থাকলে সেগুলি ক্যাশ করার পুনরায় চেষ্টা করতে হবে।

11-20 স্তর ডাউনলোড করার সময় পরিষেবা কর্মী নিহত হতে পারে যেহেতু এটি ইভেন্টগুলি পরিচালনা করা শেষ হয়েছে, যার অর্থ তাদের ক্যাশে করা হবে না। ভবিষ্যতে ওয়েব পর্যায়ক্রমিক ব্যাকগ্রাউন্ড সিঙ্ক্রোনাইজেশন API এই ধরনের কেস এবং মুভির মতো বড় ডাউনলোডগুলি পরিচালনা করবে। সেই API বর্তমানে শুধুমাত্র Chromium ফর্কগুলিতে সমর্থিত।

সক্রিয়

সক্রিয়.
সক্রিয়.

এর জন্য আদর্শ: ক্লিন-আপ এবং মাইগ্রেশন।

একবার একটি নতুন পরিষেবা কর্মী ইনস্টল হয়ে গেলে এবং একটি পূর্ববর্তী সংস্করণ ব্যবহার করা হচ্ছে না, নতুনটি সক্রিয় হবে এবং আপনি একটি activate ইভেন্ট পাবেন৷ যেহেতু পুরানো সংস্করণটি শেষ হয়ে গেছে, তাই ইনডেক্সডডিবিতে স্কিমা স্থানান্তরগুলি পরিচালনা করার এবং অব্যবহৃত ক্যাশেগুলি মুছতে এটি একটি ভাল সময়।

self.addEventListener('activate', function (event) {
  event.waitUntil(
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        cacheNames
          .filter(function (cacheName) {
            // Return true if you want to remove this cache,
            // but remember that caches are shared across
            // the whole origin
          })
          .map(function (cacheName) {
            return caches.delete(cacheName);
          }),
      );
    }),
  );
});

অ্যাক্টিভেশনের সময়, fetch মতো অন্যান্য ইভেন্টগুলিকে একটি সারিতে রাখা হয়, তাই একটি দীর্ঘ অ্যাক্টিভেশন পৃষ্ঠা লোডগুলিকে ব্লক করতে পারে৷ আপনার অ্যাক্টিভেশন যতটা সম্ভব কম রাখুন, এবং এটি শুধুমাত্র সেই জিনিসগুলির জন্য ব্যবহার করুন যা আপনি করতে পারেননি যখন পুরানো সংস্করণ সক্রিয় ছিল।

প্রশিক্ষিত-থেকে-থ্রিলে আমি পুরানো ক্যাশেগুলি সরাতে এটি ব্যবহার করি।

ব্যবহারকারী মিথস্ক্রিয়া উপর

ব্যবহারকারী মিথস্ক্রিয়া উপর.
ব্যবহারকারী মিথস্ক্রিয়া উপর.

এর জন্য আদর্শ: যখন পুরো সাইটটি অফলাইনে নেওয়া যায় না, এবং আপনি ব্যবহারকারীকে অফলাইনে উপলব্ধ সামগ্রী নির্বাচন করার অনুমতি দিতে বেছে নেন। যেমন ইউটিউবে একটি ভিডিও, উইকিপিডিয়ার একটি নিবন্ধ, ফ্লিকারে একটি নির্দিষ্ট গ্যালারি।

ব্যবহারকারীকে একটি "পরে পড়ুন" বা "অফলাইনের জন্য সংরক্ষণ করুন" বোতাম দিন৷ এটি ক্লিক করা হলে, নেটওয়ার্ক থেকে আপনার যা প্রয়োজন তা আনুন এবং এটি ক্যাশে পপ করুন৷

document.querySelector('.cache-article').addEventListener('click', function (event) {
  event.preventDefault();

  var id = this.dataset.articleId;
  caches.open('mysite-article-' + id).then(function (cache) {
    fetch('/get-article-urls?id=' + id)
      .then(function (response) {
        // /get-article-urls returns a JSON-encoded array of
        // resource URLs that a given article depends on
        return response.json();
      })
      .then(function (urls) {
        cache.addAll(urls);
      });
  });
});

ক্যাশে API পৃষ্ঠাগুলির পাশাপাশি পরিষেবা কর্মীদের থেকে পাওয়া যায়, যার অর্থ আপনি সরাসরি পৃষ্ঠা থেকে ক্যাশে যোগ করতে পারেন।

নেটওয়ার্ক প্রতিক্রিয়া

নেটওয়ার্ক প্রতিক্রিয়া.
নেটওয়ার্ক প্রতিক্রিয়া.

এর জন্য আদর্শ: ব্যবহারকারীর ইনবক্স বা নিবন্ধের বিষয়বস্তুর মতো ঘন ঘন রিসোর্স আপডেট করা। অবতারের মতো অ-প্রয়োজনীয় বিষয়বস্তুর জন্যও উপযোগী, তবে যত্নের প্রয়োজন।

যদি একটি অনুরোধ ক্যাশে কোনো কিছুর সাথে মেলে না, তবে এটি নেটওয়ার্ক থেকে পান, পৃষ্ঠায় পাঠান এবং একই সময়ে ক্যাশে যোগ করুন।

আপনি যদি এটি বিভিন্ন ইউআরএলের জন্য করেন, যেমন অবতারের জন্য, তাহলে আপনাকে সতর্ক থাকতে হবে যে আপনি আপনার মূলের সঞ্চয়স্থানকে ফুলিয়ে ফেলবেন না। ব্যবহারকারীর যদি ডিস্কের জায়গা পুনরুদ্ধার করতে হয় তবে আপনি প্রধান প্রার্থী হতে চান না। নিশ্চিত করুন যে আপনি ক্যাশে আইটেম পরিত্রাণ আপনার আর প্রয়োজন নেই.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function (cache) {
      return cache.match(event.request).then(function (response) {
        return (
          response ||
          fetch(event.request).then(function (response) {
            cache.put(event.request, response.clone());
            return response;
          })
        );
      });
    }),
  );
});

দক্ষ মেমরি ব্যবহারের অনুমতি দিতে, আপনি শুধুমাত্র একবার একটি প্রতিক্রিয়া/অনুরোধের অংশ পড়তে পারেন। উপরের কোডটি অতিরিক্ত কপি তৈরি করতে .clone() ব্যবহার করে যা আলাদাভাবে পড়া যায়।

প্রশিক্ষিত-থেকে-থ্রিলে আমি ফ্লিকার ছবি ক্যাশে করতে এটি ব্যবহার করি।

বাসি-যখন-পুনর্বিচার করা

বাসি-যখন-পুনর্বিচার করা।
বাসি-যখন-পুনর্বিচার করা।

এর জন্য আদর্শ: ঘন ঘন রিসোর্স আপডেট করা যেখানে একেবারে সর্বশেষ সংস্করণ থাকা অপ্রয়োজনীয়। অবতাররা এই বিভাগে পড়তে পারে।

যদি একটি ক্যাশে সংস্করণ উপলব্ধ থাকে তবে এটি ব্যবহার করুন, তবে পরবর্তী সময়ের জন্য একটি আপডেট আনুন৷

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function (cache) {
      return cache.match(event.request).then(function (response) {
        var fetchPromise = fetch(event.request).then(function (networkResponse) {
          cache.put(event.request, networkResponse.clone());
          return networkResponse;
        });
        return response || fetchPromise;
      });
    }),
  );
});

এটি HTTP-এর stale-while-revalidate- এর মতোই।

ধাক্কা মেসেজ অন

ধাক্কা মেসেজ অন.
ধাক্কা মেসেজ অন.

Push API হল পরিষেবা কর্মীর উপরে নির্মিত আরেকটি বৈশিষ্ট্য। এটি OS এর মেসেজিং পরিষেবা থেকে একটি বার্তার প্রতিক্রিয়া হিসাবে পরিষেবা কর্মীকে জাগ্রত করার অনুমতি দেয়৷ ব্যবহারকারীর আপনার সাইটে কোনো ট্যাব খোলা না থাকলেও এটি ঘটে। শুধু সেবা কর্মী জেগে আছে। আপনি একটি পৃষ্ঠা থেকে এটি করার অনুমতির অনুরোধ করুন এবং ব্যবহারকারীকে অনুরোধ করা হবে।

এর জন্য আদর্শ: একটি বিজ্ঞপ্তি সম্পর্কিত বিষয়বস্তু, যেমন একটি চ্যাট বার্তা, একটি ব্রেকিং নিউজ স্টোরি বা একটি ইমেল৷ এছাড়াও কদাচিৎ বিষয়বস্তু পরিবর্তন করে যা অবিলম্বে সিঙ্ক থেকে উপকৃত হয়, যেমন একটি করণীয় তালিকা আপডেট বা একটি ক্যালেন্ডার পরিবর্তন।

সাধারণ চূড়ান্ত ফলাফল হল একটি বিজ্ঞপ্তি যা, ট্যাপ করা হলে, একটি প্রাসঙ্গিক পৃষ্ঠা খোলে/ফোকাস করে, কিন্তু যার জন্য এটি হওয়ার আগে ক্যাশে আপডেট করা অত্যন্ত গুরুত্বপূর্ণ। পুশ মেসেজ পাওয়ার সময় ব্যবহারকারী স্পষ্টতই অনলাইনে থাকে, কিন্তু অবশেষে বিজ্ঞপ্তির সাথে ইন্টারঅ্যাক্ট করার সময় তারা নাও থাকতে পারে, তাই এই বিষয়বস্তুটি অফলাইনে উপলব্ধ করা গুরুত্বপূর্ণ।

এই কোডটি একটি বিজ্ঞপ্তি দেখানোর আগে ক্যাশে আপডেট করে:

self.addEventListener('push', function (event) {
  if (event.data.text() == 'new-email') {
    event.waitUntil(
      caches
        .open('mysite-dynamic')
        .then(function (cache) {
          return fetch('/inbox.json').then(function (response) {
            cache.put('/inbox.json', response.clone());
            return response.json();
          });
        })
        .then(function (emails) {
          registration.showNotification('New email', {
            body: 'From ' + emails[0].from.name,
            tag: 'new-email',
          });
        }),
    );
  }
});

self.addEventListener('notificationclick', function (event) {
  if (event.notification.tag == 'new-email') {
    // Assume that all of the resources needed to render
    // /inbox/ have previously been cached, e.g. as part
    // of the install handler.
    new WindowClient('/inbox/');
  }
});

ব্যাকগ্রাউন্ড-সিঙ্কে

ব্যাকগ্রাউন্ড-সিঙ্কে।
ব্যাকগ্রাউন্ড-সিঙ্কে।

ব্যাকগ্রাউন্ড সিঙ্ক হল সার্ভিস ওয়ার্কারের উপরে নির্মিত আরেকটি বৈশিষ্ট্য। এটি আপনাকে ব্যাকগ্রাউন্ড ডেটা সিঙ্ক্রোনাইজেশনকে এক-অফ হিসাবে বা (অত্যন্ত হিউরিস্টিক) ব্যবধানে অনুরোধ করতে দেয়। ব্যবহারকারীর আপনার সাইটে কোনো ট্যাব খোলা না থাকলেও এটি ঘটে। শুধু সেবা কর্মী জেগে আছে। আপনি একটি পৃষ্ঠা থেকে এটি করার অনুমতির অনুরোধ করুন এবং ব্যবহারকারীকে অনুরোধ করা হবে।

এর জন্য আদর্শ: অ-জরুরী আপডেট, বিশেষ করে যেগুলি এত নিয়মিত হয় যে আপডেট প্রতি একটি পুশ বার্তা ব্যবহারকারীদের জন্য খুব ঘন ঘন হবে, যেমন সামাজিক টাইমলাইন বা সংবাদ নিবন্ধ।

self.addEventListener('sync', function (event) {
  if (event.id == 'update-leaderboard') {
    event.waitUntil(
      caches.open('mygame-dynamic').then(function (cache) {
        return cache.add('/leaderboard.json');
      }),
    );
  }
});

ক্যাশে অধ্যবসায়

আপনার মূলকে একটি নির্দিষ্ট পরিমাণ ফাঁকা স্থান দেওয়া হয়েছে যা এটি চায় তা করার জন্য। সেই ফাঁকা স্থানটি সমস্ত মূল সঞ্চয়স্থানের মধ্যে ভাগ করা হয়েছে: (স্থানীয়) স্টোরেজ , ইনডেক্সডডিবি , ফাইল সিস্টেম অ্যাক্সেস এবং অবশ্যই ক্যাশে

আপনি যে পরিমাণ পাবেন তা নির্দিষ্ট নয়। এটি ডিভাইস এবং স্টোরেজ অবস্থার উপর নির্ভর করে ভিন্ন হবে। আপনি এর মাধ্যমে কতটা পেয়েছেন তা জানতে পারেন:

navigator.storageQuota.queryInfo('temporary').then(function (info) {
  console.log(info.quota);
  // Result: <quota in bytes>
  console.log(info.usage);
  // Result: <used data in bytes>
});

যাইহোক, সমস্ত ব্রাউজার স্টোরেজের মতো, ডিভাইসটি স্টোরেজের চাপে থাকলে ব্রাউজারটি আপনার ডেটা ফেলে দিতে পারে। দুর্ভাগ্যবশত ব্রাউজার সেই সিনেমাগুলির মধ্যে পার্থক্য বলতে পারে না যেগুলি আপনি যে কোনও মূল্যে রাখতে চান এবং যে গেমটি আপনি সত্যিই চিন্তা করেন না৷

এটির চারপাশে কাজ করতে, স্টোরেজ ম্যানেজার ইন্টারফেস ব্যবহার করুন:

// From a page:
navigator.storage.persist()
.then(function(persisted) {
  if (persisted) {
    // Hurrah, your data is here to stay!
  } else {
   // So sad, your data may get chucked. Sorry.
});

অবশ্যই, ব্যবহারকারীকে অনুমতি দিতে হবে। এই জন্য, অনুমতি API ব্যবহার করুন.

ব্যবহারকারীদের এই প্রবাহের অংশ করা গুরুত্বপূর্ণ, কারণ আমরা এখন আশা করতে পারি যে তারা মুছে ফেলার নিয়ন্ত্রণে থাকবে। যদি তাদের ডিভাইস স্টোরেজ চাপের মধ্যে আসে, এবং অ-প্রয়োজনীয় ডেটা সাফ করলে এটি সমাধান না হয়, তাহলে ব্যবহারকারী কোন আইটেমগুলি রাখবেন এবং অপসারণ করবেন তা বিচার করতে হবে।

এটি কাজ করার জন্য, ব্রাউজারটিকে একক আইটেম হিসাবে রিপোর্ট করার পরিবর্তে অপারেটিং সিস্টেমগুলিকে প্ল্যাটফর্ম-নির্দিষ্ট অ্যাপগুলির স্টোরেজ ব্যবহারের ভাঙ্গনের সমতুল্য হিসাবে "টেকসই" উত্স হিসাবে বিবেচনা করতে হবে৷

পরামর্শ পরিবেশন করা - অনুরোধের প্রতিক্রিয়া

আপনি কতটা ক্যাশিং করেন তা বিবেচ্য নয়, পরিষেবা কর্মী ক্যাশে ব্যবহার করবেন না যদি না আপনি কখন এবং কীভাবে এটি বলেন। অনুরোধগুলি পরিচালনা করার জন্য এখানে কয়েকটি নিদর্শন রয়েছে:

শুধুমাত্র ক্যাশে

শুধুমাত্র ক্যাশে।
শুধুমাত্র ক্যাশে।

এর জন্য আদর্শ: যেকোন কিছু যা আপনি আপনার সাইটের একটি নির্দিষ্ট "সংস্করণ"-এর জন্য স্ট্যাটিক বিবেচনা করবেন। আপনার ইন্সটল ইভেন্টে এগুলি ক্যাশে করা উচিত ছিল, যাতে আপনি তাদের সেখানে থাকার উপর নির্ভর করতে পারেন।

self.addEventListener('fetch', function (event) {
  // If a match isn't found in the cache, the response
  // will look like a connection error
  event.respondWith(caches.match(event.request));
});

…যদিও আপনার প্রায়শই এই কেসটি বিশেষভাবে পরিচালনা করার প্রয়োজন হয় না, ক্যাশে, নেটওয়ার্কে ফিরে আসা এটিকে কভার করে।

শুধুমাত্র নেটওয়ার্ক

শুধুমাত্র নেটওয়ার্ক।
শুধুমাত্র নেটওয়ার্ক।

এর জন্য আদর্শ: যে জিনিসগুলির কোনও অফলাইন সমতুল্য নেই, যেমন অ্যানালিটিক্স পিংস, নন-GET অনুরোধ৷

self.addEventListener('fetch', function (event) {
  event.respondWith(fetch(event.request));
  // or simply don't call event.respondWith, which
  // will result in default browser behavior
});

…যদিও আপনার প্রায়শই এই কেসটি বিশেষভাবে পরিচালনা করার প্রয়োজন হয় না, ক্যাশে, নেটওয়ার্কে ফিরে আসা এটিকে কভার করে।

ক্যাশে, নেটওয়ার্কে ফিরে আসছে

ক্যাশে, নেটওয়ার্কে ফিরে আসছে।
ক্যাশে, নেটওয়ার্কে ফিরে আসছে।

এর জন্য আদর্শ: অফলাইন-প্রথম নির্মাণ। এই ধরনের ক্ষেত্রে, আপনি এইভাবে বেশিরভাগ অনুরোধগুলি পরিচালনা করবেন। অন্যান্য নিদর্শন আগত অনুরোধের উপর ভিত্তি করে ব্যতিক্রম হবে.

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request).then(function (response) {
      return response || fetch(event.request);
    }),
  );
});

এটি আপনাকে ক্যাশে থাকা জিনিসগুলির জন্য "শুধুমাত্র ক্যাশে" আচরণ এবং ক্যাশে না করা কিছুর জন্য "শুধুমাত্র নেটওয়ার্ক" আচরণ দেয় (যাতে সমস্ত নন-জিইটি অনুরোধ অন্তর্ভুক্ত থাকে, কারণ সেগুলি ক্যাশে করা যায় না)।

ক্যাশে এবং নেটওয়ার্ক রেস

ক্যাশে এবং নেটওয়ার্ক রেস।
ক্যাশে এবং নেটওয়ার্ক রেস।

এর জন্য আদর্শ: ছোট সম্পদ যেখানে আপনি স্লো ডিস্ক অ্যাক্সেস সহ ডিভাইসগুলিতে পারফরম্যান্স অনুসরণ করছেন।

পুরানো হার্ড ড্রাইভ, ভাইরাস স্ক্যানার এবং দ্রুততর ইন্টারনেট সংযোগের কিছু সংমিশ্রণ সহ, নেটওয়ার্ক থেকে সংস্থানগুলি পাওয়া ডিস্কে যাওয়ার চেয়ে দ্রুত হতে পারে। যাইহোক, ব্যবহারকারীর ডিভাইসে সামগ্রী থাকা অবস্থায় নেটওয়ার্কে যাওয়া ডেটার অপচয় হতে পারে, তাই মনে রাখবেন।

// Promise.race is no good to us because it rejects if
// a promise rejects before fulfilling. Let's make a proper
// race function:
function promiseAny(promises) {
  return new Promise((resolve, reject) => {
    // make sure promises are all promises
    promises = promises.map((p) => Promise.resolve(p));
    // resolve this promise as soon as one resolves
    promises.forEach((p) => p.then(resolve));
    // reject if all promises reject
    promises.reduce((a, b) => a.catch(() => b)).catch(() => reject(Error('All failed')));
  });
}

self.addEventListener('fetch', function (event) {
  event.respondWith(promiseAny([caches.match(event.request), fetch(event.request)]));
});

নেটওয়ার্ক ক্যাশে ফিরে পতনশীল

নেটওয়ার্ক ক্যাশে ফিরে পতনশীল.
নেটওয়ার্ক ক্যাশে ফিরে পতনশীল.

এর জন্য আদর্শ: সাইটের "সংস্করণ" এর বাইরে, ঘন ঘন আপডেট হওয়া সংস্থানগুলির জন্য একটি দ্রুত সমাধান৷ যেমন নিবন্ধ, অবতার, সোশ্যাল মিডিয়া টাইমলাইন এবং গেম লিডার বোর্ড।

এর মানে হল আপনি অনলাইন ব্যবহারকারীদের সবচেয়ে আপ-টু-ডেট সামগ্রী দেন, কিন্তু অফলাইন ব্যবহারকারীরা একটি পুরানো ক্যাশে সংস্করণ পান। নেটওয়ার্ক অনুরোধ সফল হলে আপনি সম্ভবত ক্যাশে এন্ট্রি আপডেট করতে চাইবেন।

যাইহোক, এই পদ্ধতির ত্রুটি আছে। যদি ব্যবহারকারীর একটি বিরতিমূলক বা ধীর সংযোগ থাকে তবে তারা তাদের ডিভাইসে ইতিমধ্যেই সম্পূর্ণরূপে গ্রহণযোগ্য সামগ্রী পাওয়ার আগে তাদের নেটওয়ার্ক ব্যর্থ হওয়ার জন্য অপেক্ষা করতে হবে। এটি একটি অত্যন্ত দীর্ঘ সময় নিতে পারে এবং একটি হতাশাজনক ব্যবহারকারীর অভিজ্ঞতা। একটি ভাল সমাধানের জন্য পরবর্তী প্যাটার্ন, ক্যাশে তারপর নেটওয়ার্ক দেখুন।

self.addEventListener('fetch', function (event) {
  event.respondWith(
    fetch(event.request).catch(function () {
      return caches.match(event.request);
    }),
  );
});

ক্যাশে তারপর নেটওয়ার্ক

ক্যাশে তারপর নেটওয়ার্ক।
ক্যাশে তারপর নেটওয়ার্ক।

এর জন্য আদর্শ: ঘন ঘন আপডেট হওয়া সামগ্রী। যেমন নিবন্ধ, সামাজিক মিডিয়া টাইমলাইন, এবং গেম. লিডারবোর্ড

এর জন্য পৃষ্ঠাটিকে দুটি অনুরোধ করতে হবে, একটি ক্যাশে এবং একটি নেটওয়ার্কে৷ ধারণাটি হল প্রথমে ক্যাশে করা ডেটা দেখান, তারপরে নেটওয়ার্ক ডেটা আসার সময় পৃষ্ঠাটি আপডেট করুন।

কখনও কখনও নতুন ডেটা আসার সময় আপনি কেবল বর্তমান ডেটা প্রতিস্থাপন করতে পারেন (যেমন গেম লিডারবোর্ড), তবে এটি সামগ্রীর বড় অংশগুলির সাথে বিঘ্নিত হতে পারে। মূলত, ব্যবহারকারী পড়তে বা ইন্টারঅ্যাক্ট করতে পারে এমন কিছু "অদৃশ্য" করবেন না।

টুইটার পুরানো কন্টেন্টের উপরে নতুন কন্টেন্ট যোগ করে এবং স্ক্রোল পজিশন অ্যাডজাস্ট করে যাতে ব্যবহারকারী নিরবচ্ছিন্ন থাকে। এটি সম্ভব কারণ টুইটার বেশিরভাগ বিষয়বস্তুর একটি রৈখিক ক্রম ধরে রাখে। যত তাড়াতাড়ি সম্ভব স্ক্রীনে সামগ্রী পেতে প্রশিক্ষিত-টু-থ্রিলের জন্য আমি এই প্যাটার্নটি অনুলিপি করেছি, আপ-টু-ডেট সামগ্রী আসার সাথে সাথে প্রদর্শন করার সময়।

পৃষ্ঠায় কোড:

var networkDataReceived = false;

startSpinner();

// fetch fresh data
var networkUpdate = fetch('/data.json')
  .then(function (response) {
    return response.json();
  })
  .then(function (data) {
    networkDataReceived = true;
    updatePage(data);
  });

// fetch cached data
caches
  .match('/data.json')
  .then(function (response) {
    if (!response) throw Error('No data');
    return response.json();
  })
  .then(function (data) {
    // don't overwrite newer network data
    if (!networkDataReceived) {
      updatePage(data);
    }
  })
  .catch(function () {
    // we didn't get cached data, the network is our last hope:
    return networkUpdate;
  })
  .catch(showErrorMessage)
  .then(stopSpinner);

পরিষেবা কর্মীর কোড:

আপনার সর্বদা নেটওয়ার্কে যাওয়া উচিত এবং যাওয়ার সাথে সাথে একটি ক্যাশে আপডেট করা উচিত।

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.open('mysite-dynamic').then(function (cache) {
      return fetch(event.request).then(function (response) {
        cache.put(event.request, response.clone());
        return response;
      });
    }),
  );
});

প্রশিক্ষিত-থেকে-থ্রিলে আমি আনার পরিবর্তে XHR ব্যবহার করে এবং পরিষেবা কর্মীকে কোথা থেকে ফলাফল পেতে হবে তা জানাতে Accept হেডারের অপব্যবহার করে কাজ করেছি ( পৃষ্ঠা কোড , পরিষেবা কর্মী কোড )।

জেনেরিক ফলব্যাক

জেনেরিক ফলব্যাক।
জেনেরিক ফলব্যাক।

আপনি ক্যাশে এবং/অথবা নেটওয়ার্ক থেকে কিছু পরিবেশন করতে ব্যর্থ হলে আপনি একটি জেনেরিক ফলব্যাক প্রদান করতে চাইতে পারেন।

এর জন্য আদর্শ: মাধ্যমিক চিত্র যেমন অবতার, ব্যর্থ POST অনুরোধ এবং একটি "অফলাইনে অনুপলব্ধ"৷ পৃষ্ঠা

self.addEventListener('fetch', function (event) {
  event.respondWith(
    // Try the cache
    caches
      .match(event.request)
      .then(function (response) {
        // Fall back to network
        return response || fetch(event.request);
      })
      .catch(function () {
        // If both fail, show a generic fallback:
        return caches.match('/offline.html');
        // However, in reality you'd have many different
        // fallbacks, depending on URL and headers.
        // Eg, a fallback silhouette image for avatars.
      }),
  );
});

আপনি যে আইটেমটিতে ফ্যালব্যাক করছেন সেটি সম্ভবত একটি ইনস্টল নির্ভরতা

যদি আপনার পৃষ্ঠা একটি ইমেল পোস্ট করে, তাহলে আপনার পরিষেবা কর্মী একটি IndexedDB 'আউটবক্স'-এ ইমেল সংরক্ষণ করতে ফিরে আসতে পারে এবং পৃষ্ঠাটিকে জানাতে পারে যে প্রেরণ ব্যর্থ হয়েছে কিন্তু ডেটা সফলভাবে ধরে রাখা হয়েছে৷

সেবা কর্মী-সাইড টেমপ্লেটিং

সার্ভিসওয়ার্কার-সাইড টেমপ্লেটিং।
সার্ভিসওয়ার্কার-সাইড টেমপ্লেটিং।

এর জন্য আদর্শ: যে পৃষ্ঠাগুলির সার্ভারের প্রতিক্রিয়া ক্যাশে করা যায় না৷

সার্ভারে পৃষ্ঠাগুলি রেন্ডার করা জিনিসগুলিকে দ্রুত করে তোলে , কিন্তু এর অর্থ এমন রাজ্যের ডেটা অন্তর্ভুক্ত করা যেতে পারে যা ক্যাশে অর্থবোধক নাও হতে পারে, যেমন "লগ ইন হয়েছে..."৷ যদি আপনার পৃষ্ঠাটি কোনও পরিষেবা কর্মী দ্বারা নিয়ন্ত্রিত হয়, তবে আপনি পরিবর্তে একটি টেমপ্লেট সহ JSON ডেটার অনুরোধ করতে এবং পরিবর্তে এটি রেন্ডার করতে পারেন৷

importScripts('templating-engine.js');

self.addEventListener('fetch', function (event) {
  var requestURL = new URL(event.request.url);

  event.respondWith(
    Promise.all([
      caches.match('/article-template.html').then(function (response) {
        return response.text();
      }),
      caches.match(requestURL.path + '.json').then(function (response) {
        return response.json();
      }),
    ]).then(function (responses) {
      var template = responses[0];
      var data = responses[1];

      return new Response(renderTemplate(template, data), {
        headers: {
          'Content-Type': 'text/html',
        },
      });
    }),
  );
});

একসাথে রেখে

আপনি এই পদ্ধতিগুলির একটিতে সীমাবদ্ধ নন। আসলে, আপনি সম্ভবত অনুরোধ URL এর উপর নির্ভর করে তাদের অনেকগুলি ব্যবহার করবেন৷ উদাহরণস্বরূপ, প্রশিক্ষিত-থেকে-থ্রিল ব্যবহারগুলি:

শুধু অনুরোধটি দেখুন এবং সিদ্ধান্ত নিন কি করতে হবে:

self.addEventListener('fetch', function (event) {
  // Parse the URL:
  var requestURL = new URL(event.request.url);

  // Handle requests to a particular host specifically
  if (requestURL.hostname == 'api.example.com') {
    event.respondWith(/* some combination of patterns */);
    return;
  }
  // Routing for local URLs
  if (requestURL.origin == location.origin) {
    // Handle article URLs
    if (/^\/article\//.test(requestURL.pathname)) {
      event.respondWith(/* some other combination of patterns */);
      return;
    }
    if (/\.webp$/.test(requestURL.pathname)) {
      event.respondWith(/* some other combination of patterns */);
      return;
    }
    if (request.method == 'POST') {
      event.respondWith(/* some other combination of patterns */);
      return;
    }
    if (/cheese/.test(requestURL.pathname)) {
      event.respondWith(
        new Response('Flagrant cheese error', {
          status: 512,
        }),
      );
      return;
    }
  }

  // A sensible default pattern
  event.respondWith(
    caches.match(event.request).then(function (response) {
      return response || fetch(event.request);
    }),
  );
});

…আপনি ছবি পান।

ক্রেডিট

…সুন্দর আইকনগুলির জন্য:

এবং আমি "প্রকাশ" হিট করার আগে অনেক কান্নাকাটি ত্রুটি ধরার জন্য জেফ পসনিককে ধন্যবাদ।

আরও পড়া