Thunk&&函数柯里化

compose

函数做为另一个函数的参数时,因为函数式参数,所以先执行作为参数的函数。

函数柯里化

接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数。并且返回接受余下的参数而且返回结果的新函数的技术。
柯里化其实本身是固定一个可以预期的参数,并返回一个特定的函数,处理批特定的需求。这增加了函数的适用性,但同时也降低了函数的适用范围。

Thunk 函数的含义

编译器的“传名调用”实现,往往是将参数放到一个临时函数之中,再将这个临时函数传入函数体。这个临时函数就叫做 Thunk 函数。

function f(m) {
  return m * 2;
}

f(x + 5);

// 等同于

var thunk = function () {
  return x + 5;
};

function f(thunk) {
  return thunk() * 2;
}

上面代码中,函数 f 的参数x + 5被一个函数替换了。凡是用到原参数的地方,对Thunk函数求值即可。

这就是 Thunk 函数的定义,它是“传名调用”的一种实现策略,用来替换某个表达式。

JavaScript 语言的 Thunk 函数

JavaScript 语言是传值调用,它的 Thunk 函数含义有所不同。在 JavaScript 语言中,Thunk 函数替换的不是表达式,而是多参数函数,将其替换成一个只接受回调函数作为参数的单参数函数

// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);

// Thunk版本的readFile(单参数版本)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);

var Thunk = function (fileName){
  return function (callback){
    return fs.readFile(fileName, callback); 
  };
};

上面代码中,fs 模块的 readFile 方法是一个多参数函数,两个参数分别为文件名和回调函数。经过转换器处理,它变成了一个单参数函数,只接受回调函数作为参数。这个单参数版本,就叫做 Thunk 函数。

任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式。下面是一个简单的 Thunk 函数转换器。

var Thunk = function(fn){
  return function (){
    var args = Array.prototype.slice.call(arguments);
    return function (callback){
      args.push(callback);
      return fn.apply(this, args);
    }
  };
};

使用上面的转换器,生成 fs.readFile 的 Thunk 函数。

var readFileThunk = Thunk(fs.readFile);
readFileThunk(fileA)(callback);

redux中间件

让我们可以介入数据从 action 到 reducer 之间的传递过程,从而改变数据流,实现如异步、数据过滤、日志上报等功能。

加载中间件有两个核心的方法: createStore 和 applyMiddleware ,接下来我们就从源码剖析,看 redux 中间件的运行原理到底是怎么样的。

import compose from './compose'

export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, preloadedState, enhancer) => {
    var store = createStore(reducer, preloadedState, enhancer)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

实现applyMiddleware&thunk


export function applyMiddleware(middleWare){
   
    return createStore=>(...args)=>{
        // 生成createStore,...agr就是reducer
        const store = createStore(...args)
        let dispatch = store.dispatch

        const midApi = {
            getState : store.getState,
            dispatch : (...args)=>dispatch(...args)
        }
        // 把原生的dispatch拿出来,给到middleWare
        dispatch = middleWare(midApi)(store.dispatch)
        return {
            ...store,
            dispatch
        }

    }
}

----
const thunk = ({dispatch,getState})=>next=>action=>{
    // 如果是函数,执行以下,参数是dispatch和getState
    if(typeof action == 'function'){
        return action(dispatch,getState)
    }

    // 默认,什么都没干
    return next(action)
}

1、enhancer(createStore)(reducer, preloadedState) 执行的时候,参数 createStore 给了第一层匿名函数,因为我们的目的是要对 createStore 进行修饰。而 reducer, preloadedState 两个参数给了第二层匿名函数。

推荐阅读更多精彩内容

  • 异步编程对JavaScript语言太重要。Javascript语言的执行环境是“单线程”的,如果没有异步编程,根本...
    呼呼哥阅读 4,858评论 5 22
  • 上周六参加了一个公司的面试,因为是很长时间以来的第一次面试,发挥的并不是很好,有两个下来一想就明白的问题在当时却卡...
    夏尔先生阅读 5,583评论 0 14
  • http://gaearon.github.io/redux/index.html ,文档在 http://rac...
    jacobbubu阅读 75,528评论 34 192
  • 在学习了redux过程中,了解到中间件这个名词,但是我看了十遍,也完全就是懵逼的状态。于是又重复敲了几次代码也不能...
    绰号陆拾柒阅读 187评论 0 0
  • /温妮深山老林 走桥 坐船 船从桥下过 此岸 彼岸 近瞧 远望 一条河 瘦骨伶仃的样子 欲断又流 洋洋洒洒时 ...
    温妮深山老林阅读 39评论 3 3