Hướng dẫn trình bày các khái niệm về trình chạy dịch vụ của tiện ích
Tổng quan
Hướng dẫn này giới thiệu về các worker dịch vụ của Tiện ích Chrome. Trong hướng dẫn này, bạn sẽ tạo một tiện ích cho phép người dùng nhanh chóng chuyển đến các trang tham chiếu Chrome API bằng hộp địa chỉ. Bạn sẽ tìm hiểu cách:
- Đăng ký trình chạy dịch vụ và nhập các mô-đun.
- Gỡ lỗi trình thực thi dịch vụ của tiện ích.
- Quản lý trạng thái và xử lý các sự kiện.
- Kích hoạt các sự kiện định kỳ.
- Giao tiếp với tập lệnh nội dung.
Trước khi bắt đầu
Hướng dẫn này giả định rằng bạn đã có kinh nghiệm cơ bản về phát triển web. Bạn nên xem Tiện ích 101 và Hello World để biết thông tin giới thiệu về hoạt động phát triển tiện ích.
Tạo tiện ích
Bắt đầu bằng cách tạo một thư mục mới có tên quick-api-reference
để lưu trữ các tệp tiện ích hoặc tải mã nguồn xuống từ kho lưu trữ các mẫu trên GitHub của chúng tôi.
Bước 1: Đăng ký trình chạy dịch vụ
Tạo tệp manifest trong thư mục gốc của dự án rồi thêm đoạn mã sau:
manifest.json:
{
"manifest_version": 3,
"name": "Open extension API reference",
"version": "1.0.0",
"icons": {
"16": "images/icon-16.png",
"128": "images/icon-128.png"
},
"background": {
"service_worker": "service-worker.js"
}
}
Tiện ích đăng ký trình thực thi dịch vụ trong tệp kê khai, chỉ lấy một tệp JavaScript duy nhất.
Bạn không cần gọi navigator.serviceWorker.register()
như trên trang web.
Tạo thư mục images
rồi tải các biểu tượng xuống thư mục đó.
Hãy xem các bước đầu tiên của hướng dẫn Thời gian đọc để tìm hiểu thêm về siêu dữ liệu và biểu tượng của tiện ích trong tệp kê khai.
Bước 2: Nhập nhiều mô-đun trình chạy dịch vụ
Service worker của chúng tôi triển khai 2 tính năng. Để dễ bảo trì hơn, chúng ta sẽ triển khai từng tính năng trong một mô-đun riêng biệt. Trước tiên, chúng ta cần khai báo worker dịch vụ dưới dạng một ES Module trong tệp kê khai. Việc này cho phép chúng ta nhập các mô-đun trong worker dịch vụ:
manifest.json:
{
"background": {
"service_worker": "service-worker.js",
"type": "module"
},
}
Tạo tệp service-worker.js
và nhập 2 mô-đun:
import './sw-omnibox.js';
import './sw-tips.js';
Tạo các tệp này và thêm nhật ký bảng điều khiển vào từng tệp.
sw-omnibox.js:
console.log("sw-omnibox.js");
sw-tips.js:
console.log("sw-tips.js");
Hãy xem phần Nhập tập lệnh để tìm hiểu về những cách khác để nhập nhiều tệp trong một worker dịch vụ.
Không bắt buộc: Gỡ lỗi trình chạy dịch vụ
Tôi sẽ giải thích cách tìm nhật ký của worker dịch vụ và biết thời điểm nhật ký này đã kết thúc. Trước tiên, hãy làm theo hướng dẫn để Tải một tiện ích chưa đóng gói.
Sau 30 giây, bạn sẽ thấy "service worker (inactive)" (trình chạy dịch vụ (không hoạt động)). Điều này có nghĩa là trình chạy dịch vụ đã kết thúc. Nhấp vào đường liên kết "service worker (inactive)" (trình chạy dịch vụ (không hoạt động)) để kiểm tra. Ảnh động sau đây minh hoạ điều này.
Bạn có nhận thấy rằng việc kiểm tra trình chạy dịch vụ đã kích hoạt trình chạy đó không? Việc mở trình chạy dịch vụ trong công cụ cho nhà phát triển sẽ giữ cho trình chạy dịch vụ hoạt động. Để đảm bảo tiện ích của bạn hoạt động đúng cách khi trình chạy dịch vụ bị chấm dứt, hãy nhớ đóng Công cụ cho nhà phát triển.
Bây giờ, hãy chia nhỏ tiện ích để tìm hiểu vị trí xảy ra lỗi. Một cách để thực hiện việc này là xoá ".js" khỏi nội dung nhập './sw-omnibox.js'
trong tệp service-worker.js
. Chrome sẽ không thể đăng ký trình chạy dịch vụ.
Quay lại trang chrome://extensions rồi làm mới tiện ích. Bạn sẽ thấy 2 lỗi:
Service worker registration failed. Status code: 3.
An unknown error occurred when fetching the script.
Hãy xem phần Gỡ lỗi tiện ích để biết thêm các cách gỡ lỗi worker dịch vụ của tiện ích.
Bước 4: Khởi tạo trạng thái
Chrome sẽ tắt các worker dịch vụ nếu không cần thiết. Chúng tôi sử dụng API chrome.storage
để duy trì trạng thái trong các phiên của worker dịch vụ. Để truy cập vào bộ nhớ, chúng ta cần yêu cầu cấp quyền trong tệp kê khai:
manifest.json:
{
...
"permissions": ["storage"],
}
Trước tiên, hãy lưu các đề xuất mặc định vào bộ nhớ. Chúng ta có thể khởi tạo trạng thái khi tiện ích được cài đặt lần đầu bằng cách theo dõi sự kiện runtime.onInstalled()
:
sw-omnibox.js:
...
// Save default API suggestions
chrome.runtime.onInstalled.addListener(({ reason }) => {
if (reason === 'install') {
chrome.storage.local.set({
apiSuggestions: ['tabs', 'storage', 'scripting']
});
}
});
Các worker dịch vụ không có quyền truy cập trực tiếp vào đối tượng cửa sổ và do đó không thể dùng window.localStorage
để lưu trữ các giá trị. Ngoài ra, các worker dịch vụ là môi trường thực thi ngắn hạn; chúng sẽ bị chấm dứt nhiều lần trong suốt phiên hoạt động của người dùng trên trình duyệt, điều này khiến chúng không tương thích với các biến toàn cục. Thay vào đó, hãy sử dụng chrome.storage.local
để lưu trữ dữ liệu trên máy cục bộ.
Hãy xem phần Duy trì dữ liệu thay vì sử dụng biến chung để tìm hiểu về các lựa chọn lưu trữ khác cho các worker dịch vụ của tiện ích.
Bước 5: Đăng ký sự kiện
Tất cả trình nghe sự kiện đều cần được đăng ký tĩnh trong phạm vi toàn cầu của worker dịch vụ. Nói cách khác, trình nghe sự kiện không được lồng trong các hàm không đồng bộ. Bằng cách này, Chrome có thể đảm bảo rằng tất cả trình xử lý sự kiện đều được khôi phục trong trường hợp khởi động lại worker dịch vụ.
Trong ví dụ này, chúng ta sẽ sử dụng API chrome.omnibox
, nhưng trước tiên, chúng ta phải khai báo trình kích hoạt từ khoá trên hộp đa năng trong tệp kê khai:
manifest.json:
{
...
"minimum_chrome_version": "102",
"omnibox": {
"keyword": "api"
},
}
Bây giờ, hãy đăng ký trình nghe sự kiện hộp đa năng ở cấp cao nhất của tập lệnh. Khi người dùng nhập từ khoá trên thanh địa chỉ (api
) vào thanh địa chỉ, sau đó nhấn phím tab hoặc phím cách, Chrome sẽ hiển thị danh sách các đề xuất dựa trên từ khoá trong bộ nhớ. Sự kiện onInputChanged()
(nhận dữ liệu đầu vào hiện tại của người dùng và một đối tượng suggestResult
) chịu trách nhiệm điền sẵn các đề xuất này.
sw-omnibox.js:
...
const URL_CHROME_EXTENSIONS_DOC =
'https://developer.chrome.com/docs/extensions/reference/';
const NUMBER_OF_PREVIOUS_SEARCHES = 4;
// Display the suggestions after user starts typing
chrome.omnibox.onInputChanged.addListener(async (input, suggest) => {
await chrome.omnibox.setDefaultSuggestion({
description: 'Enter a Chrome API or choose from past searches'
});
const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
const suggestions = apiSuggestions.map((api) => {
return { content: api, description: `Open chrome.${api} API` };
});
suggest(suggestions);
});
Sau khi người dùng chọn một đề xuất, onInputEntered()
sẽ mở trang tham chiếu API tương ứng của Chrome.
sw-omnibox.js:
...
// Open the reference page of the chosen API
chrome.omnibox.onInputEntered.addListener((input) => {
chrome.tabs.create({ url: URL_CHROME_EXTENSIONS_DOC + input });
// Save the latest keyword
updateHistory(input);
});
Hàm updateHistory()
lấy dữ liệu đầu vào của hộp đa năng và lưu dữ liệu đó vào storage.local
. Bằng cách này, cụm từ tìm kiếm gần đây nhất có thể được dùng sau này làm đề xuất trên thanh địa chỉ.
sw-omnibox.js:
...
async function updateHistory(input) {
const { apiSuggestions } = await chrome.storage.local.get('apiSuggestions');
apiSuggestions.unshift(input);
apiSuggestions.splice(NUMBER_OF_PREVIOUS_SEARCHES);
return chrome.storage.local.set({ apiSuggestions });
}
Bước 6: Thiết lập sự kiện định kỳ
Các phương thức setTimeout()
hoặc setInterval()
thường được dùng để thực hiện các tác vụ định kỳ hoặc bị trì hoãn. Tuy nhiên, các API này có thể không hoạt động vì trình lập lịch sẽ huỷ các bộ hẹn giờ khi trình thực thi dịch vụ bị chấm dứt. Thay vào đó, các tiện ích có thể sử dụng API chrome.alarms
.
Bắt đầu bằng cách yêu cầu quyền "alarms"
trong tệp kê khai:
manifest.json:
{
...
"permissions": ["storage"],
"permissions": ["storage", "alarms"],
}
Tiện ích này sẽ tìm nạp tất cả các mẹo, chọn ngẫu nhiên một mẹo và lưu vào bộ nhớ. Chúng tôi sẽ tạo một chuông báo được kích hoạt mỗi ngày một lần để cập nhật mẹo. Chuông báo sẽ không được lưu khi bạn đóng Chrome. Vì vậy, chúng ta cần kiểm tra xem chuông báo có tồn tại hay không và tạo chuông báo nếu chưa có.
sw-tips.js:
// Fetch tip & save in storage
const updateTip = async () => {
const response = await fetch('https://chrome.dev/f/extension_tips/');
const tips = await response.json();
const randomIndex = Math.floor(Math.random() * tips.length);
return chrome.storage.local.set({ tip: tips[randomIndex] });
};
const ALARM_NAME = 'tip';
// Check if alarm exists to avoid resetting the timer.
// The alarm might be removed when the browser session restarts.
async function createAlarm() {
const alarm = await chrome.alarms.get(ALARM_NAME);
if (typeof alarm === 'undefined') {
chrome.alarms.create(ALARM_NAME, {
delayInMinutes: 1,
periodInMinutes: 1440
});
updateTip();
}
}
createAlarm();
// Update tip once a day
chrome.alarms.onAlarm.addListener(updateTip);
Bước 7: Tương tác với các ngữ cảnh khác
Tiện ích sử dụng tập lệnh nội dung để đọc và sửa đổi nội dung của trang. Khi người dùng truy cập vào trang tham chiếu Chrome API, tập lệnh nội dung của tiện ích sẽ cập nhật trang bằng mẹo trong ngày. Thao tác này sẽ gửi một thông báo để yêu cầu thông tin hữu ích trong ngày từ worker dịch vụ.
Bắt đầu bằng cách khai báo tập lệnh nội dung trong tệp kê khai và thêm mẫu so khớp tương ứng với tài liệu tham khảo Chrome API.
manifest.json:
{
...
"content_scripts": [
{
"matches": ["https://developer.chrome.com/docs/extensions/reference/*"],
"js": ["content.js"]
}
]
}
Tạo một tệp nội dung mới. Đoạn mã sau đây gửi một thông báo đến service worker để yêu cầu tiền boa. Sau đó, thêm một nút sẽ mở một cửa sổ bật lên chứa mẹo về tiện ích. Mã này sử dụng API Cửa sổ bật lên của nền tảng web mới.
content.js:
(async () => {
// Sends a message to the service worker and receives a tip in response
const { tip } = await chrome.runtime.sendMessage({ greeting: 'tip' });
const nav = document.querySelector('.upper-tabs > nav');
const tipWidget = createDomElement(`
<button type="button" popovertarget="tip-popover" popovertargetaction="show" style="padding: 0 12px; height: 36px;">
<span style="display: block; font: var(--devsite-link-font,500 14px/20px var(--devsite-primary-font-family));">Tip</span>
</button>
`);
const popover = createDomElement(
`<div id='tip-popover' popover style="margin: auto;">${tip}</div>`
);
document.body.append(popover);
nav.append(tipWidget);
})();
function createDomElement(html) {
const dom = new DOMParser().parseFromString(html, 'text/html');
return dom.body.firstElementChild;
}
Bước cuối cùng là thêm một trình xử lý thông báo vào service worker để gửi câu trả lời cho tập lệnh nội dung kèm theo mẹo hằng ngày.
sw-tips.js:
...
// Send tip to content script via messaging
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.greeting === 'tip') {
chrome.storage.local.get('tip').then(sendResponse);
return true;
}
});
Kiểm tra để đảm bảo tính năng này hoạt động
Xác minh rằng cấu trúc tệp của dự án trông như sau:
Tải tiện ích của bạn xuống máy
Để tải một tiện ích chưa đóng gói ở chế độ nhà phát triển, hãy làm theo các bước trong phần Hello world.
Mở trang thông tin tham khảo
- Nhập từ khoá "api" vào thanh địa chỉ của trình duyệt.
- Nhấn phím "tab" hoặc "space".
- Nhập tên đầy đủ của API.
- HOẶC chọn trong danh sách các nội dung tìm kiếm trước đây
- Một trang mới sẽ mở ra, chuyển đến trang tham chiếu API của Chrome.
Ứng dụng sẽ hiển thị như sau:

