成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

超級(jí)易懂的redux-saga原理解析

wendux / 2742人閱讀

摘要:原文地址前言筆者最近在做一些后臺(tái)項(xiàng)目,使用的是,其使用了處理異步數(shù)據(jù)流,本文將對(duì)的原理做一個(gè)簡(jiǎn)單的解讀,并將實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的。函數(shù)的自動(dòng)流程控制在中,是指一些長(zhǎng)時(shí)操作,用函數(shù)表示。

原文地址

前言

筆者最近在做一些后臺(tái)項(xiàng)目,使用的是Ant Design Pro,其使用了redux-saga處理異步數(shù)據(jù)流,本文將對(duì)redux-saga的原理做一個(gè)簡(jiǎn)單的解讀,并將實(shí)現(xiàn)一個(gè)簡(jiǎn)易版的redux-saga。

Generator函數(shù)的自動(dòng)流程控制

在redux-saga中,saga是指一些長(zhǎng)時(shí)操作,用generator函數(shù)表示。generator函數(shù)的強(qiáng)大之處在于其可以手動(dòng)的暫停、恢復(fù)執(zhí)行,且可以與函數(shù)體外進(jìn)行數(shù)據(jù)交互,看如下例子:

function *gen() {
  const a = yield "hello";
  console.log(a);
}

cont g = gen();
g.next(); // { value: "hello", done: false }
setTimeout(() => g.next("hi"), 1000)  // 此時(shí) a => "hi"   一秒后打印‘hi"

可以看出來genrator函數(shù)何時(shí)進(jìn)行下一步操作完全取決于外部的調(diào)度時(shí)機(jī),且其內(nèi)部執(zhí)行狀態(tài)也由外部的輸入決定,這使得generator函數(shù)可以很方便的做異步流程控制。舉個(gè)例子,我們首先讀取一個(gè)文件的內(nèi)容作為查詢參數(shù),然后請(qǐng)求一個(gè)查詢接口并把返回的內(nèi)容打印出來:

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);
}

我們可以手動(dòng)控制gen函數(shù)的執(zhí)行:

const g = gen();
g.next().value.then(params => {
  g.next(params).value.then(content => {
    g.next(content);
  })
})

以上可以達(dá)到我們的目的,但是過于繁瑣,我們想要的是generator函數(shù)可以自動(dòng)的執(zhí)行,可以寫一個(gè)簡(jiǎn)易的自動(dòng)執(zhí)行函數(shù)如下:

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);

此時(shí)generator函數(shù)便可以自動(dòng)執(zhí)行,事實(shí)上我們可以發(fā)現(xiàn),generator的內(nèi)部狀態(tài)完全是由nextWithYieldType決定的,我們可以根據(jù)yield的類型執(zhí)行不同的處理邏輯。

Effect

事實(shí)上sagaMiddleware.run(saga)可以類似看做genRun(saga),而saga是由一個(gè)個(gè)的effect組成的,那么effect是什么?redux-saga官網(wǎng)的解釋:一個(gè) effect 就是一個(gè) Plain Object JavaScript 對(duì)象,包含一些將被 saga middleware 執(zhí)行的指令。redux-saga提供了很多Effect創(chuàng)建器,如call、put、take等,已call為例:

function saga*() {
  const result = yield call(genPromise);
  console.log(result);
}

call(genPromise)生成的就是一個(gè)effect,它可能類似如下:

{
  isEffect: true,
  type: "CALL",
  fn: genPromise
}

事實(shí)上effect只表明了意圖,而實(shí)際的行為由類似于上文的nextWithYieldType完成,例如:

function nextWithYieldType(value, next) {
  ...
  if(isCallEffect(value)) {
    value.fn(). then(success => next(null, success)).catch(error => next(error))  
  } 
}

當(dāng)genPromise函數(shù)返回的promise被resolve后便會(huì)打印出結(jié)果。

生產(chǎn)者與消費(fèi)者

觀察下面的例子

function *saga() {
  yield take("TEST");
  console.log("test...");
}

sagaMiddleware.run(test);

