JavaScript의 일괄 처리 및 캐시 상세 정보
4351 단어 JavaScript일괄 처리캐시
최근 운영 환경에서 다음과 같은 상황을 만났습니다.
백그라운드는 사전표에 앞뒤가 공동으로 유지해야 하는 매개 값을 저장하고 type/id에 따라 사전을 가져오는 API를 제공합니다.그래서 목록을 렌더링할 때 많은 목록의 필드가 바로 사전의 id이고 백그라운드를 거치지 않은 데이터의 조합이다.
처음에 우리들이 문제를 해결하는 절차는 다음과 같다
생각
참조 구현:
import { wait } from '../async/wait'
/**
*
* @param handle
* @param ms ( , )
*/
export function batch<P extends any[], R extends any>(
handle: (list: P[]) => Promise<Map<P, R | Error>>,
ms: number = 0,
): (...args: P) => Promise<R> {
// =>
const resultCache = new Map<string, R | Error>()
// =>
const paramCache = new Map<string, number>()
//
let lock = false
return async function (...args: P) {
const key = JSON.stringify(args)
paramCache.set(key, (paramCache.get(key) || 0) + 1)
await Promise.all([wait(() => resultCache.has(key) || !lock), wait(ms)])
if (!resultCache.has(key)) {
try {
lock = true
Array.from(
await handle(Array.from(paramCache.keys()).map((v) => JSON.parse(v))),
).forEach(([k, v]) => {
resultCache.set(JSON.stringify(k), v)
})
} finally {
lock = false
}
}
const value = resultCache.get(key)!
paramCache.set(key, paramCache.get(key)! - 1)
if ((paramCache.get(key) || 0) <= 0) {
paramCache.delete(key)
resultCache.delete(key)
}
if (value instanceof Error) {
resultCache.delete(key)
throw value
}
return value as R
}
}
일괄 처리를 실현하는 기본적인 사고방식은 다음과 같다.1. 맵 paramCache 캐시로 전송된 매개 변수 = > 나머지 호출 횟수 (이 매개 변수는 몇 번 더 결과를 조회해야 함)
2. Map resultCache 캐시 매개 변수 => 결과 사용
3. lock을 사용하여 현재 함수가 실행 중인지 여부를 표시합니다
4. 다음 조건을 충족시키려면 기다려야 한다
맵에 결과 없음
현재 다른 호출이 실행 중입니다
최소 대기 시간 미만 (호출된 최소 시간 세션 수집)
5. lock 표시를 사용하여 실행 중
6. 결과 존재 여부 판단
존재하지 않으면 현재 모든 파라미터를 일괄 처리합니다
7. 캐시맵에서 결과 얻기
8. paramCache에 대응하는 매개 변수의 나머지 호출 횟수-1
9. 캐시를 보존해야 하는지 판단(이 매개 변수에 대응하는 나머지 호출 횟수는 0)
필요하지 않으면 삭제
10. 캐시 결과가 Error인지 판단
그렇다면 throw가 오류를 냈습니다.
LRU 캐시
참조: Wiki 캐시 알고리즘, 구현MemoryCache
질문: 여기는 왜 캐시를 사용합니까?
답: 이곳의 사전 인터페이스는 대략적인 확률상 멱등이기 때문에 캐시를 사용하여 성능을 향상시킬 수 있다
Q: 캐시 정책은 왜 LRU를 선택해야 합니까?
답: FIFO가 불합리하다는 것은 의심의 여지가 없다
물음: 그럼 왜 LFU 알고리즘을 선택하지 않습니까?그것은 가장 빈번한 자원에 접근할 수 있을 것 같다
답: 사전표가 완전한 멱등이 아니기 때문에, 우리는 C가 가장 많이 접근할 수 있는 사전이 계속 삭제되지 않고 데이터베이스에 업데이트되는 것을 피하고 싶습니다.
대체로 사고방식을 다음과 같이 실현하다.
1. Map 레코드 캐시 키 => 마지막 액세스 시간 사용하기
2. 캐시를 가져올 때마다 마지막 액세스 시간 업데이트
3. 새 캐시 추가 시 캐시 수량 확인
최대 수를 초과하면 마지막 액세스 시간이 현재 가장 긴 캐시를 삭제합니다.
4. 새 캐시 추가
Pass: 욕하지 마세요. 성능이 나빠요. 이 장면에서 너무 많은 요소를 캐시하지 않아요. 최대 1000개도 안 돼요.
결합 고급 함수
이제 우리는 이 두 가지 방식을 결합할 수 있다. 동시에onceOfSameParam/batch 두 개의 고급 함수를 사용하여 id에 따라 사전 정보를 얻는 API를 최적화할 수 있다.
const getById = onceOfSameParam(
batch<[number], Dict>(async (idList) => {
if (idList.length === 0) {
return new Map()
}
// id
const list = await this.getByIdList(uniqueBy(idList.flat()))
return arrayToMap(
list,
(dict) => [dict.id],
(dict) => dict,
)
}, 100),
)
비동기식 포맷터 지원ListTable의 비동기
formatter
함수를 지원하려고 했는데, 나중에 생각해 보니 slot
에도 사전 id가 포함되어 있다면?그렇다면 slot
비동기화도 지원해야 하는가?이것은 비교적 까다로운 문제이기 때문에 그래도 지지하지 않는 것이 좋다.마지막으로, 당사는 구성 요소와 API 사이에 *Service 중간층을 추가하여 데이터 변환을 처리합니다.
다음은 JavaScript의 일괄 처리와 캐시에 대한 상세한 내용입니다. JavaScript의 일괄 처리와 캐시에 대한 더 많은 자료는 저희의 다른 관련 글을 주목해 주십시오!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
기초 정리 - 1문자 (String) 숫자 (Number) 불린 (Boolean) null undefined 심볼 (Symbol) 큰정수 (BigInt) 따옴표로 묶어 있어야 함 Not-A-Number - 숫자 데이터 / 숫자로 표...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.