Mở mẹo hay trong ngày
Nhấp vào nút Mẹo trên thanh điều hướng để mở mẹo về tiện ích.

🎯 Các điểm có thể cải thiện
Dựa trên những gì bạn đã học được hôm nay, hãy thử thực hiện một trong những việc sau:
- Khám phá một cách khác để triển khai các đề xuất trên thanh địa chỉ.
- Tạo phương thức tuỳ chỉnh của riêng bạn để hiển thị mẹo về tiện ích.
- Mở một trang bổ sung cho các trang API tham chiếu Tiện ích trên web của MDN.
Hãy tiếp tục xây dựng!
Chúc mừng bạn đã hoàn thành hướng dẫn này 🎉. Hãy tiếp tục nâng cao kỹ năng bằng cách hoàn thành các hướng dẫn khác dành cho người mới bắt đầu:
Phần mở rộng | Kiến thức bạn sẽ học được |
---|---|
Thời gian đọc | Để tự động chèn một phần tử vào một nhóm trang cụ thể. |
Trình quản lý thẻ | Cách tạo một cửa sổ bật lên để quản lý các thẻ trình duyệt. |
Chế độ tập trung | Để chạy mã trên trang hiện tại sau khi nhấp vào thao tác của tiện ích. |
Tiếp tục khám phá
Để tiếp tục tìm hiểu về service worker của tiện ích, bạn nên khám phá các bài viết sau: