Попытка предостеречься от caches (ИИ)
Ano Mr Site / Build and deploy (push) Successful in 9s
Details
Ano Mr Site / Build and deploy (push) Successful in 9s
Details
This commit is contained in:
parent
48f8000258
commit
1a67b16153
|
|
@ -10,6 +10,17 @@ const db_get_filepath = '../db_get.php'
|
|||
/** Дефолтный срок годности кэша : 2 часа */
|
||||
const CACHE_DEFAULT_TTL_MS = 2 * 60 * 60 * 1000;
|
||||
|
||||
/**
|
||||
* Получить объект кэша, если поддерживается Cache API
|
||||
* @returns {Promise<Cache|null>}
|
||||
*/
|
||||
async function getCache() {
|
||||
if (typeof caches !== 'undefined') {
|
||||
return await caches.open('cache');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Излечь данные из ответа
|
||||
* @param {string} type - тип извлекаемых данных
|
||||
|
|
@ -19,13 +30,13 @@ const CACHE_DEFAULT_TTL_MS = 2 * 60 * 60 * 1000;
|
|||
const extract_file = recovery(async (type, response) => {
|
||||
switch(type) {
|
||||
case 'file':
|
||||
return await response.blob()
|
||||
return await response.blob();
|
||||
case 'json':
|
||||
return await response.json()
|
||||
return await response.json();
|
||||
default:
|
||||
throw new Error('Не определен type')
|
||||
throw new Error('Не определен type');
|
||||
}
|
||||
}, (...e) => {throw Error(`Ошибки при извлечении (extract_file): ${e.join(', ')}`)} )
|
||||
}, (...e) => {throw Error(`Ошибки при извлечении (extract_file): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* @param {string} path - путь (либо локальный или https)
|
||||
|
|
@ -33,50 +44,46 @@ const extract_file = recovery(async (type, response) => {
|
|||
* @param {int} timeout - секундомер
|
||||
*/
|
||||
const fetch_with_timeout = recovery(async (path, options = {}, timeout = 10 * 1000) => {
|
||||
/** Штука для преждевременного завершения fetch */
|
||||
const controller = new AbortController()
|
||||
/** Как я понял, якорь для fetch */
|
||||
const signal = controller.signal
|
||||
const controller = new AbortController();
|
||||
const signal = controller.signal;
|
||||
|
||||
/** Сработает завершение после истечения timeout */
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout)
|
||||
/** Запрос с привязкой якоря */
|
||||
const response = await fetch(path, {...options, signal})
|
||||
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
||||
const response = await fetch(path, {...options, signal});
|
||||
|
||||
try {return response}
|
||||
finally {clearTimeout(timeoutId)}
|
||||
try { return response; }
|
||||
finally { clearTimeout(timeoutId); }
|
||||
}, (e) => {
|
||||
if(e.name === 'AbortError')
|
||||
console.log('Запрос прерван по таймауту:', e)
|
||||
else console.log(e)
|
||||
}, (...e) => {throw Error(`Ошибки при запросе с таймером (fetch_with_timeout): ${e.join(', ')}`)} )
|
||||
console.log('Запрос прерван по таймауту:', e);
|
||||
else console.log(e);
|
||||
}, (...e) => {throw Error(`Ошибки при запросе с таймером (fetch_with_timeout): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Вернуть данные из ответа, кэшируя перед этим
|
||||
* Вернуть данные из ответа, кэшируя перед этим (если Cache API есть)
|
||||
* @param {string} type - тип извлекаемых данных
|
||||
* @param {string} path - путь (либо локальный или https)
|
||||
* @param {string} cache_key - ключ кэша
|
||||
* @param {Object} body_req - тело запроса
|
||||
* @returns {Promise<Object|Blob>}
|
||||
*/
|
||||
const return_fetch = recovery(async (type, path, cache_key, body_req) => {
|
||||
const cache = await caches.open('cache')
|
||||
const cache = await getCache();
|
||||
|
||||
/** Запрос по пути (если есть тело, то локальное обращение к файлу) */
|
||||
const response = !body_req ? await fetch_with_timeout(path) : await fetch_with_timeout(path, {
|
||||
const response = !body_req
|
||||
? await fetch_with_timeout(path)
|
||||
: await fetch_with_timeout(path, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json'},
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(body_req)
|
||||
})
|
||||
});
|
||||
|
||||
/** Клонирование, т.к blob/json необратимый процесс. */
|
||||
const cloned = response.clone()
|
||||
const blob = await cloned.blob()
|
||||
if (cache) {
|
||||
const cloned = response.clone();
|
||||
const blob = await cloned.blob();
|
||||
|
||||
const headers = new Headers(cloned.headers)
|
||||
/** Добавление даты создания в заголовок 'date' кешируемого ответа. */
|
||||
headers.set('date', new Date().toUTCString())
|
||||
const headers = new Headers(cloned.headers);
|
||||
headers.set('date', new Date().toUTCString());
|
||||
|
||||
/** Процесс кэширования */
|
||||
await cache.put(
|
||||
cache_key,
|
||||
new Response(blob, {
|
||||
|
|
@ -84,46 +91,41 @@ const return_fetch = recovery(async (type, path, cache_key, body_req) => {
|
|||
statusText: cloned.statusText,
|
||||
headers
|
||||
})
|
||||
)
|
||||
|
||||
/** Возвращаем оригинальный (первый) ответ */
|
||||
return await extract_file(type, response)
|
||||
}, (...e) => {throw Error(`Ошибки при запросе и кэшировании (return_fetch): ${e.join(', ')}`)} )
|
||||
);
|
||||
}
|
||||
return await extract_file(type, response);
|
||||
}, (...e) => {throw Error(`Ошибки при запросе и кэшировании (return_fetch): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Получить данные из пути(локальный или https)
|
||||
* @param {*} type - тип извлекаемых данных
|
||||
* @param {*} path - путь (либо локальный или https)
|
||||
* @param {*} body_req - тело запроса
|
||||
* Получить данные из пути (локальный или https), с поддержкой кэша, если он есть
|
||||
* @param {string} type - тип извлекаемых данных
|
||||
* @param {string} path - путь (либо локальный или https)
|
||||
* @param {Object|null} body_req - тело запроса
|
||||
* @returns {Promise<Object|Blob>}
|
||||
*/
|
||||
const get = recovery(async (type, path, body_req = null) => {
|
||||
const cache = await caches.open('cache')
|
||||
const cache = await getCache();
|
||||
|
||||
/** Ключ для добавления или получения кэш-данных. */
|
||||
const cache_key = `${path}?type=${type}&file=${encodeURIComponent(JSON.stringify(body_req || {}))}`
|
||||
const cache_key = `${path}?type=${type}&file=${encodeURIComponent(JSON.stringify(body_req || {}))}`;
|
||||
|
||||
/** Результат поиска ответа в кэше */
|
||||
const cached_response = await cache.match(cache_key)
|
||||
if (cache) {
|
||||
const cached_response = await cache.match(cache_key);
|
||||
|
||||
if (cached_response) {
|
||||
/** Срок годности кэша (если задан) */
|
||||
const expires_value = cached_response.headers.get('expires')
|
||||
/** Дата создания кэша */
|
||||
const date_value = cached_response.headers.get('date')
|
||||
/** До какого числа годен */
|
||||
const expires_value = cached_response.headers.get('expires');
|
||||
const date_value = cached_response.headers.get('date');
|
||||
const exp = expires_value && expires_value !== '-1'
|
||||
? Date.parse(expires_value)
|
||||
: Date.parse(date_value ?? '') + CACHE_DEFAULT_TTL_MS
|
||||
/** Если exp больше, вернуть ответ из кэша, иначе удалить протухшие данные */
|
||||
: Date.parse(date_value ?? '') + CACHE_DEFAULT_TTL_MS;
|
||||
|
||||
if (Date.now() < exp) {
|
||||
return await extract_file(type, cached_response )
|
||||
return await extract_file(type, cached_response);
|
||||
}
|
||||
await cache.delete(cache_key)
|
||||
await cache.delete(cache_key);
|
||||
}
|
||||
/** Формирование нового кэша, т.к предыдущий протух или его нет */
|
||||
return await return_fetch(type, path, cache_key, body_req)
|
||||
}, (...e) => {throw Error(`Ошибки при получении (get): ${e.join(', ')}`)} )
|
||||
}
|
||||
return await return_fetch(type, path, cache_key, body_req);
|
||||
}, (...e) => {throw Error(`Ошибки при получении (get): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Получить данные на диске (абсолютный/относительный путь)
|
||||
|
|
@ -134,8 +136,8 @@ const get_local = recovery(async (filepath) => {
|
|||
return await get('file', db_get_filepath, {
|
||||
mode: 'file',
|
||||
path: filepath
|
||||
})
|
||||
}, (...e) => {throw Error(`Ошибки при локальном получении (get_local): ${e.join(', ')}`)} )
|
||||
});
|
||||
}, (...e) => {throw Error(`Ошибки при локальном получении (get_local): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Получить данные без кэширования
|
||||
|
|
@ -144,46 +146,43 @@ const get_local = recovery(async (filepath) => {
|
|||
* @returns {Promise<Object|Blob>}
|
||||
*/
|
||||
const get_no_cached = recovery(async (type, path) => {
|
||||
const file = await fetch_with_timeout(path)
|
||||
return await extract_file(type, file)
|
||||
}, (...e) => {throw Error(`Ошибки при получении без кэширования (get_no_cached): ${e.join(', ')}`)} )
|
||||
const file = await fetch_with_timeout(path);
|
||||
return await extract_file(type, file);
|
||||
}, (...e) => {throw Error(`Ошибки при получении без кэширования (get_no_cached): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Получить метериалы поселения для инфо. страницы
|
||||
* Получить материалы поселения для инфо. страницы
|
||||
* @param {MarkerData} properties
|
||||
* - нужные свойства (пути) из свойств feature.
|
||||
* @returns {Promise<{ background: Blob, images: Blob[], slider: Blob[]}>}
|
||||
*/
|
||||
const get_for_info_page = recovery(async (properties) => {
|
||||
/** Фон инфо. страницы */
|
||||
const background = await get_local(properties.background)
|
||||
const background = await get_local(properties.background);
|
||||
|
||||
/** Фотографи инфо. страницы */
|
||||
const images = await Promise.all(
|
||||
(properties.images || []).map(i_path => get_local(i_path))
|
||||
)
|
||||
);
|
||||
|
||||
/** Слайды инфо. страницы (если есть) */
|
||||
const slider = Array.isArray(properties.slider)
|
||||
? await Promise.all(properties.slider.map(s_path => get_local(s_path)))
|
||||
: []
|
||||
: [];
|
||||
|
||||
return {
|
||||
background,
|
||||
images,
|
||||
slider,
|
||||
}
|
||||
}, (...e) => {throw Error(`Ошибки при получении материалов для страницы (get_for_info_page): ${e.join(', ')}`)} )
|
||||
};
|
||||
}, (...e) => {throw Error(`Ошибки при получении материалов для страницы (get_for_info_page): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Получить иконки для стилизации страниц.
|
||||
* @returns {Promise<Object|Blob>}
|
||||
*/
|
||||
const get_icons = recovery(async () => await get_no_cached ('json', './data/icons.json')
|
||||
, (...e) => {throw Error(`Ошибки при получении данных для стилизации (get_icons): ${e.join(', ')}`)} )
|
||||
const get_icons = recovery(async () => await get_no_cached('json', './data/icons.json')
|
||||
, (...e) => {throw Error(`Ошибки при получении данных для стилизации (get_icons): ${e.join(', ')}`)} );
|
||||
|
||||
/**
|
||||
* Получить все geojson'ы из базы данных
|
||||
* @returns {Promise<Object>}
|
||||
*/
|
||||
const get_all_geojsons = recovery(async () => await get('json', db_get_filepath, {'mode': 'geojsons'})
|
||||
, (...e) => {throw Error(`Ошибки при получении geojson'ов из бд (get_all_geojsons): ${e.join(', ')}`)} )
|
||||
, (...e) => {throw Error(`Ошибки при получении geojson'ов из бд (get_all_geojsons): ${e.join(', ')}`)} );
|
||||
|
|
|
|||
Loading…
Reference in New Issue