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

資訊專欄INFORMATION COLUMN

【響應(yīng)式編程的思維藝術(shù)】 (2)響應(yīng)式Vs面向?qū)ο?

Tonny / 2690人閱讀

摘要:本文是響應(yīng)式編程第一章響應(yīng)式這篇文章的學(xué)習(xí)筆記。通過代碼對(duì)比可以發(fā)現(xiàn),在響應(yīng)式編程中,我們不再用對(duì)象的概念來對(duì)現(xiàn)實(shí)世界進(jìn)行建模,而是使用流的思想對(duì)信息進(jìn)行拆分和聚合。

本文是Rxjs 響應(yīng)式編程-第一章:響應(yīng)式這篇文章的學(xué)習(xí)筆記。

示例代碼地址:【示例代碼】

更多文章:【《大史住在大前端》博文集目錄】

[TOC]

一. 劃重點(diǎn)

三句非常重要的話:

從理念上來理解,Rx模式引入了一種新的“一切皆流”的編程范式

從設(shè)計(jì)模式的角度來看,Rx模式發(fā)布訂閱模式迭代器模式的組合使用

Rxjs對(duì)事件(流)的變換處理,可以對(duì)比lodash對(duì)數(shù)據(jù)的處理進(jìn)行理解。

原文對(duì)很多基礎(chǔ)卻核心的概念都有詳細(xì)的講解,本文不再贅述。需要注意的是,理解原理是一方面,但能夠熟練使用運(yùn)算符來轉(zhuǎn)換或查詢流信息是需要很長時(shí)間積累的,建議在學(xué)習(xí)過程中,每次遇到新的運(yùn)算符就主動(dòng)查閱資料理解其用法,這樣積少成多慢慢地就總結(jié)出開發(fā)模(tao)式(lu)了。

為了更直觀地感受面向?qū)ο蠛晚憫?yīng)式編程中的不同,筆者分別用兩種模式實(shí)現(xiàn)了兩個(gè)一樣的小動(dòng)畫,Demo比較簡單,就是一個(gè)不斷奔跑的角色和一個(gè)無限滾動(dòng)的背景圖。但是就體會(huì)和理解兩種開發(fā)模式而言基本夠用了。

二. 面向?qū)ο缶幊虒?shí)例 2.1 動(dòng)畫的基本編程范式

動(dòng)畫實(shí)例使用canvas畫布來完成,簡單動(dòng)畫的基本編程模式如下:

//啟動(dòng)函數(shù)
function startCanvasAnimation(){
    //初始化舞臺(tái),舞臺(tái)對(duì)象(或者叫做精靈動(dòng)畫類,幀動(dòng)畫類)
    let background = new Background(ctx1,bgImg);
    let bird = new Bird(ctx1,roleImg);
    //把精靈動(dòng)畫實(shí)例集中管理
    spirits.push(background);
    spirits.push(bird);
    //啟動(dòng)一個(gè)無限循環(huán)繪制暫態(tài)動(dòng)畫的遞歸函數(shù)
    return requestAnimationFrame(paint)
}

//每個(gè)繪制周期重復(fù)調(diào)用的繪制函數(shù)
function paint() {
    //遍歷精靈動(dòng)畫實(shí)例集合
    for(let spirit of spirits){
        spirit.update();//更新自己的參數(shù)
        spirit.paint();//繪制精靈動(dòng)畫
    }
    return requestAnimationFrame(paint);//尾遞歸調(diào)用繪制函數(shù)
}

當(dāng)然示例中沒有涉及局部更新或其他有關(guān)渲染性能的部分,更復(fù)雜的動(dòng)畫需求可以直接使用引擎來實(shí)現(xiàn),這不是本篇的重點(diǎn)。

2.2 參考代碼
/**
 * 角色類
 */
class Role{
    constructor(ctx,img){
        this.ctx = ctx; //傳入畫布上下文實(shí)例
        this.img = img; //傳入幀動(dòng)畫用的圖片
        this.pos = [0,0]; //記錄幀動(dòng)畫初始位置
        this.step = 68; //幀動(dòng)畫不同幀位置間距
        this.index = 0; 
        this.ratio = 4;
    }

    //更新自身狀態(tài)
    update(){
        //此處通過速率控制實(shí)現(xiàn)了幀動(dòng)畫待繪制區(qū)域在雪碧圖中的起始位置
        if (!(this.index++ % this.ratio)) {   
           this.pos[1] = this.pos[1] === 748 ? 0 : this.pos[1] + this.step;
        }
    }

