Skip to content

Instantly share code, notes, and snippets.

@akaz00
Last active June 30, 2021 00:06
Show Gist options
  • Select an option

  • Save akaz00/50239fa691a78dbd2880e2381d1849db to your computer and use it in GitHub Desktop.

Select an option

Save akaz00/50239fa691a78dbd2880e2381d1849db to your computer and use it in GitHub Desktop.
캐시 데코레이터
function flatObjToArray(o) {
return Object.keys(o).sort().reduce(function (r, k) {
if(typeof o[k] !== "object") return r.concat(k, o[k]);
else return r.concat(k, flatObjToArray(o[k]));
}, []);
}
// 전달되는 함수는 모두 결정적인 함수라고 가정
function cache(f, thisContext = null) {
const cached = new Map();
const wrapper = (function() {
const keys = [];
for(let arg of arguments) {
// 객체인 경우 배열로 flat
keys.push(JSON.stringify((typeof arg !== "object") ? arg : flatObjToArray(arg)));
}
const cacheKey = keys.join(',');
const fromCache = cached.get(cacheKey);
if(fromCache) {
console.log('find cache, retun value from it');
return fromCache;
} else {
console.log('no cache, add result');
const result = f.call(thisContext, ...arguments);
// Promise 처리
if(result instanceof Promise) {
// 기존에 같은 값으로 진행 중인 프로미스가 있으면 해당 프로미스 반환
cached.set(cacheKey, result);
result.then(promiseResult => {
console.log('set Promise result');
// 프로미스를 프로미스 결과값으로 대체
cached.set(cacheKey, promiseResult);
});
} else {
cached.set(cacheKey, result);
}
return result;
}
});
wrapper.cached = cached;
return wrapper;
}
// 일반적인 함수 캐싱
const add = cache((a, b) => a + b);
const triple = cache((a) => a * 3);
add(2, 5); add(2, 5); add(3, 4);
triple(3); triple(5); triple(3);
const getName = cache((person) => person.name);
getName({ name: "John" }); getName({ name: "John" });
getName({ name: "John", address: { city: "Seoul", detail: { loc: 20.1 } }});
// 순서가 바뀐 객체가 전달되도 무방
getName({ address: { detail: { loc: 20.1 }, city: "Seoul" }, name: "John" });
console.log(add.cached);
console.log(triple.cached);
console.log(getName.cached);
// Promise를 반환하는 함수와 async 함수 캐싱
const getNumberInfo = cache(function(num) {
return fetch(`http://numbersapi.com/${num}`)
.then(res => res.text());
});
let a = getNumberInfo(5);
let b = getNumberInfo(5); // 연속적으로 같은 요청이 이루어질 경우 기존 프라미스 객체 반납
console.log(a === b); // true, 같은 객체
const getNumberInfoFromAsync = cache(async function(num) {
return await fetch(`http://numbersapi.com/${num}`)
.then(res => res.text());
});
getNumberInfoFromAsync(5);
// 메소드 캐싱
const person = {
name: "John",
sayGreetTo(target) {
return `${this.name} say hello to ${target}`;
}
}
// 두 번째 인자로 this 전달 가능
const sayGreetTo = cache(person.sayGreetTo, person);
sayGreetTo("Sally"); sayGreetTo("Sally");
@akaz00
Copy link
Author

akaz00 commented Jun 29, 2021

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment