日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Reflux系列01:异步操作经验小结

發布時間:2023/12/10 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Reflux系列01:异步操作经验小结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

寫在前面

在實際項目中,應用往往充斥著大量的異步操作,如ajax請求,定時器等。一旦應用涉及異步操作,代碼便會變得復雜起來。在flux體系中,讓人困惑的往往有幾點:

  • 異步操作應該在actions還是store中進行?
  • 異步操作的多個狀態,如pending(處理中)、completed(成功)、failed(失敗),該如何拆解維護?
  • 請求參數校驗:應該在actions還是store中進行校驗?校驗的邏輯如何跟業務邏輯本身進行分離?
  • 本文從簡單的同步請求講起,逐個對上面3個問題進行回答。一家之言并非定則,讀者可自行判別。

    本文適合對reflux有一定了解的讀者,如尚無了解,可先行查看 官方文檔 。本文所涉及的代碼示例,可在 此處下載。

    Sync Action:同步操作

    同步操作比較簡單,沒什么好講的,直接上代碼可能更直觀。

    var Reflux = require('reflux');var TodoActions = Reflux.createActions({addTodo: {sync: true} });var state = []; var TodoStore = Reflux.createStore({listenables: [TodoActions],onAddTodo: function(text){state.push(text);this.trigger(state);},getState: function(){return state;} });TodoStore.listen(function(state){console.log('state is: ' + state); }); TodoActions.addTodo('起床'); TodoActions.addTodo('吃早餐'); TodoActions.addTodo('上班');

    看下運行結果

    ? examples git:(master) ? node 01-sync-actions.js state is: 起床 state is: 起床,吃早餐 state is: 起床,吃早餐,上班

    Async Action:在store中處理

    下面是個簡單的異步操作的例子。這里通過addToServer這個方法來模擬異步請求,并通過isSucc字段來控制請求的狀態為成功還是失敗

    可以看到,這里對前面例子中的state進行了一定的改造,通過state.status來保存請求的狀態,包括:

    • pending:請求處理中
    • completed:請求處理成功
    • failed:請求處理失敗
    var Reflux = require('reflux');/*** @param {String} options.text * @param {Boolean} options.isSucc 是否成功* @param {Function} options.callback 異步回調* @param {Number} options.delay 異步延遲的時間*/ var addToServer = function(options){var ret = {code: 0, text: options.text, msg: '添加成功 :)'};if(!options.isSucc){ret = {code: -1, msg: '添加失敗!'};}setTimeout(function(){options.callback && options.callback(ret);}, options.delay); };var TodoActions = Reflux.createActions(['addTodo']);var state = {items: [],status: '' };var TodoStore = Reflux.createStore({init: function(){state.items.push('睡覺');},listenables: [TodoActions],onAddTodo: function(text, isSucc){var that = this;state.status = 'pending';that.trigger(state);addToServer({text: text,isSucc: isSucc,delay: 500,callback: function(ret){if(ret.code===0){state.status = 'success';state.items.push(text);}else{state.status = 'error';}that.trigger(state);}});},getState: function(){return state;} });TodoStore.listen(function(state){console.log('status is: ' + state.status + ', current todos is: ' + state.items); });TodoActions.addTodo('起床', true); TodoActions.addTodo('吃早餐', false); TodoActions.addTodo('上班', true);

    看下運行結果:

    ? examples git:(master) ? node 02-async-actions-in-store.js status is: pending, current todos is: 睡覺 status is: pending, current todos is: 睡覺 status is: pending, current todos is: 睡覺 status is: success, current todos is: 睡覺,起床 status is: error, current todos is: 睡覺,起床 status is: success, current todos is: 睡覺,起床,上班

    Async Action:在store中處理 潛在的問題

    首先,祭出官方flux架構示意圖,相信大家對這張圖已經很熟悉了。flux架構最大的特點就是單向數據流,它的好處在于 可預測易測試

    一旦將異步邏輯引入store,單向數據流被打破,應用的行為相對變得難以預測,同時單元測試的難度也會有所增加。

    ps:在大部分情況下,將異步操作放在store里,簡單粗暴有效,反而可以節省不少代碼,看著也直觀。究竟放在actions、store里,筆者是傾向于放在actions里的,讀者可自行斟酌。

    畢竟,社區對這個事情也還在吵個不停。。。

    Async 操作:在actions中處理

    還是前面的例子,稍作改造,將異步的邏輯挪到actions里,二話不說上代碼。

    reflux是比較接地氣的flux實現,充分考慮到了異步操作的場景。定義action時,通過asyncResult: true標識:

  • 操作是異步的。
  • 異步操作是分狀態(生命周期)的,默認的有completed、failed。可以通過children參數自定義請求狀態。
  • 在store里通過類似onAddTodo、onAddTodoCompleted、onAddTodoFailed對請求的不同的狀態進行處理。
  • var Reflux = require('reflux');/*** @param {String} options.text * @param {Boolean} options.isSucc 是否成功* @param {Function} options.callback 異步回調* @param {Number} options.delay 異步延遲的時間*/ var addToServer = function(options){var ret = {code: 0, text: options.text, msg: '添加成功 :)'};if(!options.isSucc){ret = {code: -1, msg: '添加失敗!'};}setTimeout(function(){options.callback && options.callback(ret);}, options.delay); };var TodoActions = Reflux.createActions({addTodo: {asyncResult: true} });TodoActions.addTodo.listen(function(text, isSucc){var that = this;addToServer({text: text,isSucc: isSucc,delay: 500,callback: function(ret){if(ret.code===0){that.completed(ret);}else{that.failed(ret);}}}); });var state = {items: [],status: '' };var TodoStore = Reflux.createStore({init: function(){state.items.push('睡覺');},listenables: [TodoActions],onAddTodo: function(text, isSucc){var that = this;state.status = 'pending';this.trigger(state);},onAddTodoCompleted: function(ret){state.status = 'success';state.items.push(ret.text);this.trigger(state);},onAddTodoFailed: function(ret){state.status = 'error';this.trigger(state);},getState: function(){return state;} });TodoStore.listen(function(state){console.log('status is: ' + state.status + ', current todos is: ' + state.items); });TodoActions.addTodo('起床', true); TodoActions.addTodo('吃早餐', false); TodoActions.addTodo('上班', true);

    運行,看程序輸出

    ? examples git:(master) ? node 03-async-actions-in-action.js status is: pending, current todos is: 睡覺 status is: pending, current todos is: 睡覺 status is: pending, current todos is: 睡覺 status is: success, current todos is: 睡覺,起床 status is: error, current todos is: 睡覺,起床 status is: success, current todos is: 睡覺,起床,上班

    Async Action:參數校驗

    前面已經示范了如何在actions里進行異步請求,接下來簡單演示下異步請求的前置步驟:參數校驗。

    預期中的流程是:

    流程1:參數校驗 --> 校驗通過 --> 請求處理中 --> 請求處理成功(失敗)
    流程2:參數校驗 --> 校驗不通過 --> 請求處理失敗

    預期之外:store.onAddTodo 觸發

    直接對上一小節的代碼進行調整。首先判斷傳入的text參數是否是字符串,如果不是,直接進入錯誤處理。

    var Reflux = require('reflux');/*** @param {String} options.text * @param {Boolean} options.isSucc 是否成功* @param {Function} options.callback 異步回調* @param {Number} options.delay 異步延遲的時間*/ var addToServer = function(options){var ret = {code: 0, text: options.text, msg: '添加成功 :)'};if(!options.isSucc){ret = {code: -1, msg: '添加失敗!'};}setTimeout(function(){options.callback && options.callback(ret);}, options.delay); };var TodoActions = Reflux.createActions({addTodo: {asyncResult: true} });TodoActions.addTodo.listen(function(text, isSucc){var that = this;if(typeof text !== 'string'){that.failed({ret: 999, text: text, msg: '非法參數!'});return;}addToServer({text: text,isSucc: isSucc,delay: 500,callback: function(ret){if(ret.code===0){that.completed(ret);}else{that.failed(ret);}}}); });var state = {items: [],status: '' };var TodoStore = Reflux.createStore({init: function(){state.items.push('睡覺');},listenables: [TodoActions],onAddTodo: function(text, isSucc){var that = this;state.status = 'pending';this.trigger(state);},onAddTodoCompleted: function(ret){state.status = 'success';state.items.push(ret.text);this.trigger(state);},onAddTodoFailed: function(ret){state.status = 'error';this.trigger(state);},getState: function(){return state;} });TodoStore.listen(function(state){console.log('status is: ' + state.status + ', current todos is: ' + state.items); });// 非法參數 TodoActions.addTodo(true, true);

    運行看看效果。這里發現一個問題,盡管參數校驗不通過,但store.onAddTodo 還是被觸發了,于是打印出了status is: pending, current todos is: 睡覺。

    而按照我們的預期,store.onAddTodo是不應該觸發的。

    ? examples git:(master) ? node 04-invalid-params.js status is: pending, current todos is: 睡覺 status is: error, current todos is: 睡覺

    shouldEmit 阻止store.onAddTodo觸發

    好在reflux里也考慮到了這樣的場景,于是我們可以通過shouldEmit來阻止store.onAddTodo被觸發。關于這個配置參數的使用,可參考文檔。

    看修改后的代碼

    var Reflux = require('reflux');/*** @param {String} options.text * @param {Boolean} options.isSucc 是否成功* @param {Function} options.callback 異步回調* @param {Number} options.delay 異步延遲的時間*/ var addToServer = function(options){var ret = {code: 0, text: options.text, msg: '添加成功 :)'};if(!options.isSucc){ret = {code: -1, msg: '添加失敗!'};}setTimeout(function(){options.callback && options.callback(ret);}, options.delay); };var TodoActions = Reflux.createActions({addTodo: {asyncResult: true} });TodoActions.addTodo.shouldEmit = function(text, isSucc){if(typeof text !== 'string'){this.failed({ret: 999, text: text, msg: '非法參數!'});return false;}return true; };TodoActions.addTodo.listen(function(text, isSucc){var that = this;addToServer({text: text,isSucc: isSucc,delay: 500,callback: function(ret){if(ret.code===0){that.completed(ret);}else{that.failed(ret);}}}); });var state = {items: [],status: '' };var TodoStore = Reflux.createStore({init: function(){state.items.push('睡覺');},listenables: [TodoActions],onAddTodo: function(text, isSucc){var that = this;state.status = 'pending';this.trigger(state);},onAddTodoCompleted: function(ret){state.status = 'success';state.items.push(ret.text);this.trigger(state);},onAddTodoFailed: function(ret){state.status = 'error';this.trigger(state);},getState: function(){return state;} });TodoStore.listen(function(state){console.log('status is: ' + state.status + ', current todos is: ' + state.items); });// 非法參數 TodoActions.addTodo(true, true); setTimeout(function(){TodoActions.addTodo('起床', true); }, 100)

    再次運行看看效果。通過對比可以看到,當shouldEmit返回false,就達到了之前預期的效果。

    ? examples git:(master) ? node 05-invalid-params-shouldEmit.js status is: error, current todos is: 睡覺 status is: pending, current todos is: 睡覺 status is: success, current todos is: 睡覺,起床

    寫在后面

    flux的實現細節存在不少爭議,而針對文中例子,reflux的設計比較靈活,同樣是使用reflux,也可以有多種實現方式,具體全看判斷取舍。

    最后,歡迎交流。

    總結

    以上是生活随笔為你收集整理的Reflux系列01:异步操作经验小结的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。