すべての静的リソースをキャッシュするオフラインアプリがあります。現在、ビデオアセットの最初の15秒のみがキャッシュされます。
以下に、install
およびfetch
イベントリスナーの基本的な実装を示します。
Service Worker:
self.addEventListener('install', event => {
event.waitUntil(
caches.open('v1').then(cache => {
return cache.addAll([
'/',
'/videos/one.mp4',
'/videos/two.mp4'
]);
})
);
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
if (response) return response;
return fetch(event.request);
});
);
});
そしてindex.html
<video controls preload>
<source src="/videos/one.mp4" type="video/mp4">
</video>
次の手順を使用して、最初にビデオ全体を視聴せずに、最初のページの読み込みでオフラインビデオを実現しました。
'/'
この場合。 Service Workerのfetch
イベントを調べると、後続のリクエストもキャッシュされていることがわかります。fetch
APIを使用して、blob
として動画をリクエストします。フェッチを使用して動画をblobとしてリクエストする例
const videoRequest = fetch('/path/to/video.mp4').then(response => response.blob());
videoRequest.then(blob => {
...
});
IndexedDB
APIを使用してblob
を保存します。 (保存中にメインスレッドがブロックされないようにするには、IndexedDB
ではなくLocalStorage
を使用してください。)それでおしまい!これで、オフラインモードのときに、Service Workerはリクエストをインターセプトし、html
とblob
の両方をキャッシュから提供します。
index.html
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Service Worker Test</h1>
<p>Try reloading the page without an Internet connection.</p>
<video controls></video>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}).catch(error => {
console.log('ServiceWorker registration failed: ', error);
});
});
} else {
alert('serviceWorker is not in navigator');
}
</script>
<script>
const videos = {
one: document.querySelector('video')
};
const videoRequest = fetch('/path/to/video.mp4').then(response => response.blob());
videoRequest.then(blob => {
const request = indexedDB.open('databaseNameHere', 1);
request.onsuccess = event => {
const db = event.target.result;
const transaction = db.transaction(['videos']);
const objectStore = transaction.objectStore('videos');
const test = objectStore.get('test');
test.onerror = event => {
console.log('error');
};
test.onsuccess = event => {
videos.one.src = window.URL.createObjectURL(test.result.blob);
};
}
request.onupgradeneeded = event => {
const db = event.target.result;
const objectStore = db.createObjectStore('videos', { keyPath: 'name' });
objectStore.transaction.oncomplete = event => {
const videoObjectStore = db.transaction('videos', 'readwrite').objectStore('videos');
videoObjectStore.add({name: 'test', blob: blob});
};
}
});
</script>
</body>
</html>
Service Worker
const latest = {
cache: 'some-cache-name/v1'
};
self.addEventListener('install', event => {
event.waitUntil(
caches.open(latest.cache).then(cache => {
return cache.addAll([
'/'
]);
})
);
});
self.addEventListener('fetch', event => {
// exclude requests that start with chrome-extension://
if (event.request.url.startsWith('chrome-extension://')) return;
event.respondWith(
caches.open(latest.cache).then(cache => {
return cache.match(event.request).then(response => {
var fetchPromise = fetch(event.request).then(networkResponse => {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
return response || fetchPromise;
})
})
);
});
self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.filter(cacheName => {
if (cacheName === latest.cache) {
return false;
}
return true;
}).map(cacheName => {
return caches.delete(cacheName)
})
);
})
);
});
リソース: