Многие приложения предоставляют один и тот же контент всем пользователям при первой загрузке страницы. Например, новостной сайт может показывать последние новости, а сайт электронной коммерции может показывать самые продаваемые товары.
Если этот контент обслуживается из Cloud Firestore , каждый пользователь будет выдавать новый запрос с теми же результатами при загрузке приложения. Поскольку эти результаты не кэшируются между пользователями, приложение работает медленнее и дороже, чем должно быть.
Решение: Пакеты
Пакеты Cloud Firestore позволяют собирать пакеты данных из общих результатов запросов на серверной стороне с помощью Firebase Admin SDK и обслуживать эти предварительно вычисленные BLOB-объекты, кэшированные в CDN. Это дает вашим пользователям гораздо более быструю первую загрузку и снижает затраты на запросы Cloud Firestore .
В этом руководстве мы будем использовать Cloud Functions для создания пакетов и Firebase Hosting для динамического кэширования и обслуживания содержимого пакетов. Подробнее о пакетах можно узнать в гайдах .
Сначала создайте простую общедоступную HTTP-функцию для запроса 50 последних «историй» и предоставления результата в виде пакета.
exports.createBundle = functions.https.onRequest(async (request, response) => { // Query the 50 latest stories const latestStories = await db.collection('stories') .orderBy('timestamp', 'desc') .limit(50) .get(); // Build the bundle from the query results const bundleBuffer = db.bundle('latest-stories') .add('latest-stories-query', latestStories) .build(); // Cache the response for up to 5 minutes; // see https://firebase.google.com/docs/hosting/manage-cache response.set('Cache-Control', 'public, max-age=300, s-maxage=600'); response.end(bundleBuffer); });
package com.example; import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.firestore.Firestore; import com.google.cloud.firestore.FirestoreBundle; import com.google.cloud.firestore.Query.Direction; import com.google.cloud.firestore.QuerySnapshot; import com.google.cloud.functions.HttpFunction; import com.google.cloud.functions.HttpRequest; import com.google.cloud.functions.HttpResponse; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.cloud.FirestoreClient; import java.io.BufferedWriter; import java.io.IOException; public class ExampleFunction implements HttpFunction { public static FirebaseApp initializeFirebase() throws IOException { if (FirebaseApp.getApps().isEmpty()) { FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.getApplicationDefault()) .setProjectId("YOUR-PROJECT-ID") .build(); FirebaseApp.initializeApp(options); } return FirebaseApp.getInstance(); } @Override public void service(HttpRequest request, HttpResponse response) throws Exception { // Get a Firestore instance FirebaseApp app = initializeFirebase(); Firestore db = FirestoreClient.getFirestore(app); // Query the 50 latest stories QuerySnapshot latestStories = db.collection("stories") .orderBy("timestamp", Direction.DESCENDING) .limit(50) .get() .get(); // Build the bundle from the query results FirestoreBundle bundle = db.bundleBuilder("latest-stores") .add("latest-stories-query", latestStories) .build(); // Cache the response for up to 5 minutes // see https://firebase.google.com/docs/hosting/manage-cache response.appendHeader("Cache-Control", "public, max-age=300, s-maxage=600"); // Write the bundle to the HTTP response BufferedWriter writer = response.getWriter(); writer.write(new String(bundle.toByteBuffer().array())); } }
Затем настройте хостинг Firebase для обслуживания и кэширования этой облачной функции, изменив firebase.json
. В этой конфигурации CDN Firebase Hosting будет обслуживать содержимое пакета в соответствии с настройками кэша, установленными функцией облака. Когда срок действия кеша истечет, он обновит содержимое, снова запустив функцию.
firebase.json
{
"hosting": {
// ...
"rewrites": [{
"source": "/createBundle",
"function": "createBundle"
}]
},
// ...
}
Наконец, в своем веб-приложении извлеките связанный контент из CDN и загрузите его в Firestore SDK.
// If you are using module bundlers.
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/firestore/bundle" // This line enables bundle loading as a side effect.
async function fetchFromBundle() {
// Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache'
// response header will be set to 'HIT'
const resp = await fetch('/createBundle');
// Load the bundle contents into the Firestore SDK
await db.loadBundle(resp.body);
// Query the results from the cache
// Note: omitting "source: cache" will query the Firestore backend.
const query = await db.namedQuery('latest-stories-query');
const storiesSnap = await query.get({ source: 'cache' });
// Use the results
// ...
}
Предполагаемая экономия
Рассмотрим новостной веб-сайт, который посещают 100 000 пользователей в день, и каждый пользователь загружает одни и те же 50 главных новостей при начальной загрузке. Без какого-либо кэширования это привело бы к 50 x 100 000 = 5 000 000 чтений документов в день из Cloud Firestore .
Теперь предположим, что сайт использует описанную выше технику и кэширует эти 50 результатов на срок до 5 минут. Таким образом, вместо загрузки результатов запроса для каждого пользователя результаты загружаются ровно 12 раз в час. Независимо от того, сколько пользователей зайдет на сайт, количество запросов к Cloud Firestore останется прежним. Вместо 5 000 000 прочтений документов на этой странице будет использоваться 12 x 24 x 50 = 14 400 прочтений документов в день. Небольшие дополнительные затраты на хостинг Firebase и Cloud Functions легко компенсируются экономией средств на Cloud Firestore .
Хотя разработчик выигрывает от экономии средств, наибольший выигрыш получает пользователь. Загрузка этих 50 документов из CDN хостинга Firebase, а не напрямую из Cloud Firestore может легко сократить время загрузки контента страницы на 100–200 мс или более. Исследования неоднократно показывали, что более быстрые страницы означают более счастливых пользователей.
,Многие приложения предоставляют один и тот же контент всем пользователям при первой загрузке страницы. Например, новостной сайт может показывать последние новости, а сайт электронной коммерции может показывать самые продаваемые товары.
Если этот контент предоставляется из Cloud Firestore , каждый пользователь будет выдавать новый запрос с теми же результатами при загрузке приложения. Поскольку эти результаты не кэшируются между пользователями, приложение работает медленнее и дороже, чем должно быть.
Решение: Пакеты
Пакеты Cloud Firestore позволяют собирать пакеты данных из общих результатов запросов на серверной стороне с помощью Firebase Admin SDK и обслуживать эти предварительно вычисленные BLOB-объекты, кэшированные в CDN. Это дает вашим пользователям гораздо более быструю первую загрузку и снижает затраты на запросы Cloud Firestore .
В этом руководстве мы будем использовать Cloud Functions для создания пакетов и Firebase Hosting для динамического кэширования и обслуживания содержимого пакетов. Подробнее о пакетах можно узнать в гайдах .
Сначала создайте простую общедоступную HTTP-функцию для запроса 50 последних «историй» и предоставления результата в виде пакета.
exports.createBundle = functions.https.onRequest(async (request, response) => { // Query the 50 latest stories const latestStories = await db.collection('stories') .orderBy('timestamp', 'desc') .limit(50) .get(); // Build the bundle from the query results const bundleBuffer = db.bundle('latest-stories') .add('latest-stories-query', latestStories) .build(); // Cache the response for up to 5 minutes; // see https://firebase.google.com/docs/hosting/manage-cache response.set('Cache-Control', 'public, max-age=300, s-maxage=600'); response.end(bundleBuffer); });
package com.example; import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.firestore.Firestore; import com.google.cloud.firestore.FirestoreBundle; import com.google.cloud.firestore.Query.Direction; import com.google.cloud.firestore.QuerySnapshot; import com.google.cloud.functions.HttpFunction; import com.google.cloud.functions.HttpRequest; import com.google.cloud.functions.HttpResponse; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.cloud.FirestoreClient; import java.io.BufferedWriter; import java.io.IOException; public class ExampleFunction implements HttpFunction { public static FirebaseApp initializeFirebase() throws IOException { if (FirebaseApp.getApps().isEmpty()) { FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.getApplicationDefault()) .setProjectId("YOUR-PROJECT-ID") .build(); FirebaseApp.initializeApp(options); } return FirebaseApp.getInstance(); } @Override public void service(HttpRequest request, HttpResponse response) throws Exception { // Get a Firestore instance FirebaseApp app = initializeFirebase(); Firestore db = FirestoreClient.getFirestore(app); // Query the 50 latest stories QuerySnapshot latestStories = db.collection("stories") .orderBy("timestamp", Direction.DESCENDING) .limit(50) .get() .get(); // Build the bundle from the query results FirestoreBundle bundle = db.bundleBuilder("latest-stores") .add("latest-stories-query", latestStories) .build(); // Cache the response for up to 5 minutes // see https://firebase.google.com/docs/hosting/manage-cache response.appendHeader("Cache-Control", "public, max-age=300, s-maxage=600"); // Write the bundle to the HTTP response BufferedWriter writer = response.getWriter(); writer.write(new String(bundle.toByteBuffer().array())); } }
Затем настройте хостинг Firebase для обслуживания и кэширования этой облачной функции, изменив firebase.json
. В этой конфигурации CDN Firebase Hosting будет обслуживать содержимое пакета в соответствии с настройками кэша, установленными функцией облака. Когда срок действия кеша истечет, он обновит содержимое, снова запустив функцию.
firebase.json
{
"hosting": {
// ...
"rewrites": [{
"source": "/createBundle",
"function": "createBundle"
}]
},
// ...
}
Наконец, в своем веб-приложении извлеките связанный контент из CDN и загрузите его в Firestore SDK.
// If you are using module bundlers.
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/firestore/bundle" // This line enables bundle loading as a side effect.
async function fetchFromBundle() {
// Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache'
// response header will be set to 'HIT'
const resp = await fetch('/createBundle');
// Load the bundle contents into the Firestore SDK
await db.loadBundle(resp.body);
// Query the results from the cache
// Note: omitting "source: cache" will query the Firestore backend.
const query = await db.namedQuery('latest-stories-query');
const storiesSnap = await query.get({ source: 'cache' });
// Use the results
// ...
}
Предполагаемая экономия
Рассмотрим новостной веб-сайт, который посещают 100 000 пользователей в день, и каждый пользователь загружает одни и те же 50 главных новостей при начальной загрузке. Без какого-либо кэширования это привело бы к 50 x 100 000 = 5 000 000 чтений документов в день из Cloud Firestore .
Теперь предположим, что сайт использует описанную выше технику и кэширует эти 50 результатов на срок до 5 минут. Таким образом, вместо загрузки результатов запроса для каждого пользователя результаты загружаются ровно 12 раз в час. Независимо от того, сколько пользователей зайдет на сайт, количество запросов к Cloud Firestore останется прежним. Вместо 5 000 000 прочтений документов на этой странице будет использоваться 12 x 24 x 50 = 14 400 прочтений документов в день. Небольшие дополнительные затраты на хостинг Firebase и Cloud Functions легко компенсируются экономией средств на Cloud Firestore .
Хотя разработчик выигрывает от экономии средств, наибольший выигрыш получает пользователь. Загрузка этих 50 документов из CDN хостинга Firebase, а не напрямую из Cloud Firestore может легко сократить время загрузки контента страницы на 100–200 мс или более. Исследования неоднократно показывали, что более быстрые страницы означают более счастливых пользователей.
,Многие приложения предоставляют один и тот же контент всем пользователям при первой загрузке страницы. Например, новостной сайт может показывать последние новости, а сайт электронной коммерции может показывать самые продаваемые товары.
Если этот контент предоставляется из Cloud Firestore , каждый пользователь будет выдавать новый запрос с теми же результатами при загрузке приложения. Поскольку эти результаты не кэшируются между пользователями, приложение работает медленнее и дороже, чем должно быть.
Решение: Пакеты
Пакеты Cloud Firestore позволяют собирать пакеты данных из общих результатов запросов на серверной стороне с помощью Firebase Admin SDK и обслуживать эти предварительно вычисленные BLOB-объекты, кэшированные в CDN. Это дает вашим пользователям гораздо более быструю первую загрузку и снижает затраты на запросы Cloud Firestore .
В этом руководстве мы будем использовать Cloud Functions для создания пакетов и Firebase Hosting для динамического кэширования и обслуживания содержимого пакетов. Подробнее о пакетах можно узнать в гайдах .
Сначала создайте простую общедоступную HTTP-функцию для запроса 50 последних «историй» и предоставления результата в виде пакета.
exports.createBundle = functions.https.onRequest(async (request, response) => { // Query the 50 latest stories const latestStories = await db.collection('stories') .orderBy('timestamp', 'desc') .limit(50) .get(); // Build the bundle from the query results const bundleBuffer = db.bundle('latest-stories') .add('latest-stories-query', latestStories) .build(); // Cache the response for up to 5 minutes; // see https://firebase.google.com/docs/hosting/manage-cache response.set('Cache-Control', 'public, max-age=300, s-maxage=600'); response.end(bundleBuffer); });
package com.example; import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.firestore.Firestore; import com.google.cloud.firestore.FirestoreBundle; import com.google.cloud.firestore.Query.Direction; import com.google.cloud.firestore.QuerySnapshot; import com.google.cloud.functions.HttpFunction; import com.google.cloud.functions.HttpRequest; import com.google.cloud.functions.HttpResponse; import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.cloud.FirestoreClient; import java.io.BufferedWriter; import java.io.IOException; public class ExampleFunction implements HttpFunction { public static FirebaseApp initializeFirebase() throws IOException { if (FirebaseApp.getApps().isEmpty()) { FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.getApplicationDefault()) .setProjectId("YOUR-PROJECT-ID") .build(); FirebaseApp.initializeApp(options); } return FirebaseApp.getInstance(); } @Override public void service(HttpRequest request, HttpResponse response) throws Exception { // Get a Firestore instance FirebaseApp app = initializeFirebase(); Firestore db = FirestoreClient.getFirestore(app); // Query the 50 latest stories QuerySnapshot latestStories = db.collection("stories") .orderBy("timestamp", Direction.DESCENDING) .limit(50) .get() .get(); // Build the bundle from the query results FirestoreBundle bundle = db.bundleBuilder("latest-stores") .add("latest-stories-query", latestStories) .build(); // Cache the response for up to 5 minutes // see https://firebase.google.com/docs/hosting/manage-cache response.appendHeader("Cache-Control", "public, max-age=300, s-maxage=600"); // Write the bundle to the HTTP response BufferedWriter writer = response.getWriter(); writer.write(new String(bundle.toByteBuffer().array())); } }
Затем настройте хостинг Firebase для обслуживания и кэширования этой облачной функции, изменив firebase.json
. В этой конфигурации CDN Firebase Hosting будет обслуживать содержимое пакета в соответствии с настройками кэша, установленными функцией облака. Когда срок действия кэша истечет, он обновит содержимое, снова запустив функцию.
firebase.json
{
"hosting": {
// ...
"rewrites": [{
"source": "/createBundle",
"function": "createBundle"
}]
},
// ...
}
Наконец, в своем веб-приложении извлеките связанный контент из CDN и загрузите его в Firestore SDK.
// If you are using module bundlers.
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/firestore/bundle" // This line enables bundle loading as a side effect.
async function fetchFromBundle() {
// Fetch the bundle from Firebase Hosting, if the CDN cache is hit the 'X-Cache'
// response header will be set to 'HIT'
const resp = await fetch('/createBundle');
// Load the bundle contents into the Firestore SDK
await db.loadBundle(resp.body);
// Query the results from the cache
// Note: omitting "source: cache" will query the Firestore backend.
const query = await db.namedQuery('latest-stories-query');
const storiesSnap = await query.get({ source: 'cache' });
// Use the results
// ...
}
Предполагаемая экономия
Рассмотрим новостной веб-сайт, который посещают 100 000 пользователей в день, и каждый пользователь загружает одни и те же 50 главных новостей при начальной загрузке. Без какого-либо кэширования это привело бы к 50 x 100 000 = 5 000 000 чтений документов в день из Cloud Firestore .
Теперь предположим, что сайт использует описанную выше технику и кэширует эти 50 результатов на срок до 5 минут. Таким образом, вместо загрузки результатов запроса для каждого пользователя результаты загружаются ровно 12 раз в час. Независимо от того, сколько пользователей зайдет на сайт, количество запросов к Cloud Firestore останется прежним. Вместо 5 000 000 прочтений документов на этой странице будет использоваться 12 x 24 x 50 = 14 400 прочтений документов в день. Небольшие дополнительные затраты на хостинг Firebase и Cloud Functions легко компенсируются экономией средств на Cloud Firestore .
Хотя разработчик выигрывает от экономии средств, наибольший выигрыш получает пользователь. Загрузка этих 50 документов из CDN хостинга Firebase, а не напрямую из Cloud Firestore может легко сократить время загрузки контента страницы на 100–200 мс или более. Исследования неоднократно показывали, что более быстрые страницы означают более счастливых пользователей.