saga會(huì)在take("TEST")處阻塞,只有執(zhí)行了dispatch({type: "TEST"})后saga才能繼續(xù)運(yùn)行(注意:此時(shí)的dispatch方法是經(jīng)過sagaMiddleware包裝過的)。這給我們的感覺似乎很像是take是一個(gè)生產(chǎn)者,在等待disaptch的消費(fèi),事實(shí)上take只是一個(gè)Effect生成器,具體的處理邏輯依然是在nextWithYieldType完成的,類似于:

function nextWithYieldType(value, next) {
  ...
  // take("TEST")生成的effect簡(jiǎn)單的認(rèn)為是  {isEffect: true, type: "TAKE", name: "TEST"}
  if(isTakeEffect(value)) {
    channel.take({pattern: value.name, cb: params => next(null, params)})  
  } 
}

channel是一個(gè)任務(wù)生成器,它有兩個(gè)方法:take生成任務(wù),put消費(fèi)任務(wù):

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
  }
}

顯然任務(wù)是在執(zhí)行dispatch的時(shí)候被消費(fèi)掉的,這個(gè)工作是在sagaMiddleware中做的,類似于如下:

const sagaMiddleware = store => {
  return next => action => {
    next(action);
    
    const { type, ...payload } = action;
    channel.put(type, payload);
  }
} 

看到這里我們可以發(fā)現(xiàn),需要我們做的就是不斷的完善nextWithYieldType這個(gè)函數(shù),當(dāng)完成了putfork、takeEvery對(duì)應(yīng)的邏輯后,一個(gè)具備基本功能的redux-saga就誕生啦,筆者就不在贅述這些功能的實(shí)現(xiàn)了。最后,你可以查看這里:tiny-redux-saga,這是筆者實(shí)現(xiàn)的一個(gè)簡(jiǎn)易版的redux-saga,希望對(duì)你有所幫助。

全文完。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/98775.html

相關(guān)文章

  • redux-saga實(shí)現(xiàn)與原理

    摘要:特點(diǎn)集中處理副作用問題異步實(shí)現(xiàn)為監(jiān)聽執(zhí)行的工作形式主要是借鑒模式和使用進(jìn)行實(shí)現(xiàn)的。返回的遍歷器對(duì)象,可以依次遍歷函數(shù)內(nèi)部的每一個(gè)狀態(tài)。為了方便,下文中是的簡(jiǎn)稱。若任務(wù)仍在運(yùn)行中則為任務(wù)拋出的錯(cuò)誤。由于循環(huán),再次執(zhí)行。 介紹redux-saga使用和常用api介紹的文章很多,但是真正介紹原理的卻很少,下面我用自己的思路講一下redux-saga的執(zhí)行過程。源碼有很多刪減,感興趣的可自行查...

    itvincent 評(píng)論0 收藏0
  • npm 包如何支持子路徑?

    摘要:包如何支持子路徑目前看到了兩種做法。最終,以根目錄下的為基準(zhǔn),將此包發(fā)布出去。通過能夠正常處理此種類型的庫,但是像等需要解析文件的可能會(huì)查找失敗。這種方案最終輸出到上的文件也更少,省得再寫了。目前來看,兼容性更強(qiáng)一些。 npm 包如何支持子路徑? 目前看到了兩種做法。 redux-saga 一種是像 redux-saga/effects 一樣,其實(shí)際的資源文件在 lib/cjs/eff...

    teren 評(píng)論0 收藏0
  • 即將立秋《課多周刊》(第2期)

    摘要:即將立秋的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。課多周刊機(jī)器人運(yùn)營中心是如何玩轉(zhuǎn)起來的分享課多周刊是如何運(yùn)營并堅(jiān)持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大...

    ruicbAndroid 評(píng)論0 收藏0
  • 即將立秋《課多周刊》(第2期)

    摘要:即將立秋的課多周刊第期我們的微信公眾號(hào),更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。若有幫助,請(qǐng)把課多周刊推薦給你的朋友,你的支持是我們最大的動(dòng)力。課多周刊機(jī)器人運(yùn)營中心是如何玩轉(zhuǎn)起來的分享課多周刊是如何運(yùn)營并堅(jiān)持下來的。 即將立秋的《課多周刊》(第2期) 我們的微信公眾號(hào):fed-talk,更多精彩內(nèi)容皆在微信公眾號(hào),歡迎關(guān)注。 若有幫助,請(qǐng)把 課多周刊 推薦給你的朋友,你的支持是我們最大...

    MRZYD 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<