frontend-interview icon indicating copy to clipboard operation
frontend-interview copied to clipboard

什么是惰性计算

Open su37josephxia opened this issue 2 years ago • 7 comments

su37josephxia avatar Feb 25 '22 01:02 su37josephxia

惰性计算

惰性求值又叫惰性计算、懒惰求值,也称为传需求调用,目的就是要 最小化 计算机做的工作

惰性求值的思想就是:不需要立即返回的值,就先别计算

惰性求值是一种编程语言的特性,很多纯粹的函数式编程语言都有这种特性,但是在 JS 中是没有的

那么在 JS 中如何模拟实现惰性计算呢?

我们知道 Generator 函数就不是立即执行的,而是调用 next 方法后再执行,这一点就和惰性计算的特性很像

实现 take 函数,取出数组中前 n 条数据

function test1() {
  function* take(n, items) {
    let i = 0
    if (n < 1) return
    for (let item of items) {
      yield item
      i++
      if (i >= n) {
        return
      }
    }
  }

  let thunk = take(3, [1, 2, 3, 4, 5])

  console.log(thunk.next()) // {value: 1, done: false}
  console.log(thunk.next()) // {value: 2, done: false}
  console.log(thunk.next()) // {value: 3, done: false}
  console.log(thunk.next()) // {value: undefined, done: true}
}
test1()

可以实现惰性计算的 JS 库

RJM1996 avatar Mar 01 '22 13:03 RJM1996

什么是惰性计算?

惰性计算(Lazy Evaluation),又称懒惰计算、懒汉计算,是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。用大白话来理解就是先不计算,等到需要的时候再来计算,绝大多数的时候惰性计算将可以提高程序的性能。

QbjGKNick avatar Mar 01 '22 14:03 QbjGKNick

解释

官方: 惰性计算(Lazy Evaluation),又称懒惰计算、懒汉计算,是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。

理解: 同惰性加载等同理, 主要的思想就是当需要的时候才进行操作, 通过把不需要当前立即执行的操作滞后来实现优化的一种方案.

惰性计算在 Python 等纯粹的函数式编程中都有体现, 在 JS 中可以通过 .next() 的形式来实现

shangjunhao avatar Mar 01 '22 15:03 shangjunhao

解释

官方: 惰性计算(Lazy Evaluation),又称懒惰计算、懒汉计算,是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。

理解: 同惰性加载等同理, 主要的思想就是当需要的时候才进行操作, 通过把不需要当前立即执行的操作滞后来实现优化的一种方案.

惰性计算在 Python 等纯粹的函数式编程中都有体现, 在 JS 中可以通过 .next() 的形式来实现

shangjunhao avatar Mar 01 '22 15:03 shangjunhao

惰性计算是指表达式在绑定时不求值,而是在使用时才求值。简单来说例如我们使用一个计算复杂的函数求值,在加载时不做函数计算调用,等要使用这个值时才调用,象我们通过thunk解决回调地狱的问题,其实就是用通过将函数改造为惰性函数将想要进行的操作先传入函数再作为回调函数传入异步函数,待异步函数完成再去执行想要进行的操作

jiafei-cat avatar Mar 01 '22 15:03 jiafei-cat

惰性计算是指表达式不在它被绑定变量后立即求值,而是需要使用时才去执行计算求值

rachern avatar Mar 01 '22 17:03 rachern

惰性计算就是等到执行这行代码,需要用到的时候再进行计算。比如 fn(1 + 2),这时候 1 + 2已经被计算,如果是惰性计算的话,fn(() => 1 + 2),等到在函数内部用到的时候再执行得到 3。JavaScript实现惰性计算的方式是写成函数,延迟调用。

为什么要惰性计算。假如函数内部有这样的代码,实际上我们不需要提前计算这个数组。可以在内部确认是这个if分支后再计算。

foo([1, 2, 3, 4].filter(n => n > 2))
function foo(arr) {
  if(nums > 5) {
    return
  } else {
    用到 arr 的地方
  }
}

通过惰性计算减少不必要的工作。比如对一个数组,只处理前面的某些值。除非用for循环手动控制,然后 break,不然用什么api都是全部遍历一遍数组。

比如这段代码 Lazy([1,4,2,7,3]).filter(i => i < 3).map(i => i + 10).value(),将数组和各种操作条件存起来,最后value() 的时候再同时进行,这时候一次遍历,如果filter不通过根本不会走后面的map。

// 用另一种思路模仿的话
// 假设在一个实例内
const reduce = (fn, initial) => {
  return val => {
    initial = fn(initial, val)
  }
}

function each(arr, i = 0, ii = arr.length) {
   let value = []
   const reducer = reduce((a, b) => {
     a.push(b)
     return a
   }, value)

   const e = () => {
     if (i < ii) {
       return {
         done: false,
         value: arr[i++],
         next: {
           push(val) {
             reducer(val)
             return e
           },
           e
         }
       }
     } else {
       return { done: true }
     }
  }
  return transform(e, value)
}

function filter(condition) {
  const fi = fn => {
    const { done, value, next } = fn()
    if (done) {
      return { done: true }
    }

    if (condition(value)) {
      return {
        done: false,
        value,
        next: fi(next.push(value))
       }
    }

    fi(next.e)
    return null
  }
  return fi
}

function transform(fn, value) {
  return {
    pipe: f => transform(f(fn), value),
    value: () => value
  }
}

const a = each([1, 2, 3])
  .pipe(filter(i => i < 2))
  .value() // [1]

zcma11 avatar Mar 01 '22 19:03 zcma11