本節知識點是對【異步編程】的學習,首先我們來認識幾個概念:
-
什麼是異步和同步?
- 同步的概念:執行一個方法或者功能,在沒得到結果前,其他方法不執行,一定得等當前方法執行完,纔會執行下一步驟;
- 異步的概念:執行一個方法或者功能,不需要等待到當前方法執行完,其他方法也可以執行;
同步比較符合我們常規思維,相對簡單,容易理解接受,異步不會按規定格式(硬編碼順序)按步驟執行,執行無序,相對複雜,當然也就不易理解接受;
-
異步編程的常用方案有哪些?
- Callback 回調函數的方式獲取異步方法的數據,比如:JQuery 的 AJAX(基於XMLHttpRequest對象封裝)就實現的異步編程;
- Promise(ES6)對象獲取異步方法的數據;
- RxJs(第三方庫/Microsoft)獲取異步方法的數據(ng 重度使用,比如:【HttpClient】對象);
-
爲什麼選擇【RxJs】?
爲什麼在 ng 中會使用 RxJs,並且基於此封裝實現了【HttpClient】對象,接下來我們對上面提出的常用的異步編程的幾種方案舉例對比,由於我們整個過程中都是藉助ES中的內置函數實現分別是 setInterval() & setTimeout();
- setInterval() 會週期性的重複執行;
- setTimeout() 定時延遲執行,只執行一次;
- CLI 創建服務【request】;
ng generate service services/request
- 創建組件【async】;
ng generate component components/async
在組件中引入服務並註冊聲明;
//引入服務RequestService
import { RequestService } from '../../services/request.service';
//引入rxjs工具函數,map & filter
import { map,filter } from 'rxjs/operators';
//在組件的構造函數DI註冊服務request
constructor(public request:RequestService) { }
以上我們就把基礎環境準備好了,接下來我們就實現以下幾種方案:
- Callback 回調函數方式實現異步編程;
//【request】服務中編寫
//1.Callback回調函數
getCallbackData(cb:Function):void{
//延遲1s執行
setTimeout(() => {
let userName:string = '1 => 1s後執行,CallbackData => 張三';
cb(userName);
}, 1000); //單位ms =》 1s = 1000ms
console.log('2 => Callback回調函數'); //此行代碼被執行
}
//在組件【async】的聲明周期函數【ngOnInit】中使用上面服務中編寫的方法
//生命週期函數,首次載入/加載或數據初始化(請求數據)使用
ngOnInit() {
//1.callback獲取異步方法的數據
this.request.getCallbackData((data: any) => {
console.log(data);
});
}
- Promise(ES6)對象獲取異步方法的數據;
//【request】服務中編寫
//2.Promise/ES6
getPromiseData(): Promise<any>{
return new Promise<any>((resolve)=>{
setTimeout(() =>{
let userName:string = '2s後執行,PromiseData => 張三';
resolve(userName);
}, 2000);
console.log('2 => Promise'); //此行代碼不會被執行
});
}
//在組件【async】的聲明周期函數【ngOnInit】中使用上面服務中編寫的方法
//生命週期函數,首次載入/加載或數據初始化(請求數據)使用
ngOnInit() {
//2.Promise獲取異步方法的數據
let promiseData = this.request.getPromiseData();
promiseData.then((data)=>{
console.log(data);
});
}
- RxJs(第三方庫/Microsoft)獲取異步方法的數據;
//【request】服務中編寫
//3.RxJs/Microsoft
getRxJsData(): Observable<any>{
return new Observable<any>((observer)=>{
setTimeout(() =>{
let userName:string = '3s後執行,RxJsData => 張三';
observer.next(userName);
//observer.error('RxJsData => Error');
}, 3000);
});
}
//在組件【async】的聲明周期函數【ngOnInit】中使用上面服務中編寫的方法
//生命週期函數,首次載入/加載或數據初始化(請求數據)使用
ngOnInit() {
//3.rxjs獲取異步方法的數據
let rxjsData = this.request.getRxJsData();
//3.1【訂閱|subscribe】
rxjsData.subscribe((data)=>{
console.log(data);
});
//3.2繼續上面的方式演示【取消訂閱|unsubscribe】
let testUnsubscribe= rxjsData.subscribe((data)=>{
console.log(data);
});
//過1s後撤回上面的方法, testUnsubscribe 接收subscribe返回的信息
setTimeout(() =>{
testUnsubscribe.unsubscribe(); //unsubscribe 取消訂閱
}, 1000);
}
- 對比 Pomise 對象和 RxJs 對象是否能執行多次方法調用;
//【request】服務中編寫
//4.Promise多次執行(沒有這個能力,只會執行一次)
getPromiseIntarvalData(): Promise<any>{
return new Promise<any>((resolve)=>{
setInterval(() =>{
let userName:string = '定時輪詢,每1s執行一次,PromiseData => 張三';
resolve(userName);
}, 1000);
});
}
//5.rxjs多次執行
getRxJsIntervalData(): Observable<any>{
return new Observable<any>((observer)=>{
setInterval(() =>{
let userName:string = '定時輪詢,每1s執行一次,RxJsData => 張三';
observer.next(userName);
//observer.error('RxJsData => Error');
}, 1000);
});
}
//在組件【async】的聲明周期函數【ngOnInit】中使用上面服務中編寫的方法
//生命週期函數,首次載入/加載或數據初始化(請求數據)使用
ngOnInit() {
//注意4和5演示的時候注意先註釋,方便看演示結果
//4.Promise執行多次(沒有這個能力)
let promiseIntervalData = this.request.getPromiseIntarvalData();
promiseIntervalData.then((data)=>{
console.log(data);
});
//5.rxjs執行多次,類似爬蟲
let rxjsIntervalData = this.request.getRxJsIntervalData();
rxjsIntervalData.subscribe((data)=>{
console.log(data);
});
}
- RxJs 對象工具函數【map & filter】對返回的數據進行處理;
//【request】服務中編寫
//6.rxjs 工具函數【map & filter】對返回的數據進行處理
let rxjsIntervalNum = this.request.getRxJsIntervalNum();
rxjsIntervalNum.subscribe((data)=>{
console.log(data);
});
//在組件【async】的聲明周期函數【ngOnInit】中使用上面服務中編寫的方法
//生命週期函數,首次載入/加載或數據初始化(請求數據)使用
ngOnInit() {
//6.rxjs 工具函數map & filter 對返回的數據進行處理
let rxjsIntervalNum = this.request.getRxJsIntervalNum();
rxjsIntervalNum.subscribe((data)=>{
console.log(data);
});
/*
//filter單個使用
rxjsIntervalNum.pipe( //pipe 管道
//過濾count爲偶數的數據
filter((value) => {
if (value % 2 ==0) {
return true;
}
})
).subscribe((data)=>{
console.log(data);
});
*/
/*
//map單個使用
rxjsIntervalNum.pipe( //pipe 管道
//對結果數據處理後再返回
map((value) => {
if (value % 2 ==0) {
return value * value;
}
})
).subscribe((data)=>{
console.log(data);
});
*/
//map & filter 聯合使用
rxjsIntervalNum.pipe( //pipe 管道,可以有序的打包多個方法一併執行
//1.先按條件過濾
filter((value) => {
if (value % 2 ==0) {
return true;
}
}),
//2.對過濾後的數據進行處理後再返回
map((value) => {
if (value % 2 ==0) {
return value * value;
}
})
).subscribe((data)=>{
console.log(data);
});
}
- Promise(ES6)和 RxJs 對比:
- Promise 通過【then】獲取異步方法數據,RxJs通過【subscribe】獲取異步方法數據;
- Promise執行方法後無法撤銷,而RxJs可以實現訂閱【subscribe】和取消訂閱【unsubscribe】;
- Promise只能執行一次(沒有這個能力),RxJs可以執行多次(類似定向任務/輪詢獲取數據/爬蟲);
- RxJs 可以延遲執行;