    //繪制
    paint(){
        //將角色繪制在畫布的指定位置
       this.ctx.drawImage(this.img, this.pos[0] , this.pos[1] , 54 ,  64 , 120 , 304, 54, 64);
    }
}

背景也可以當(dāng)做是一個(gè)精靈動(dòng)畫實(shí)例,以同樣的模式定義即可,示例中的角色并沒有實(shí)現(xiàn)相對(duì)畫布的運(yùn)動(dòng)(也就是視差),感興趣的讀者可以自己嘗試實(shí)現(xiàn),完整的示例代碼見附件。

2.3 小結(jié)

面向?qū)ο缶幊讨校唧w的精靈類可以繼承抽象精靈類,且將具體的實(shí)現(xiàn)封裝在自己的類定義中,最后使用類似于建造者模式的方法將各個(gè)實(shí)例組織起來,有面向?qū)ο缶幊探?jīng)驗(yàn)的讀者對(duì)這個(gè)流程應(yīng)該不會(huì)陌生。

三. 響應(yīng)式編程實(shí)現(xiàn)

在響應(yīng)式編程中,我們需要構(gòu)建角色動(dòng)畫流背景動(dòng)畫流這兩個(gè)可觀測(cè)對(duì)象,然后將這兩個(gè)流合并起來,此時(shí)就得到了一個(gè)尚未啟動(dòng)的動(dòng)畫信息流,通過subscribe( )方法啟動(dòng)這個(gè)流,并將繪制方法傳入回調(diào)函數(shù),就可以實(shí)現(xiàn)一個(gè)同樣的動(dòng)畫了。

/**動(dòng)畫的rxjs響應(yīng)式編程實(shí)現(xiàn)*/
//定義動(dòng)畫幀率
var rxjsRatio = 50;
var rxjsFrame = parseInt(1000/rxjsRatio,10);
//構(gòu)建角色動(dòng)畫流
var roleStream = Rx.Observable.interval(rxjsFrame).map(i=>{return {x:0,y:(i%12)*68}});
//構(gòu)建背景動(dòng)畫流
var bgiStream = Rx.Observable.interval(rxjsFrame).map(i=> i%800);
//合并流
var rxjsAnim = Rx.Observable.combineLatest(roleStream,bgiStream,(role, bgi)=>{
                                       return {role,bgi}
                                   }).subscribe(rxjsRender);

//繪制角色
function rxjsPaintRole(rolePos) {
       ctx2.drawImage(roleImg, rolePos.x , rolePos.y , 54 ,  64 , 120 , 304, 54, 64);
}

//繪制背景
function rxjsPaintBgi(offset) {
      let delta = 92;
       //繪制左半部分
       ctx2.drawImage(bgImg , offset + delta , 0 , 800 + delta - offset , 576 , 0 , 0 , 800 + delta - offset , 400);
       //繪制右半部分
       ctx2.drawImage(bgImg , delta, 0 , offset, 576 , 800 - offset , 0 , offset , 400);
}

//繪制
function rxjsRender(actors) {
    rxjsPaintBgi(actors.bgi);
    rxjsPaintRole(actors.role);
}
四. 差異對(duì)比 4.1 編程理念差異
面向?qū)ο缶幊?/strong>用類和繼承封裝多臺(tái)來聚合關(guān)系,響應(yīng)式編程用流和變換來聚合信息。

通過代碼對(duì)比可以發(fā)現(xiàn),在響應(yīng)式編程中,我們不再用對(duì)象的概念來對(duì)現(xiàn)實(shí)世界進(jìn)行建模,而是使用的思想對(duì)信息進(jìn)行拆分和聚合。在面向?qū)ο缶幊讨校?strong>數(shù)據(jù)信息數(shù)據(jù)更新方法,繪制方法這三大要素都是描述具體類的,他們被類的定義聚合在了一起;而在響應(yīng)式編程中,不再強(qiáng)調(diào)“關(guān)系”,而是將數(shù)據(jù)和變化聚合在一起,將處理方式聚合在一起。試想假如上面的示例中增加不同的類,障礙,怪物,積分等等,那么面向?qū)ο缶幊讨芯托枰黾有碌念惗x,而響應(yīng)式編程中就需要增加新的數(shù)據(jù)流,但是在每一個(gè)繪制的時(shí)間點(diǎn)拿到的暫態(tài)數(shù)據(jù)和根據(jù)這些暫態(tài)數(shù)據(jù)進(jìn)行的繪制動(dòng)作,其實(shí)都是一致的,區(qū)別只是關(guān)鍵信息的聚合方式不一樣了。

