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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

flowJS源码个人分析

發(fā)布時(shí)間:2025/7/25 javascript 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 flowJS源码个人分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

剛剛在騰訊云技術(shù)社區(qū)前端專欄中看到一篇騰訊高級(jí)前端工程師寫的《一個(gè)只有99行代碼的js流程框架》覺得很屌,感覺是將后臺(tái)的簡(jiǎn)單的工作流思維搬到了前端js實(shí)現(xiàn),本人不才在這里拜讀解析下源碼,而且經(jīng)常有新手問我的很多問題其實(shí)是不懂如何調(diào)試一段js代碼,在這這里就詳細(xì)說明下我是怎么調(diào)試flowJS的源碼思路的。前端大神見笑小弟的總結(jié)

首先第一段:

var obj = arguments[0], flow = {init: function(){}}, flowData = {}, noop = function(){}, init = 'init', trace = flowJS.trace = flowJS.trace||[init];

?

這段代碼就是把要用到的變量在開始聲明用逗號(hào)隔開,為了代碼的整潔和節(jié)省代碼的語句數(shù)量。

第二段:

if(({}).toString.call(obj) === '[object Object]'){//判斷第一個(gè)參數(shù)是否是對(duì)象,這個(gè)方法最準(zhǔn)確extend(flow, obj);flow.init.call(extend({getCurr:function(){return init;}, stepData:function(dataName){return dataName?undefined:{};}, getPrev:noop, fail:noop, success:noop}, new Step(init)));}

?

讀到extend(flow,obj);我們應(yīng)該猜到是將參數(shù)和flow合并,我們?cè)趤砜磂xtend方法:

function prop(obj, fun){for(var p in obj) {obj.hasOwnProperty(p) && fun(p);//判斷這個(gè)屬性是原始屬性還是原型上的屬性}}/*對(duì)象的合并擴(kuò)展*/function extend(des, src){prop(src, function(p){des[p] = src[p];});return des;}

?

extend的方法是將src的原生屬性添加到des對(duì)象中。然后我們接著主線看:

flow.init.call(extend({getCurr:function(){return init;}, stepData:function(dataName){return dataName?undefined:{};}, getPrev:noop, fail:noop, success:noop}, new Step(init)));

這段代碼就是要執(zhí)行參數(shù)中的init方法并且將一個(gè)自定義添加Step(init)返回的對(duì)象中的屬性的對(duì)象作為init中的this對(duì)象。那重點(diǎn)在Step方法,但由于里面有點(diǎn)復(fù)雜剛開始接觸你看不到他在里什么的各種方法的用處,在這里我們最后結(jié)合《一個(gè)只有99行代碼的js流程框架》文章提供的api例子來調(diào)試?yán)锩娓鱾€(gè)方法的作用這樣更好的梳理整個(gè)功能的運(yùn)行邏輯,在這里就體現(xiàn)了張鎮(zhèn)圳大神的所說的一個(gè)模塊的功能中代碼的邏輯梳理、可讀性、語義化多么重要,但flowJS這個(gè)框架可以理解為項(xiàng)目的在js原生上封裝了一層脫了業(yè)務(wù)層的框架,這種框架一般是組長(zhǎng)或是高級(jí)前端工程來維護(hù),而且一般隨著時(shí)間的積累慢慢成熟成型后期的改動(dòng)會(huì)很小,所以這里只要相對(duì)用面向?qū)ο笫崂硐逻壿嬀涂梢?#xff0c;而業(yè)務(wù)層隨客戶的不斷增多,需求的改動(dòng)頻繁出現(xiàn),而且項(xiàng)目的大部分改動(dòng)工作量都在業(yè)務(wù)層上,所以業(yè)務(wù)層代碼邏輯梳理、可讀性、語義化尤為重要,關(guān)系到后期維護(hù)的成本。

