摘要:原文地址前言筆者最近在做一些后臺項目,使用的是,其使用了處理異步數據流,本文將對的原理做一個簡單的解讀,并將實現一個簡易版的。函數的自動流程控制在中,是指一些長時操作,用函數表示。
原文地址
前言筆者最近在做一些后臺項目,使用的是Ant Design Pro,其使用了redux-saga處理異步數據流,本文將對redux-saga的原理做一個簡單的解讀,并將實現一個簡易版的redux-saga。
Generator函數的自動流程控制在redux-saga中,saga是指一些長時操作,用generator函數表示。generator函數的強大之處在于其可以手動的暫停、恢復執行,且可以與函數體外進行數據交互,看如下例子:
function *gen() { const a = yield "hello"; console.log(a); } cont g = gen(); g.next(); // { value: "hello", done: false } setTimeout(() => g.next("hi"), 1000) // 此時 a => "hi" 一秒后打印‘hi"
可以看出來genrator函數何時進行下一步操作完全取決于外部的調度時機,且其內部執行狀態也由外部的輸入決定,這使得generator函數可以很方便的做異步流程控制。舉個例子,我們首先讀取一個文件的內容作為查詢參數,然后請求一個查詢接口并把返回的內容打印出來:
function getParams(file) { return new Promise(resolve => { fs.readFile(file, (err, data) => { resolve(data) }) }) } function getContent(params) { // request返回promise return request(params) } function *gen() { const params = yield getParams("config.json"); const content = yield getContent(params); console.log(content); }
我們可以手動控制gen函數的執行:
const g = gen(); g.next().value.then(params => { g.next(params).value.then(content => { g.next(content); }) })
以上可以達到我們的目的,但是過于繁瑣,我們想要的是generator函數可以自動的執行,可以寫一個簡易的自動執行函數如下:
function genRun(gen) { const g = gen(); next(); function next(err, pre) { let temp; (err === null) && (temp = g.next(pre)); (err !== null) && (temp = g.throw(pre)); if(!temp.done) { nextWithYieldType(temp.value, next); } } } function nextWithYieldType(value, next) { if(isPromise(value)) { value .then(success => next(null, success)) .catch(error => next(error)) } } genRun(gen);
此時generator函數便可以自動執行,事實上我們可以發現,generator的內部狀態完全是由nextWithYieldType決定的,我們可以根據yield的類型執行不同的處理邏輯。
Effect事實上sagaMiddleware.run(saga)可以類似看做genRun(saga),而saga是由一個個的effect組成的,那么effect是什么?redux-saga官網的解釋:一個 effect 就是一個 Plain Object JavaScript 對象,包含一些將被 saga middleware 執行的指令。redux-saga提供了很多Effect創建器,如call、put、take等,已call為例:
function saga*() { const result = yield call(genPromise); console.log(result); }
call(genPromise)生成的就是一個effect,它可能類似如下:
{ isEffect: true, type: "CALL", fn: genPromise }
事實上effect只表明了意圖,而實際的行為由類似于上文的nextWithYieldType完成,例如:
function nextWithYieldType(value, next) { ... if(isCallEffect(value)) { value.fn(). then(success => next(null, success)).catch(error => next(error)) } }
當genPromise函數返回的promise被resolve后便會打印出結果。
生產者與消費者觀察下面的例子
function *saga() { yield take("TEST"); console.log("test..."); } sagaMiddleware.run(test);
saga會在take("TEST")處阻塞,只有執行了dispatch({type: "TEST"})后saga才能繼續運行(注意:此時的dispatch方法是經過sagaMiddleware包裝過的)。這給我們的感覺似乎很像是take是一個生產者,在等待disaptch的消費,事實上take只是一個Effect生成器,具體的處理邏輯依然是在nextWithYieldType完成的,類似于:
function nextWithYieldType(value, next) { ... // take("TEST")生成的effect簡單的認為是 {isEffect: true, type: "TAKE", name: "TEST"} if(isTakeEffect(value)) { channel.take({pattern: value.name, cb: params => next(null, params)}) } }
channel是一個任務生成器,它有兩個方法:take生成任務,put消費任務:
function channel() { /* task = { pattern, cb } */ let _task = null; function take(task) { _task = task; } function put(pattern, args) { if(!_task) return; if(pattern == _task.pattern) _task.cb.call(null, args); } return { take, put } }
顯然任務是在執行dispatch的時候被消費掉的,這個工作是在sagaMiddleware中做的,類似于如下:
const sagaMiddleware = store => { return next => action => { next(action); const { type, ...payload } = action; channel.put(type, payload); } }
看到這里我們可以發現,需要我們做的就是不斷的完善nextWithYieldType這個函數,當完成了put、fork、takeEvery對應的邏輯后,一個具備基本功能的redux-saga就誕生啦,筆者就不在贅述這些功能的實現了。最后,你可以查看這里:tiny-redux-saga,這是筆者實現的一個簡易版的redux-saga,希望對你有所幫助。
全文完。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98775.html
摘要:特點集中處理副作用問題異步實現為監聽執行的工作形式主要是借鑒模式和使用進行實現的。返回的遍歷器對象,可以依次遍歷函數內部的每一個狀態。為了方便,下文中是的簡稱。若任務仍在運行中則為任務拋出的錯誤。由于循環,再次執行。 介紹redux-saga使用和常用api介紹的文章很多,但是真正介紹原理的卻很少,下面我用自己的思路講一下redux-saga的執行過程。源碼有很多刪減,感興趣的可自行查...
摘要:包如何支持子路徑目前看到了兩種做法。最終,以根目錄下的為基準,將此包發布出去。通過能夠正常處理此種類型的庫,但是像等需要解析文件的可能會查找失敗。這種方案最終輸出到上的文件也更少,省得再寫了。目前來看,兼容性更強一些。 npm 包如何支持子路徑? 目前看到了兩種做法。 redux-saga 一種是像 redux-saga/effects 一樣,其實際的資源文件在 lib/cjs/eff...
摘要:即將立秋的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。課多周刊機器人運營中心是如何玩轉起來的分享課多周刊是如何運營并堅持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大...
摘要:即將立秋的課多周刊第期我們的微信公眾號,更多精彩內容皆在微信公眾號,歡迎關注。若有幫助,請把課多周刊推薦給你的朋友,你的支持是我們最大的動力。課多周刊機器人運營中心是如何玩轉起來的分享課多周刊是如何運營并堅持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號:fed-talk,更多精彩內容皆在微信公眾號,歡迎關注。 若有幫助,請把 課多周刊 推薦給你的朋友,你的支持是我們最大...
閱讀 1215·2021-11-22 12:05
閱讀 1342·2021-09-29 09:35
閱讀 639·2019-08-30 15:55
閱讀 3128·2019-08-30 14:12
閱讀 958·2019-08-30 14:11
閱讀 2881·2019-08-30 13:10
閱讀 2403·2019-08-29 16:33
閱讀 3332·2019-08-29 11:02