4.2 編程體驗(yàn)差異

在傳統(tǒng)編程中,我們常常會(huì)得到一個(gè)無法直接用于最終場(chǎng)景的數(shù)據(jù)集合,然后需要手動(dòng)做一些后處理,最終把生成可被使用的數(shù)據(jù)提供給消費(fèi)模塊;而響應(yīng)式編程中強(qiáng)調(diào)的,是“直接告訴程序你最終想要獲得什么數(shù)據(jù)”,然后將程序的加工流程內(nèi)化到生產(chǎn)過程中,從而當(dāng)消費(fèi)模塊得到數(shù)據(jù)時(shí),直接就可以使用,而不需要再做更多的后處理,這對(duì)于消費(fèi)者來說無疑是體驗(yàn)的提升,就好像你去買組裝電腦時(shí),商家都會(huì)幫你推薦組件送貨上門還會(huì)幫你組裝好,你肯定感覺服務(wù)很到位,因?yàn)榇蟛糠秩说哪康氖鞘褂秒娔X,而不是享受買電腦的過程。

4.3 數(shù)學(xué)思想差異
如果說面向?qū)ο缶幊趟枷胧窃诿枋隹陀^世界,那么響應(yīng)式編程就更像是在嘗試揭示規(guī)律。

回過頭再來看我們上面實(shí)現(xiàn)的Demo,在傳統(tǒng)的編程中,我們的思維模式更加傾向于一種微積分的思想,也就是說我們?cè)噲D描述一個(gè)精靈動(dòng)畫的變化時(shí),關(guān)注的是如何從x[i]得到x[i+1],當(dāng)我們得到這樣一個(gè)變換方法x[i+1]=g(x[i])后,只需要在對(duì)象的屬性中記錄每一個(gè)時(shí)刻的x[i],然后在下一個(gè)繪制周期開始時(shí)運(yùn)行這個(gè)方法計(jì)算出x[i+1],按照新的值繪制元素,用新值覆蓋舊值,然后循環(huán)這個(gè)過程就可以了;而在響應(yīng)式編程中,我們采取的方式是為x[i]求出一個(gè)通項(xiàng)公式,也就是x = f(i)這樣一種數(shù)學(xué)形式的描述,它們之間的關(guān)鍵區(qū)別并不是函數(shù)體內(nèi)邏輯的表達(dá)形式,而是在面向?qū)ο笾袑?shí)現(xiàn)的方法是有狀態(tài)的(你需要用某個(gè)實(shí)例屬性來標(biāo)記幀動(dòng)畫實(shí)例當(dāng)前的執(zhí)行狀態(tài)),而響應(yīng)式編程中的方法是無狀態(tài)的,是不是聯(lián)想到什么了?沒錯(cuò),函數(shù)式編程中的純函數(shù)。響應(yīng)式編程本來就是建立在函數(shù)式編程基礎(chǔ)之上的,只通過純函數(shù)實(shí)現(xiàn)集合的映射變換。

如果你聽說過傅里葉變換,應(yīng)該不難發(fā)現(xiàn)響應(yīng)式編程的思維模式和它很像,傅里葉變換可以將一個(gè)混雜的信號(hào),拆分成若干個(gè)不同振幅頻率和相位的正弦波的,這樣工程師就可以獨(dú)立分析自己感興趣的部分,這是信號(hào)分析中很基本的手段。在響應(yīng)式編程中,系統(tǒng)中的狀態(tài)變化以類似的方式被拆分成了很多獨(dú)立的流,如果開發(fā)者關(guān)注的某個(gè)流出現(xiàn)異常,只需要多帶帶關(guān)注其數(shù)據(jù)源和用于流變換的函數(shù)鏈即可(當(dāng)然它的數(shù)據(jù)源也可能會(huì)被拆分成若干個(gè)獨(dú)立的流),而不必陷入巨大的邏輯關(guān)系網(wǎng),這對(duì)于提升大型系統(tǒng)的調(diào)試效率來說是非常重要的。在面向?qū)ο缶幊讨?,這一點(diǎn)是很難做到的,更常見的情況是你修改了A方法,然后B方法就報(bào)錯(cuò)了,緊接著你發(fā)現(xiàn)這個(gè)過程竟然是遞歸的,最后程序崩潰了,你也崩潰了。

4.3 小結(jié)