我們先從文章中第一個(gè)例子來調(diào)試;

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>flowJS demo1</title> </head> <body> </body> <script type="text/javascript" src="./flowJS.js"></script> <script type="text/javascript"> flowJS({init:function(){this.setNext('步驟A').setNext('步驟B').setNext('步驟C'); //預(yù)先設(shè)置好需要經(jīng)過的每個(gè)步驟this.next();},'步驟A':function(){console.log('執(zhí)行 步驟A');this.next(); //告訴流程執(zhí)行下一步},'步驟B':function(){console.log('執(zhí)行 步驟B');this.next();},'步驟C':function(){console.log('執(zhí)行 步驟C');} }); </script> </html>

?

第一例子中就兩個(gè)函數(shù)一個(gè)setNext,next;我們先來看setNext方法:

this.setNext = function(stepName, s, f){success = s||success;//獲取參數(shù)中成功回調(diào)函數(shù)fail = f||fail;//獲取參數(shù)中失敗回調(diào)函數(shù)nextStepName = stepName||nextStepName;//判斷stepName是否為空,為空將賦值原來的nextStep = new Step(nextStepName);//實(shí)例化對(duì)象return nextStep; };

?

比較簡(jiǎn)單,就是實(shí)例化step對(duì)象。之后我們?cè)诳磏ext方法代碼:

this.next = function(stepName, s, f){nextStepName = stepName||nextStepName;success = s||success;fail = f||fail;nextStep = stepName?new Step(stepName):nextStep;if(nextStepName){nextStep.stepData = function(dataName){return dataName?nextData[dataName]:nextData;};nextStep.getPrev = function(){return name;};nextStep.fail = function(){fail.apply(this, arguments);};nextStep.success = function(){success.apply(this, arguments);};stepMapping[this.getCurr()] = true;if(allDone()){trace.push(nextStepName);typeof nextStepName == 'string' && proxy(nextStepName);if(({}).toString.call(nextStepName) === '[object Array]'){for(var i=0; i<nextStepName.length; i++){proxy(nextStepName[i]);}}function proxy(stepName, fn){if(typeof (fn = flow[stepName]) == 'function'){(function(fn, context){return function(){debugger;return fn.apply(context, arguments);};})(fn, extend({getCurr:function(){return stepName;}}, nextStep))();}else{throw new Error("step not found: "+stepName);}}}return nextStep;} };

?

一開始懵逼看不懂很正常,我們?cè)诶锩婕訑帱c(diǎn)跟著demo一步一步走對(duì)整個(gè)邏輯的理解會(huì)更清晰一點(diǎn)。

this.next = function(stepName, s, f){debugger;nextStepName = stepName||nextStepName;success = s||success;fail = f||fail;nextStep = stepName?new Step(stepName):nextStep;if(nextStepName){nextStep.stepData = function(dataName){

?

在里面加了debugger,然后我們一步一步的調(diào)試:

?

開始我覺得遺憾的是為什么nextStepName里的值是“步驟A”,整個(gè)方法是在這個(gè)地方調(diào)用的。

?

而nextStepName的變量是在setNext復(fù)制的

?

按道理應(yīng)該里面的值是最后一次調(diào)用setNext的參數(shù)也就是“步驟C”,那為什么運(yùn)行結(jié)果里面的值是步驟A呢,這里要看你的理解領(lǐng)悟能了,算法有了,結(jié)果有了,你能強(qiáng)行理解算法而經(jīng)歷往結(jié)果靠攏么?這個(gè)問題的重點(diǎn)是在setNext的返回值,setNext返回的是新的step實(shí)例對(duì)象。在結(jié)合

this.setNext('步驟A').setNext('步驟B').setNext('步驟C'); //預(yù)先設(shè)置好需要經(jīng)過的每個(gè)步驟

?

用圖來解析這個(gè)方法的輸出和執(zhí)行會(huì)更好理解:

?

this.next();

?

這段代碼執(zhí)行的this對(duì)象中的nextStepName私有變量的值為步驟A。

然后我們接著往下看next方法里的代碼:

success = s||success;//賦值參數(shù)的成功回調(diào)函數(shù) fail = f||fail;//賦值參數(shù)的失敗回調(diào)函數(shù) nextStep = stepName?new Step(stepName):nextStep;//如果第一參數(shù)有值的話返回這個(gè)值得step實(shí)例對(duì)象,沒有的話返回對(duì)象的nextStep私有變量 if(nextStepName){/*對(duì)象上添加一系列方法 暫時(shí)忽略*/nextStep.stepData = function(dataName){return dataName?nextData[dataName]:nextData;};nextStep.getPrev = function(){return name;};nextStep.fail = function(){fail.apply(this, arguments);};nextStep.success = function(){success.apply(this, arguments);};/*對(duì)象上添加一系列方法 暫時(shí)忽略*/stepMapping[this.getCurr()] = true;//標(biāo)記上一步步驟被執(zhí)行了

?

代碼加了注釋基本很好理解就不多說了。下一個(gè)重點(diǎn)是這句

if(allDone()){

? ?下回分解。

源碼可以在騰訊云技術(shù)社區(qū)上下載,我把源碼都上加注釋在放到Github上,下載暫時(shí)不放上去。

轉(zhuǎn)載于:https://www.cnblogs.com/libin-1/p/6708330.html

總結(jié)

以上是生活随笔為你收集整理的flowJS源码个人分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。