Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

14 - 函数式编程 #14

Open
Linjiayu6 opened this issue Jul 18, 2020 · 6 comments
Open

14 - 函数式编程 #14

Linjiayu6 opened this issue Jul 18, 2020 · 6 comments

Comments

@Linjiayu6
Copy link
Owner

Linjiayu6 commented Jul 18, 2020

概念

  • 函数式编程 特点是pure function 纯函数 给定相同输入就一定有相同输出
  • 通过高阶函数实现复用

compose 函数组合

概念:  c(b(a('......'))) 先执行的是a, b, c
合成:  解决嵌套多层的问题,  compose([a, b, c])
// 同步事件串联起来 a => b => c
var a = str => str.toUpperCase() + '+'
var b = str => str.split('').join('&')
var c = str => str + 'bye'

c(b(a('abc')))

实现1 reduce / reduceRight

function compose (funcs) { 
  // 或 funcs.reduceRight((prev, curr) => (...args) => prev(curr(...args)))
  return funcs.reverse().reduce((prev, curr) => (...args) => prev(curr(...args)))
}
compose([a, b, c])('abc')

实现2 指针 + 递归

function compose (funcs) { // funcs 所有执行函数队列 [a, b, c]
  var pointer = 0 // 指针概念
  var _len = funcs.length
  var result = null
  return function fn (...args) {
    if (pointer === _len) return result

    result = funcs[pointer].apply(this, args) // 当前执行
    pointer += 1 // 指针 + 1
    return fn.call(this, result) // 继续往下面执行
  }
}

compose([a, b, c])('abc')
@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 18, 2020

curry 多参数函数 变为 单一参数函数

面试题: 如何实现 multi(2)(3, 4)= 24?

// 接收多参
var add = (a, b, c) => a + b + c

// curry 接收单一参数
var add = a => b => c => a + b + c
var add = function (a) {
  return function (b) {
    return function (c) {
      return a + b + c
    }
  }
}

// 如何实现
var curried = curry(add)
curried(1, 2, 3)()
curried(1, 2)(3)()
curried(1)(2)(3)() 都是一样的结果?

接收参数先保存, 再执行

var add = (...args) => args.reduce((sum, cur) => sum += cur, 0)
function curry (executor) { // executor 最终执行函数
  var _args = [] // 保存函数
  return function fn (...args) {
    if (args && args.length > 0) {
      _args = _args.concat(args) // 接收参数
      return fn // 递归下去
    }
    return executor.apply(this, _args) // 最终执行
  }
}

curry(add)(1, 2)(3)(4, 5)()
curry(add)(1, 2, 3, 4, 5)()
curry(add)(1)(2, 3, 4, 5)()
curry(add)(1)(2, 3, 4)(5)()

@Linjiayu6
Copy link
Owner Author

洋葱模型

class Koa {
  constructor () {
    this.middleware = []
    this.ctx = {}
  }

  use (fn) {
    this.middleware.push(fn)
    return this
  }

  /**
   * 将所有函数组合在一起, 串联流程, 调用next才往下面执行
   * c(b(a()))
   * 先执行a, 通过调用next() koa内部派发 dispatch(i + 1), 继续下一个中间件
   * 目标: 洋葱模型
   */
  compose () {
    var index = 0
    var middleware = this.middleware
    var ctx = this.ctx

    function dispatch (i) {
      if (i >= middleware.length || i < 0) return

      index = i
      var fn = middleware[index]
      var next = () => dispatch(i + 1)
      try {
        return Promise.resolve(fn(ctx, next))
      } catch (err) {
        return Promise.reject(err)
      }
    }

    dispatch(0)
  }

  start () {
    this.compose()
  }
}

var app = new Koa()
app.use(async (ctx, next) => {
  console.log(1)
  await next()
  console.log(6)
})

app.use(async (ctx, next) => {
  console.log(2)
  await next()
  console.log(5)
})

app.use(async (ctx, next) => {
  console.log(3)
  await next()
  console.log(4)
})

app.start()

@Linjiayu6
Copy link
Owner Author

KOA 洋葱模型 + 异步处理

class Koa {
  constructor () {
    this.middleware = []
    this.ctx = {}
  }

  use (fn) {
    this.middleware.push(fn)
    return this
  }

