響應式編程
以下概念介紹,基於 node v10.16.3 版本進行。不滿足條件的,請移步 google or 度娘。
概念介紹
const a = 1,b = 2;
const c = a b;
響應式編程,當a,b再次變化時,c會再次做出修改。
背景
- RxJS是一個用於使用Observables進行響應式編程的庫
- 可簡化編寫異步或基於回調的代碼
本地環境搭建
- node
- npm script
- rollup
npm install --global rollup
- rxjs
npm install rxjs
- es6 語法,利用tree-shaking ,縮減代碼
使用
hello-world 之123
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
of(1,2,3).subscribe(res => {
console.log(res);
});
rollup打包→ bundle.js → node bundle.js,連續輸出123
rollup main.js --file bundle.js --format cjs
'use strict';
var rxjs = require('rxjs');
require('rxjs/operators');
rxjs.of(1,2,3).subscribe(res => {
console.log(res);
});
優化rollup配置
創建rollup.config.js
export default {
input: 'main.js',
output: {
file: 'bundle.js',
format: 'cjs'
}
};
rollup -c rollup.config.js
npm script支持
package.json
{
"name": "rxjs-demo",
"version": "1.0.0",
"description": "",
"main": "test.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build":"rollup -c", // 默認配置 rollup --config rollup.config.js
"start":"npm run build && node bundle.js" // && 是繼發,& 是併發
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"rxjs": "^6.5.3"
}
}
最終的運行如下:
npm start
Rxjs讀取package.json字段version
// install plugin
npm install --save-dev rollup-plugin-json
// rollup.config.js
import json from 'rollup-plugin-json';
export default {
input: 'main.js',
output: {
file: 'bundle.js',
format: 'cjs'
},
plugins:[json()]
};
// main.js
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
of(1,2,3,version).subscribe(res => {
console.log(res);
});
pipe管道在輸出前修改數據
import { of } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
of(1,2,3,version).pipe(map(item => item ' through pipe use map'))
.subscribe(res => {
console.log(res);
});
用Observable改寫of
其中,可以看到observable屬於異步執行。
import { of,Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
//through pipe
// of(1,2,3,version).pipe(map(item => item ' through pipe use map'))
// .subscribe(res => {
// console.log(res);
// });
console.log("before observable....");
const publisher$ = new Observable(suber => {
console.log("in observable....");
suber.next(1);
suber.next(2);
suber.next(3);
suber.next(version);
});
console.log("after observable....");
publisher$.pipe(map(item => item ' through pipe use map')).subscribe(res => {
console.log(res);
});
subscribe訂閱幾次,通知執行幾次,而不是僅消費一次
console.log("before observable....");
const publisher$ = new Observable(suber => {
console.log("in observable....");
suber.next(1);
suber.next(2);
suber.next(3);
suber.next(version);
});
console.log("after observable....");
publisher$.pipe(map(item => item ' through pipe use map')).subscribe(res => {
console.log(res);
});
publisher$.subscribe(res => {
console.log("subscribe second..." res);
});
hot subscribe - 與時間先後有關,訂閱內容差
import { of,Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
let count = 0;
console.log("before observable....");
const publisher$ = new Observable(suber => {
console.log("in observable....");
setInterval(() => {
count ;
suber.next(count);
}, 100);
});
console.log("after observable....");
publisher$.pipe(map(item => 'first ...' item)).subscribe(res => {
console.log(res);
});
setTimeout(() => {
const publisher2$ = new Observable(suber => {
setInterval(() => {
suber.next(count);
}, 100);
});
publisher2$.subscribe(res => {
console.log("second ..." res);
});
}, 1000);
cold subscribe -- 時間先後無關,內容無差異
import { of,Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
console.log("before observable....");
const publisher$ = new Observable(suber => {
console.log("in observable....");
setInterval(() => {
let count = 0;
count ;
suber.next(count);
}, 100);
});
console.log("after observable....");
publisher$.pipe(map(item => 'first ...' item)).subscribe(res => {
console.log(res);
});
setTimeout(() => {
const publisher2$ = new Observable(suber => {
setInterval(() => {
let count = 0;
count ;
suber.next(count);
}, 100);
});
publisher2$.subscribe(res => {
console.log("second ..." res);
});
}, 1000);
observable狀態終止
import { of,Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
const publiser$ = new Observable(suber => {
suber.next(1);
suber.next(2);
suber.next(3);
suber.next(version);
// suber.complete();
suber.error();
});
publiser$.subscribe({
next:res => {
console.log(`next ...${res}`);
},
complete:() => {
console.log("complete done....");
},
error: () => {
console.log("error occur....");
}
});
停止訂閱,釋放資源,但狀態沒有終止
import { of,Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
const publiser$ = new Observable(suber => {
let count = 0;
const timer = setInterval(() => {
suber.next(count);
count ;
},400);
//suber.next(1);
// suber.complete();
// suber.error();
return {
unsubscribe:() => {
console.log("stop push data....");
clearInterval(timer);
}
}
});
const unsuber = publiser$.subscribe({
next:res => {
console.log(`next ...${res}`);
},
complete:() => {
console.log("complete done....");
},
error: () => {
console.log("error occur....");
}
});
setTimeout(() => {
unsuber.unsubscribe();
},2000);
利用rxjs自帶操作符優化上述的取消訂閱
import { of,Observable, interval } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
const publiser$ = interval(400);
const unsuber = publiser$.subscribe({
next:res => {
console.log(`next ...${res}`);
},
complete:() => {
console.log("complete done....");
},
error: () => {
console.log("error occur....");
}
});
setTimeout(() => {
unsuber.unsubscribe();
},2000);
雙重身份的SubJect
import { of,Observable, interval,Subject } from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
const sub = new Subject();
sub.pipe(map(res => 'first ...' res)).subscribe((res) => {
console.log("sub one...",res);
});
sub.subscribe({
next:(res) => {
console.log(`second...${res}`);
}
});
sub.next(1);
sub.next(2);
import { of,Observable, interval,Subject ,from} from 'rxjs';
import { map } from 'rxjs/operators';
import { version } from './package.json';
const sub = new Subject();
sub.pipe(map(res => 'first ...' res)).subscribe((res) => {
console.log("sub one...",res);
});
sub.subscribe({
next:(res) => {
console.log(`second...${res}`);
}
});
// sub.next(1);
// sub.next(2);
const publisher$ = from([1,2,3]);
publisher$.subscribe(sub);
參考文獻
RxJS
RxJS 操作符
阮一峯的網絡日誌 npm scripts 使用指南
本文作者:前端首席體驗師(CheongHu)
聯繫郵箱:[email protected]