1. 什么是备忘录模式
它属于行为模式,保存某个状态,并且在需要的时候直接获取,而不是重复计算。
注意:备忘录模式实现,不能破坏原始封装。
也就是说,能拿到内部状态,将其保存在外部。
2. 应用场景
最典型的例子是“斐波那契数列”递归实现。
不借助备忘录模式,数据一大,就容易爆栈;借助备忘录,算法的时间复杂度可以降低到$ O(N) $
除此之外,数据的缓存等也是常见应用场景。
3. 多语言实现
3.1 ES6 实现
首先模拟了一下简单的拉取分页数据。
如果当前数据没有被缓存,那么就模拟异步请求,并将结果放入缓存中;
如果已经缓存过,那么立即取出即可,无需多次请求。
main.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const fetchData = (() => { const cache = {}
return (page) => new Promise((resolve) => { if (page in cache) { return resolve(cache[page]) } setTimeout(() => { cache[page] = `内容是${page}` resolve(cache[page]) }, 1000) }) })()
const run = async () => { let start = new Date().getTime(), now await fetchData(1) now = new Date().getTime() console.log(`没有缓存, 耗时${now - start}ms`)
start = now await fetchData(1) now = new Date().getTime() console.log(`有缓存, 耗时${now - start}ms`) }
run()
|
最近在项目中还遇到一个场景,在React
中加载微信登陆二维码。
这需要编写一个插入script
标签的函数。
要考虑的情况是:
- 同一个
script
标签不能被多次加载
- 对于加载错误,要正确处理
- 对于几乎同时触发加载函数的情况, 应该考虑锁住
基于此,main2.js文件编码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| const loadScript = (src) => { let exists = false
return () => new Promise((resolve, reject) => { if (exists) return resolve() exists = true let script = document.createElement('script') script.src = src script.type = 'text/javascript' script.onerror = (ev) => { script.remove() exists = false reject(new Error('Load Error')) } script.onload = () => { resolve() } document.body.appendChild(script) }) }
const wxLoader = loadScript('https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.jser')
setInterval(() => { wxLoader() .then() .catch((error) => console.log(error.message)) }, 5000)
|
在index2.html
中引入上述代码,即可查看效果:
1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <script src="./main2.js"></script> </body> </html>
|
3.2 python3 实现
这里实现一下借助“备忘录模式”优化过的、递归写法的“斐波那契数列”。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| def fibonacci(n): mem = {1: 1, 2: 1}
def _fibonacci(_n): if _n in mem: return mem[_n] mem[_n] = _fibonacci(_n - 1) + _fibonacci(_n - 2) return mem[_n]
return _fibonacci(n)
if __name__ == '__main__': print(fibonacci(999))
|