高级前端性能优化【Q399】实现一个 once 函数,记忆返回结果只执行一次

实现一个 once 函数,记忆返回结果只执行一次

更多描述 类似于 lodash.once

const f = (x) => x;
 
const onceF = once(f);
 
//=> 3
onceF(3);
 
//=> 3
onceF(4);

Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 406

Author 回答者: shfshanyue

简单实现如下:

function once(f) {
  let result;
  let revoked = false;
 
  return (...args) => {
    if (revoked) return result;
    const r = f(...args);
    revoked = true;
    result = r;
    return r;
  };
}

测试一下

> const f = () => {console.log('call'); return 3;}
< undefined
 
> once_f = once(f)
< (...args) => {
    if (revoked) return result
    const r = f(...args)
    revoked = true
    result = r
  }
 
// 第一次调用
> once_f()
< call
< 3
 
// 第二次调用,没有打印 call
> once_f()
< 3

once 是社区使用最广泛的一个库,代码实现与上大同小异,然而每月下载量可达上亿,比 vue/react/angular 三者一个月的下载量加起来还要高一倍

Author 回答者: Vi-jay

function onceCache(fn) {
  let toggle = false,
    ret = null;
  return function () {
    if (toggle) return ret;
    toggle = true;
    return (ret = fn.apply(this, arguments));
  };
}

Author 回答者: eva-asdf

惰性函数

function once(fn) {
  function o(...args) {
    const res = fn(...args);
    o = () => res;
    return o();
  }
  return o;
}

Author 回答者: plutda

function once(func) {
    let revoke = false
    let ret = null
    return function() {
        if (!revoke) {
            ret = func.apply(this, arguments)
            revoke = true
        }
        return ret
    }
}

// 测试
function test() {
    console.log('test')
    return 1
}

let o = once(test)

console.log(o()) // test 1
console.log(o()) // 1
console.log(o()) // 1