From 58a6bbd88b4fc486506477fca8d65f6fb5801b93 Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 30 Jul 2020 17:01:13 +0700 Subject: [PATCH] Subscription refactoring to increase performance. --- .../blockchain-blocks.component.ts | 30 +++++--- .../blockchain/blockchain.component.html | 4 +- .../blockchain/blockchain.component.ts | 21 ++---- .../fee-distribution-graph.component.ts | 5 +- .../mempool-blocks.component.html | 2 +- .../mempool-blocks.component.ts | 68 +++++++++++-------- .../transaction/transaction.component.ts | 3 +- .../tx-fee-rating/tx-fee-rating.component.ts | 16 ++++- 8 files changed, 89 insertions(+), 60 deletions(-) diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 57e9a917a..9f63da176 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -1,24 +1,27 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; import { Subscription } from 'rxjs'; import { Block } from 'src/app/interfaces/electrs.interface'; import { StateService } from 'src/app/services/state.service'; import { Router } from '@angular/router'; -import { AudioService } from 'src/app/services/audio.service'; import { env } from 'src/app/app.constants'; @Component({ selector: 'app-blockchain-blocks', templateUrl: './blockchain-blocks.component.html', - styleUrls: ['./blockchain-blocks.component.scss'] + styleUrls: ['./blockchain-blocks.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class BlockchainBlocksComponent implements OnInit, OnDestroy { network = ''; blocks: Block[] = []; markHeight: number; blocksSubscription: Subscription; + networkSubscriotion: Subscription; + tabHiddenSubscription: Subscription; + markBlockSubscription: Subscription; blockStyles = []; interval: any; - tabHidden = true; + tabHidden = false; arrowVisible = false; arrowLeftPx = 30; @@ -35,11 +38,12 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { constructor( private stateService: StateService, private router: Router, + private cd: ChangeDetectorRef, ) { } ngOnInit() { - this.stateService.networkChanged$.subscribe((network) => this.network = network); - this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden); + this.networkSubscriotion = this.stateService.networkChanged$.subscribe((network) => this.network = network); + this.tabHiddenSubscription = this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden); this.blocksSubscription = this.stateService.blocks$ .subscribe(([block, txConfirmed]) => { @@ -71,20 +75,23 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { setTimeout(() => { this.blockStyles = []; this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b))); + this.cd.markForCheck(); }, 50); if (this.blocks.length === env.KEEP_BLOCKS_AMOUNT) { this.blocksFilled = true; } + this.cd.markForCheck(); }); - this.stateService.markBlock$ + this.markBlockSubscription = this.stateService.markBlock$ .subscribe((state) => { this.markHeight = undefined; if (state.blockHeight) { this.markHeight = state.blockHeight; } this.moveArrowToPosition(false); + this.cd.markForCheck(); }); this.stateService.keyNavigation$.subscribe((event) => { @@ -112,6 +119,9 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { ngOnDestroy() { this.blocksSubscription.unsubscribe(); + this.networkSubscriotion.unsubscribe(); + this.tabHiddenSubscription.unsubscribe(); + this.markBlockSubscription.unsubscribe(); clearInterval(this.interval); } @@ -131,11 +141,15 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy { setTimeout(() => { this.transition = '2s'; this.arrowLeftPx = blockindex * 155 + 30; + this.cd.markForCheck(); }, 50); } else { this.arrowLeftPx = blockindex * 155 + 30; if (!animate) { - setTimeout(() => this.transition = '2s'); + setTimeout(() => { + this.transition = '2s'; + this.cd.markForCheck(); + }); } } } diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 1470243ce..7bfd20bc8 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,12 +1,12 @@
-
+
-
+

Waiting for blocks...

diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index 592355bea..73dc09768 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -1,28 +1,21 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy } from '@angular/core'; import { StateService } from 'src/app/services/state.service'; -import { Subscription } from 'rxjs'; +import { Subscription, Observable } from 'rxjs'; @Component({ selector: 'app-blockchain', templateUrl: './blockchain.component.html', - styleUrls: ['./blockchain.component.scss'] + styleUrls: ['./blockchain.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class BlockchainComponent implements OnInit, OnDestroy { - txTrackingLoading = false; - txShowTxNotFound = false; - isLoading = true; - subscription: Subscription; +export class BlockchainComponent implements OnInit { + isLoading$: Observable; constructor( private stateService: StateService, ) {} ngOnInit() { - this.subscription = this.stateService.isLoadingWebSocket$ - .subscribe((isLoading) => this.isLoading = isLoading); - } - - ngOnDestroy() { - this.subscription.unsubscribe(); + this.isLoading$ = this.stateService.isLoadingWebSocket$; } } diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts index db3dbb734..277baf675 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts @@ -1,10 +1,11 @@ -import { Component, Input, OnChanges } from '@angular/core'; +import { Component, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core'; import * as Chartist from 'chartist'; @Component({ selector: 'app-fee-distribution-graph', templateUrl: './fee-distribution-graph.component.html', - styleUrls: ['./fee-distribution-graph.component.scss'] + styleUrls: ['./fee-distribution-graph.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class FeeDistributionGraphComponent implements OnChanges { @Input() feeRange; diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index 473284ca3..165a749ee 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -1,6 +1,6 @@
- +
 
diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 320ac6a9d..4e327eced 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -1,27 +1,32 @@ -import { Component, OnInit, OnDestroy, HostListener } from '@angular/core'; -import { Subscription, pipe } from 'rxjs'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Subscription, Observable, fromEvent, merge, of } from 'rxjs'; import { MempoolBlock } from 'src/app/interfaces/websocket.interface'; import { StateService } from 'src/app/services/state.service'; import { Router } from '@angular/router'; -import { take, map } from 'rxjs/operators'; +import { take, map, switchMap } from 'rxjs/operators'; import { feeLevels, mempoolFeeColors } from 'src/app/app.constants'; @Component({ selector: 'app-mempool-blocks', templateUrl: './mempool-blocks.component.html', styleUrls: ['./mempool-blocks.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class MempoolBlocksComponent implements OnInit, OnDestroy { mempoolBlocks: MempoolBlock[]; + mempoolBlocks$: Observable; + mempoolBlocksFull: MempoolBlock[]; mempoolBlockStyles = []; - mempoolBlocksSubscription: Subscription; + markBlocksSubscription: Subscription; + blockSubscription: Subscription; + networkSubscription: Subscription; network = ''; blockWidth = 125; blockPadding = 30; arrowVisible = false; - tabHidden = true; + tabHidden = false; rightPosition = 0; transition = '2s'; @@ -36,21 +41,25 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { constructor( private router: Router, private stateService: StateService, + private cd: ChangeDetectorRef, ) { } ngOnInit() { this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden); - this.mempoolBlocksSubscription = this.stateService.mempoolBlocks$ - .pipe( - map((blocks) => { - if (!blocks.length) { - return [{ index: 0, blockSize: 0, blockVSize: 0, feeRange: [0, 0], medianFee: 0, nTx: 0, totalFees: 0 }]; - } - return blocks; - }), - ) - .subscribe((blocks) => { + this.mempoolBlocks$ = merge( + of(true), + fromEvent(window, 'resize') + ) + .pipe( + switchMap(() => this.stateService.mempoolBlocks$), + map((blocks) => { + if (!blocks.length) { + return [{ index: 0, blockSize: 0, blockVSize: 0, feeRange: [0, 0], medianFee: 0, nTx: 0, totalFees: 0 }]; + } + return blocks; + }), + map((blocks) => { blocks.forEach((block, i) => { block.index = this.blockIndex + i; }); @@ -59,9 +68,11 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(stringifiedBlocks)); this.updateMempoolBlockStyles(); this.calculateTransactionPosition(); - }); + return this.mempoolBlocks; + }) + ); - this.stateService.markBlock$ + this.markBlocksSubscription = this.stateService.markBlock$ .subscribe((state) => { this.markIndex = undefined; this.txFeePerVSize = undefined; @@ -72,16 +83,17 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.txFeePerVSize = state.txFeePerVSize; } this.calculateTransactionPosition(); + this.cd.markForCheck(); }); - this.stateService.blocks$ + this.blockSubscription = this.stateService.blocks$ .subscribe(([block]) => { if (block.matchRate >= 66 && !this.tabHidden) { this.blockIndex++; } }); - this.stateService.networkChanged$ + this.networkSubscription = this.stateService.networkChanged$ .subscribe((network) => this.network = network); this.stateService.keyNavigation$.subscribe((event) => { @@ -109,15 +121,11 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { }); } - @HostListener('window:resize', ['$event']) - onResize() { - if (this.mempoolBlocks && this.mempoolBlocks.length) { - this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(JSON.stringify(this.mempoolBlocksFull))); - } - } - ngOnDestroy() { - this.mempoolBlocksSubscription.unsubscribe(); + this.markBlocksSubscription.unsubscribe(); + this.blockSubscription.unsubscribe(); + this.networkSubscription.unsubscribe(); + clearTimeout(this.resetTransitionTimeout); } trackByFn(index: number, block: MempoolBlock) { @@ -192,7 +200,11 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.transition = 'inherit'; this.rightPosition = this.markIndex * (this.blockWidth + this.blockPadding) + 0.5 * this.blockWidth; this.arrowVisible = true; - this.resetTransitionTimeout = window.setTimeout(() => this.transition = '2s', 100); + + this.resetTransitionTimeout = window.setTimeout(() => { + this.transition = '2s'; + this.cd.markForCheck(); + }, 100); return; } diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 259a003c5..1fe8ddf9b 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { ActivatedRoute, ParamMap } from '@angular/router'; -import { switchMap, filter, take, catchError, flatMap } from 'rxjs/operators'; +import { switchMap, filter, catchError } from 'rxjs/operators'; import { Transaction, Block } from '../../interfaces/electrs.interface'; import { of, merge, Subscription, Observable } from 'rxjs'; import { StateService } from '../../services/state.service'; @@ -9,7 +9,6 @@ import { WebsocketService } from '../../services/websocket.service'; import { AudioService } from 'src/app/services/audio.service'; import { ApiService } from 'src/app/services/api.service'; import { SeoService } from 'src/app/services/seo.service'; -import { BisqTransaction } from 'src/app/bisq/bisq.interfaces'; @Component({ selector: 'app-transaction', diff --git a/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts b/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts index 32ca9b258..639822dda 100644 --- a/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts +++ b/frontend/src/app/components/tx-fee-rating/tx-fee-rating.component.ts @@ -1,15 +1,19 @@ -import { Component, ChangeDetectionStrategy, OnChanges, Input, OnInit, ChangeDetectorRef } from '@angular/core'; +import { Component, ChangeDetectionStrategy, OnChanges, Input, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { Transaction, Block } from 'src/app/interfaces/electrs.interface'; import { StateService } from 'src/app/services/state.service'; +import { Subscription } from 'rxjs'; @Component({ selector: 'app-tx-fee-rating', templateUrl: './tx-fee-rating.component.html', styleUrls: ['./tx-fee-rating.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class TxFeeRatingComponent implements OnInit, OnChanges { +export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy { @Input() tx: Transaction; + blocksSubscription: Subscription; + medianFeeNeeded: number; overpaidTimes: number; feeRating: number; @@ -18,13 +22,15 @@ export class TxFeeRatingComponent implements OnInit, OnChanges { constructor( private stateService: StateService, + private cd: ChangeDetectorRef, ) { } ngOnInit() { - this.stateService.blocks$.subscribe(([block]) => { + this.blocksSubscription = this.stateService.blocks$.subscribe(([block]) => { this.blocks.push(block); if (this.tx.status.confirmed && this.tx.status.block_height === block.height) { this.calculateRatings(block); + this.cd.markForCheck(); } }); } @@ -41,6 +47,10 @@ export class TxFeeRatingComponent implements OnInit, OnChanges { } } + ngOnDestroy() { + this.blocksSubscription.unsubscribe(); + } + calculateRatings(block: Block) { const feePervByte = this.tx.fee / (this.tx.weight / 4); this.medianFeeNeeded = Math.round(block.feeRange[Math.round(block.feeRange.length * 0.5)]);