thunk
什麼是thunk
thunk的中文翻譯叫形實轉換程序,計算機編程語言在函數參數求值策略方面有兩大流派,"傳值調用" VS "傳名調用" 。而在實現傳名調用時候編譯器需要將參數放置到一個零時函數中,調用時將這個臨時函數傳入函數體,這個函數就叫做 形式轉換函數 也就是Thunk。
//數學題nvar y = 2;nnfunction f(x){n return x * 2;n}nf(y + 1);nn//===>nnvar thunk = function () {n return y + 1;n}nn//調用時 執行trunknfunction f(thunk){n return thunk() * 2;n};n
而js是傳值調用,所以js裡面的thunk含義更多的是「替換」函數;此函數替換的不是表達式,而是多參函數,藉助柯里化我們就可以實現一個Thunk;
//一個非同步策略nfunction xhr(param, cb){n $.ajax(param, function(data){n if(data.code < 0){n cb && cb(data.msg);n }esle{n cb && cb(null, data)n }n })n};nxhr(param, function (err, data) {n ...n})n// thunk 版本nnvar thunk = Thunk(param);nthunk(function(err, data) {n if(err){n return alert(err);n }n ...n});nnfunction Thunk (param) {n return function(cb){n xhr(param, cb);n }n}n
上面的代碼可以看到,Thunk 轉換器將一個多參函數轉換成為一個單參函數,只接受回調函數作為參數,這個單參的版本就叫Thunk函數。
Generator 函數
先講講回調函數的概念: 所謂回調函數就是把任務的第二段單獨寫在一個函數裡面,等到重新執行這個任務的時候就直接用這個函數,callback 「重新調用」
用回調來解決非同步的問題,會造成回調地獄的事大家都知道,所以為了解決這個問題,大家想出了Promise這種寫法。但有的人寫了很多promise之後覺得雖然函數體橫向上沒有問題了,但是縱向上太過冗長。所以就有了Generator的概念。
Generator 函數 是多線程語言中協程概念在js中的一種實現。
傳統的編程語言,早有非同步編程的解決方案(其實是多任務的解決方案)。其中有一種叫做"協程"(coroutine),意思是多個線程互相協作,完成非同步任務。
Generator 在執行非同步任務時候做如下操作:
- 任務A開始執行
- A執行到一半,暫停,交給任務B
- 一段時間後,(B執行完)交回執行權
- A繼續執行
這個交出執行權的命令就是yield。
// Generator 函數實例nfunction* gen(x){n var y = yield x + 2;n return y;n}nnvar myGen = gen(1);nmyGen.next();//{value:3, done:false}nmyGen.next();//{value:undefined,done:true}n
調用 Generator 函數,會返回一個內部指針,調用該指針對象的next方法,會讓指針游標指向yeild語句,每次調用next 方法會返回一個對象語句表達式當前值value和布爾屬性done
相關的文章可以看下阮一峰的es6 。
Thunk 和Generator在流程管理上的應用
//回調nstep1(function (value1) {n step2(value1, function(value2) {n step3(value2, function(value3) {n step4(value3, function(value4) {n // Do something with value4n });n });n });n});nn// thunk nfunction thunk (fn) {n return function (){n var args = Array.prototype.splice.call(arguments);n return function (cb) {n args.push(cb);n return fn.apply(this, args);n }n }n}n//Generatorn//為了簡單我就寫一個step了nvar step = thunk(function(value) {n return value + 1;n});nfunction* gen() {n var value1 = yield step();n var value2 = yield step(value1);n var value3 = yield step(value2);n var value4 = yield step(value3);n}nnfunction run(fn){n var gen = fn();n function next(value){n var result = gen.next(value);n if (result.done){n return;n }n result.value(next)n }n next()n}nrun(gen);n
有了thunk函數 就可以讓Generator 函數自動執行起來了。
thunk-redux
回到redux,thunk在這裡有什麼用呢?
在redux裡面可以用MIDDLEWARE 來擴展dispatch的功能;import { createStore, applyMiddleware, combineReducers } from redux;nimport thunk from redux-thunk;nimport userReducer from ./reducers/user;nnvar createStoreWithMiddleware = applyMiddleware(thunk)(createStore);n// combine reducernvar reducers = combineReducers({n userReducer: userReducern});nvar store = createStoreWithMiddleware(reducers)nexport default store;nn//這樣就可以讓store來dispatch thunk了nstore.dispatch(function(dispatch){n dispatch(/* action */)n})n.then(function(){n //如果thunk裡面的返回的是promise的就可以在這裡取得n})n
《Thunk 函數的含義和用法》
推薦閱讀:
※[一勺燴]CSS3中常用字體圖標庫總結
※TypeScript 2.5~2.6 新特性一覽
※2017 年 4 月:前端與設計資源集
※(譯)關於響應式的另一種思考
※2017 年了,這麼多前端框架,你會怎樣選擇?
TAG:前端开发 |