Last active
June 30, 2021 00:06
-
-
Save akaz00/50239fa691a78dbd2880e2381d1849db to your computer and use it in GitHub Desktop.
캐시 데코레이터
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://stackoverflow.com/questions/15376185/is-it-fine-to-use-json-stringify-for-deep-comparisons-and-cloning