筆者只是初學(xué),對(duì)響應(yīng)式編程談不上什么經(jīng)驗(yàn),但程序的世界里終究是“沒有更好的技術(shù),只有更適合的方案”,在合適的場(chǎng)景做到合適的技術(shù)選型才更重要,至于什么樣的場(chǎng)景更適合響應(yīng)式編程,還需要在后續(xù)的學(xué)習(xí)和實(shí)踐中慢慢體會(huì),但無論如何,響應(yīng)式編程中蘊(yùn)含的工程思想和數(shù)學(xué)之美讓我贊嘆。

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

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

相關(guān)文章

  • 響應(yīng)編程思維藝術(shù)】 (1)Rxjs專題學(xué)習(xí)計(jì)劃

    摘要:由于技術(shù)棧的學(xué)習(xí),筆者需要在原來函數(shù)式編程知識(shí)的基礎(chǔ)上,學(xué)習(xí)的使用。筆者在社區(qū)發(fā)現(xiàn)了一個(gè)非常高質(zhì)量的響應(yīng)式編程系列教程共篇,從基礎(chǔ)概念到實(shí)際應(yīng)用講解的非常詳細(xì),有大量直觀的大理石圖來輔助理解流的處理,對(duì)培養(yǎng)響應(yīng)式編程的思維方式有很大幫助。 showImg(https://segmentfault.com/img/bVus8n); [TOC] 一. 響應(yīng)式編程 響應(yīng)式編程,也稱為流式編程...

    lscho 評(píng)論0 收藏0
  • 從命令響應(yīng)(一)

    摘要:響應(yīng)式命令式這兩種編程風(fēng)格的思維方式是完全相反的。第二種方式是工人主動(dòng)去找工人索取生產(chǎn)手機(jī)所要的零件,然后生產(chǎn)一臺(tái)完整的手機(jī),這兩種方式就對(duì)應(yīng)的響應(yīng)式和命令式。 angular2中內(nèi)置了rxjs,雖然框架本身并沒有強(qiáng)制開發(fā)者使用響應(yīng)式風(fēng)格來組織代碼,但是從框架開發(fā)團(tuán)隊(duì)的角度可以看出他們必然是認(rèn)同這種編程風(fēng)格的。rxjs本質(zhì)是基于函數(shù)式編程的響應(yīng)式風(fēng)格的庫,函數(shù)式相對(duì)于面向?qū)ο髞碚f更加抽...

    JayChen 評(píng)論0 收藏0
  • 響應(yīng)編程思維藝術(shù)】 (5)Angular中Rxjs應(yīng)用示例

    摘要:本文是響應(yīng)式編程第四章構(gòu)建完整的應(yīng)用程序這篇文章的學(xué)習(xí)筆記。涉及的運(yùn)算符每隔指定時(shí)間將流中的數(shù)據(jù)以數(shù)組形式推送出去。中提供了一種叫做異步管道的模板語法,可以直接在的微語法中使用可觀測(cè)對(duì)象示例五一點(diǎn)建議一定要好好讀官方文檔。 本文是【Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整的Web應(yīng)用程序】這篇文章的學(xué)習(xí)筆記。示例代碼托管在:http://www.github.com/dashnoword...

    shenhualong 評(píng)論0 收藏0
  • 響應(yīng)編程思維藝術(shù)】 (3)flatMap背后代數(shù)理論Monad

    摘要:本文是響應(yīng)式編程第二章序列的深入研究這篇文章的學(xué)習(xí)筆記。函數(shù)科里化的基本應(yīng)用,也是函數(shù)式編程中運(yùn)算管道構(gòu)建的基本方法。四資料參考函數(shù)式編程指南 本文是Rxjs 響應(yīng)式編程-第二章:序列的深入研究這篇文章的學(xué)習(xí)筆記。示例代碼托管在:http://www.github.com/dashnowords/blogs 更多博文:《大史住在大前端》目錄 showImg(https://segme...

    MorePainMoreGain 評(píng)論0 收藏0
  • 響應(yīng)編程思維藝術(shù)】 (4)從打飛機(jī)游戲理解并發(fā)與流融合

    摘要:本文是響應(yīng)式編程第三章構(gòu)建并發(fā)程序這篇文章的學(xué)習(xí)筆記。筆者在自己的實(shí)現(xiàn)中又加入了右鍵切換飛船類型的功能,必須得說開發(fā)游戲的確比寫業(yè)務(wù)邏輯要有意思。由于沒有精確計(jì)算雪碧圖的坐標(biāo),所以在碰撞檢測(cè)時(shí)會(huì)有一些偏差。 本文是Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序這篇文章的學(xué)習(xí)筆記。示例代碼托管在:http://www.github.com/dashnowords/blogs 更多博文:《大...

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

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

0條評(píng)論

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