新聞中心
記得當(dāng)年我剛學(xué) JavaScript 的時(shí)候,是從原生的 dom api 學(xué)起的,用原生的 dom api 完成一些增刪改的功能,之后就會(huì)學(xué)習(xí) JQuery。

在薊州等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專(zhuān)注、極致的服務(wù)理念,為客戶(hù)提供成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站 網(wǎng)站設(shè)計(jì)制作定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營(yíng)銷(xiāo)型網(wǎng)站,外貿(mào)營(yíng)銷(xiāo)網(wǎng)站建設(shè),薊州網(wǎng)站建設(shè)費(fèi)用合理。
剛接觸 JQuery 的時(shí)候,感覺(jué)這也太爽了吧。比如這樣一段邏輯:
創(chuàng)建一個(gè) p 標(biāo)簽包含一個(gè)文本節(jié)點(diǎn),然后插入到 container 中。
用原生 dom api 寫(xiě)是這樣的:
const containerDom = document.getElementById('container');
const textDom = document.createTextNode("Hello World.");
const paraDom = document.createElement("p");
pparaDom.appendChild(textDom);
containerDom.appendChild(paraDom);
而用 JQuery 寫(xiě)是這樣的:
const $container = $('#container');
$container.append('Hello World.
');
比起用原生 dom api 來(lái)寫(xiě)簡(jiǎn)化太多了!這也是為什么 JQuery 當(dāng)年那么火的原因。
雖然現(xiàn)在都用 Vue、React 這種數(shù)據(jù)驅(qū)動(dòng)的前端框架來(lái)寫(xiě)頁(yè)面,基本不直接操作 dom 了。但涉及到一些活動(dòng)頁(yè)等需要直接操作 dom 的場(chǎng)景,用 JQuery 依然很方便。
那 JQuery 做了什么呢?
JQuery 把 dom 封裝了一層,提供了很多操作 dom 的 api,并且支持鏈?zhǔn)秸{(diào)用,可以方便的組織 dom 操作邏輯,而且還支持插件來(lái)自定義一些方法在鏈?zhǔn)秸{(diào)用中使用。
可能你會(huì)說(shuō),JQuery 不是基本用不到了么,提它干什么?
因?yàn)槲矣X(jué)得 JQuery 對(duì) dom 操作的這層封裝很好,把操作 dom 的復(fù)雜度降低了很多。前端除了經(jīng)常操作 dom 外,還會(huì)經(jīng)常處理異步,比如 XHR 和 Fetch、Event Listener 等,雖然可以用 Promise 封裝,還可以進(jìn)一步簡(jiǎn)化成 async/await 的寫(xiě)法,但是 Promise 和 async/await 只是改變了異步邏輯的書(shū)寫(xiě)形式,并沒(méi)有降低異步邏輯編寫(xiě)的復(fù)雜度。 能不能就像 JQuery 對(duì) dom 操作的封裝那樣,把異步邏輯也給封裝一層,簡(jiǎn)化下異步邏輯的編寫(xiě)呢?
確實(shí)有這樣的一個(gè)庫(kù),就是 Rx.js。
寫(xiě) JQuery 的時(shí)候我們是把 dom 封裝了一層,比如 const $container = $(dom),這樣就能用 JQuery 內(nèi)置的工具函數(shù)或者通過(guò)插件擴(kuò)展的一些函數(shù),通過(guò)鏈?zhǔn)秸{(diào)用把邏輯串起來(lái)。
為了和 dom 對(duì)象容易區(qū)分,我們會(huì)把 JQuery 對(duì)象命名成 $、$yy 等。
那么 Rx.js 第一步要做的也是把異步邏輯包一層:
也就是把 Event Listener、Promise、回調(diào)函數(shù)這種異步代碼包一層:
// 包一層 Event Listener
const observable$ = Rx.Observable.fromEvent(document.querySelector('button'), 'click');
// 包一層 Promise
const observable2$ = Rx.Observable.fromPromise(fetch('/users'));
// 包一層 callback
const observeable3$ = Rx.Observable.bindCallback(fs.exists);
包裝以后的對(duì)象不叫 RxJS 對(duì)象,叫做 Observable 對(duì)象,而且為了便于區(qū)分,我們會(huì)把它命名為 xxx$、$,就像 JQuery 對(duì)象我們會(huì)命名成 $、$yyy 一樣。
然后就可以用內(nèi)置的一系列工具函數(shù)了,這些叫做操作符 operator:
observable$.pipe(
throttleTime(300),
take(3),
map(event => event.target.value)
);
比如異步邏輯我們經(jīng)常做節(jié)流處理,那就不用自己寫(xiě)了,直接用內(nèi)置的操作符 throttleTime 就行。
還有忽略前三次事件 take(3),對(duì)數(shù)據(jù)做一次映射 map(() => xxx) 等等這些常見(jiàn)異步邏輯用操作符來(lái)寫(xiě)就很簡(jiǎn)單。
把異步邏輯組織成鏈條(或者叫管道 pipe),用操作符來(lái)寫(xiě)每步的處理邏輯,然后串聯(lián)起來(lái),這樣就把異步邏輯的書(shū)寫(xiě)變?yōu)榱?pipe 的組織。而且就像 JQuery 可以寫(xiě)插件來(lái)擴(kuò)展一樣,Rxjs 也支持自定義操作符。
經(jīng)過(guò)這個(gè)管道之后,數(shù)據(jù)經(jīng)過(guò)了每一步異步邏輯的處理,我們可以通過(guò) subcribe 監(jiān)聽(tīng),拿到最終的數(shù)據(jù)。
observerable$.subscribe((value) => {
// xxx
})
當(dāng)然,也可能在處理的過(guò)程中出錯(cuò)了,那也要把 error 傳下去,并且最終處理完以后也會(huì)有個(gè)通知,所以可以寫(xiě)這樣三種情況的處理:
observerable$.subscribe({
next: (v) => {},
error: (err) =>{},
complete: () => {}
});
這些處理邏輯叫做 Observer。
這就是 RxJs 做的事情了。因?yàn)楫惒竭壿嬍菍?duì)某個(gè)事件的響應(yīng),這也叫做響應(yīng)式編程。
剛才我們創(chuàng)建 Observable 是包了一層 Event Listener、callback、Promise,當(dāng)然也可以直接創(chuàng)建這樣一個(gè) Observable 對(duì)象:
比如我們把一系列數(shù)封裝成 Observable:
// 多個(gè)數(shù)據(jù)
const observable$ = Rx.Observable.of(1, 2, 3);
// 數(shù)組中的多個(gè)數(shù)據(jù)
const observable2$ = Rx.Observable.from([1,2,3]);
或者經(jīng)過(guò)一些邏輯邏輯產(chǎn)生一系列數(shù)據(jù):
var observable$ = new Rx.Observable(function (observer) {
observer.next(1);
observer.next(2);
observer.next(3);
setTimeout(() => {
observer.next(4);
observer.complete();
}, 1000);
});
或者這樣:
const observable$ = new Rx.Subject();
observable$.next(1);
observable$.next(2);
這里的區(qū)別是 Subject 是可以在外部調(diào)用 next 來(lái)產(chǎn)生數(shù)據(jù)的,而 new Observable 是在回調(diào)函數(shù)內(nèi)調(diào)用 next 產(chǎn)生數(shù)據(jù)。
我們小結(jié)一下:
就像 JQuery 對(duì) dom 包了一層,然后提供了簡(jiǎn)化 dom 操作的 api 一樣,RxJS 也對(duì)異步邏輯包裝了一層,然后提供了一系列 operator。我們可以把 EventListenr、Promise、callback 等包裝成 Observable(或者自己用 of、from、Subject 等創(chuàng)建 Observable),然后用內(nèi)置的或者自己擴(kuò)展的 oprator 組織處理管道,在管道的末尾用 Observer 接受數(shù)據(jù)、處理錯(cuò)誤。這樣就把異步邏輯的編寫(xiě),轉(zhuǎn)變?yōu)榱瞬僮鞣艿赖慕M織。當(dāng)對(duì)內(nèi)置的 operator 足夠熟練或者自己沉淀了一些 operator 之后,寫(xiě)異步的邏輯速度會(huì)變得很快。
因?yàn)?RxJS 只是對(duì)異步邏輯的封裝,和 Vue、React 等前端框架并不沖突,所以可以很好的結(jié)合在一起。(Angular 甚至默認(rèn)就集成了 RxJS)
比如在 Vue 里面,我們可以把事件用 Subject 封裝成一個(gè) Observable,然后就可以用 RxJS 的操作符來(lái)組織異步邏輯了:
點(diǎn)我
import { Subject } from 'rxjs'
import { debounceTime } from 'rxjs/operators'
export default {
data() {
return {
observable$: new Subject()
}
},
created() {
this.observable$.pipe(debounceTime(500)).subscribe((event) => {
// xxx
})
},
methods: {
clickHandler(event) {
this.observable$.next(event)
}
}
}
在 React 里面也一樣,用 Subject 自己創(chuàng)建個(gè) Observale,就可以把異步邏輯的編寫(xiě)轉(zhuǎn)變?yōu)?operator 的組裝了:
class MyButton extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
this.observable$ = new Rx.Subject();
this.observable$.pipe(
debounceTime(500),
map(() => 1),
scan((total, num) => total + num, 0)
);
this.observable$.subscribe(x => {
this.setState({ count: x })
})
}
render() {
return
}
}
我們用 Subject 創(chuàng)建了個(gè) Observable 對(duì)象,每次點(diǎn)擊都調(diào)用 next 產(chǎn)生一個(gè)數(shù)據(jù),傳入處理管道。
管道我們是用 operator 組織的,先做了 500ms 的截流,然后把值變?yōu)?1,之后計(jì)數(shù)。
處理完之后傳遞給 Observer 的就是累加后的數(shù)值,設(shè)置到 state 即可。
這樣一段節(jié)流 + 計(jì)數(shù)的異步邏輯就寫(xiě)完了,其實(shí)就是組裝了下 operator,這就是 RxJS 的意義。
總結(jié)
用原生的 dom api 進(jìn)行 dom 操作比較繁瑣,所以我們會(huì)使用 JQuery,它把 dom 包了一層,提供了很多方便的內(nèi)置 api,而且還支持通過(guò)插件擴(kuò)展,這樣極大的簡(jiǎn)化了 dom 操作。
除了操作 dom,前端開(kāi)發(fā)還經(jīng)常要寫(xiě)異步邏輯,同樣也需要這樣一個(gè)包一層的庫(kù)來(lái)簡(jiǎn)化,它就是 Rx.js。
Rx.js 把 Event Listener、Promise、callback 等封裝成了 Observable(也可以自己創(chuàng)建),提供了很多操作符 operator(還可以自定義),用它們來(lái)組裝成處理管道(pipe)來(lái)處理異步邏輯,最后傳入 Observer 來(lái)接收數(shù)據(jù)和處理錯(cuò)誤。這樣把異步邏輯的編寫(xiě)轉(zhuǎn)變?yōu)榱?operator 的組裝,把填空題變?yōu)榱诉x擇題,異步邏輯的編寫(xiě)速度和體驗(yàn)自然會(huì)提升很多。
而且,RxJS 是專(zhuān)門(mén)處理異步邏輯的,可以和前端框架很好的結(jié)合在一起使用。
就像用 JQuery 操作 dom 很爽一樣,熟悉了 RxJS 的 operator,用 RxJS 編寫(xiě)(組裝)異步邏輯的體驗(yàn)很非常棒。
分享名稱(chēng):RxJS 之于異步,就像 JQuery 之于Dom
URL網(wǎng)址:http://fisionsoft.com.cn/article/dhopcse.html


咨詢(xún)
建站咨詢(xún)