  /**
   * 将所有函数组合在一起, 串联流程, 调用next才往下面执行
   * c(b(a()))
   * 先执行a, 通过调用next() koa内部派发 dispatch(i + 1), 继续下一个中间件
   * 目标: 洋葱模型
   */
  compose () {
    var index = 0
    var middleware = this.middleware
    var ctx = this.ctx

    function dispatch (i) {
      if (i > middleware.length || i < 0) return
      // 若最后一个中间件,返回一个 resolve promise, 必须返回这个要不然报错
      if (i === middleware.length) return Promise.resolve()

      index = i
      var fn = middleware[index]
      var next = () => dispatch(index + 1)
      try {
        return Promise.resolve(fn(ctx, next))
      } catch (err) {
        return Promise.reject(err)
      }
    }

    dispatch(0)
  }

  start () {
    this.compose()
  }
}

var app = new Koa()
app.use(async (ctx, next) => {
  console.log(1)
  await next()
  console.log(8)
})

app.use(async (ctx, next) => {
  console.log(2)
  let p = new Promise((resolve, roject) => {
      setTimeout(() => {
          console.log(3)
          resolve(4)
      }, 3000)
  })
  await p.then(data => console.log(data))
  await next()
  console.log(7)
})

app.use(async (ctx, next) => {
  console.log(5)
  await new Promise(resolve => setTimeout(() => resolve(1), 2000)).then()
  await next()
  console.log(6)
})

app.start()

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 23, 2020

Generator + CO

  • g = fn(初始化值)
  • { value, done } = g.next()
  • value.then((data) => 函数(data))
    当done true, 则停止。

主动推进

function getData (arg) {
  return new Promise(resolve => setTimeout(() => { resolve(arg + 1) }, arg * 1000))
}

function * generator (a) {
  console.log('1', a)
  var b = yield getData(a)
  console.log('2', b)
  var c = yield getData(b)
  console.log('3', c)
  var d = yield getData(c)
  console.log('4', d)
  return d
}

var g = generator(1)
function doing (...args) {
  var { value, done } = g.next(...args)
  if (done === true) {
    return Promise.resolve(value)
  }
  return value.then(doing)
}
doing().then(console.log)

co结合

function getData (arg) {
  return new Promise(resolve => setTimeout(() => { resolve(arg + 1) }, arg * 1000))
}

function * generator (a) {
  console.log('1', a)
  var b = yield getData(a)
  console.log('2', b)
  var c = yield getData(b)
  console.log('3', c)
  var d = yield getData(c)
  console.log('4', d)
  return d
}

function co (generator, ...args) {
  return new Promise(resolve => {
    var g = generator(...args)

    function executor (...args1) {
      var { value, done } = g.next(...args1)
      if (done === true) return resolve(value)
      return value.then((...args2) => executor(...args2))
    }

    executor()
  })
}

// 必须是 Promise加持 才能 then 下去嘛
co(generator, 1).then(d => console.log('最后结果', d))

@Linjiayu6
Copy link
Owner Author

dpr viewpoint media query
bfc
http get post
cache
last-modified IF modified SINCE
etag

@Linjiayu6
Copy link
Owner Author

Linjiayu6 commented Jul 29, 2020

异步串行处理 pipeline

1. reduce

queue.reduce((prev, next) => prev.then(d => next(d))) // 将上一个值返回传给下一个

var A = args => new Promise(resolve => {
  setTimeout(() => {
    console.log('A', args)
    resolve(1)
  }, 1000)
})

var B = args => new Promise(resolve => {
  setTimeout(() => {
    console.log('B', args)
    resolve(2)
  }, 2000)
})

var C = args => new Promise(resolve => {
  setTimeout(() => {
    console.log('C', args)
    resolve(3)
  }, 3000)
})

var queue = [A, B, C]
function compose (queue, arg) {
  return queue.reduce((prev, next) => prev.then(d => next(d)), Promise.resolve(arg))
}
compose(queue, 0)

2. dispatch

var A = args => new Promise(resolve => {
  setTimeout(() => {
    console.log('A', args)
    resolve(1)
  }, 1000)
})

var B = args => new Promise(resolve => {
  setTimeout(() => {
    console.log('B', args)
    resolve(2)
  }, 2000)
})

var C = args => new Promise(resolve => {
  setTimeout(() => {
    console.log('C', args)
    resolve(3)
  }, 3000)
})

var queue = [A, B, C]
function compose (queue) {
  var _args1 = Array.prototype.slice.call(arguments, 1)

  function dispatch (i) {
    var _args2 = Array.prototype.slice.call(arguments, 1)
    if (i === queue.length - 1) return Promise.resolve(queue[i](..._args2))
    if (i < queue.length) {
      return queue[i](..._args2).then((...d) => dispatch(i + 1, ...d))
    }
  }
  dispatch(0, ..._args1)
}
compose(queue, 0)

@Linjiayu6 Linjiayu6 mentioned this issue Jul 29, 2020
9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant