aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-07-27 18:18:20 +0800
committercrupest <crupest@outlook.com>2020-07-27 18:18:20 +0800
commit0863e0d139f12c444a2a01bb899bc3148c52e7ce (patch)
treeb1f7833d3ccf5b7419c824ea2d5b34e546d66755
parentc10218d8d5ec01ae29c0b2880a8d6af371a562e5 (diff)
downloadtimeline-0863e0d139f12c444a2a01bb899bc3148c52e7ce.tar.gz
timeline-0863e0d139f12c444a2a01bb899bc3148c52e7ce.tar.bz2
timeline-0863e0d139f12c444a2a01bb899bc3148c52e7ce.zip
Refactor SubscriptionHub.
-rw-r--r--Timeline/ClientApp/src/app/data/SubscriptionHub.ts43
-rw-r--r--Timeline/ClientApp/src/app/data/timeline.ts15
-rw-r--r--Timeline/ClientApp/src/app/data/user.ts14
3 files changed, 42 insertions, 30 deletions
diff --git a/Timeline/ClientApp/src/app/data/SubscriptionHub.ts b/Timeline/ClientApp/src/app/data/SubscriptionHub.ts
index 92a54bc7..f09cd9f8 100644
--- a/Timeline/ClientApp/src/app/data/SubscriptionHub.ts
+++ b/Timeline/ClientApp/src/app/data/SubscriptionHub.ts
@@ -8,7 +8,6 @@
// There might be some bugs, especially memory leaks and in asynchronization codes.
import * as rxjs from 'rxjs';
-import { filter } from 'rxjs/operators';
export type Subscriber<TData> = (data: TData) => void;
@@ -26,25 +25,25 @@ class SubscriptionToken {
class SubscriptionLine<TData> {
private _lastDataPromise: Promise<TData>;
- private _dataSubject = new rxjs.BehaviorSubject<TData | undefined>(undefined);
- private _data$: rxjs.Observable<TData> = this._dataSubject.pipe(
- filter((d) => d !== undefined)
- ) as rxjs.Observable<TData>;
+ private _dataSubject: rxjs.BehaviorSubject<TData>;
private _refCount = 0;
constructor(
- _creator: () => Promise<TData>,
+ defaultValueProvider: () => TData,
+ setup: ((old: TData) => Promise<TData>) | undefined,
private _destroyer: ((data: TData) => void) | undefined,
private _onZeroRef: (self: SubscriptionLine<TData>) => void
) {
- this._lastDataPromise = _creator().then((data) => {
- this._dataSubject.next(data);
- return data;
- });
+ const initValue = defaultValueProvider();
+ this._lastDataPromise = Promise.resolve(initValue);
+ this._dataSubject = new rxjs.BehaviorSubject<TData>(initValue);
+ if (setup != null) {
+ this.next(setup);
+ }
}
subscribe(subscriber: Subscriber<TData>): SubscriptionToken {
- const subscription = this._data$.subscribe(subscriber);
+ const subscription = this._dataSubject.subscribe(subscriber);
this._refCount += 1;
return new SubscriptionToken(subscription);
}
@@ -53,11 +52,12 @@ class SubscriptionLine<TData> {
token._subscription.unsubscribe();
this._refCount -= 1;
if (this._refCount === 0) {
- void this._lastDataPromise.then((data) => {
- if (this._destroyer != null && data !== undefined) {
- this._destroyer(data);
- }
- });
+ const { _destroyer: destroyer } = this;
+ if (destroyer != null) {
+ void this._lastDataPromise.then((data) => {
+ destroyer(data);
+ });
+ }
this._onZeroRef(this);
}
}
@@ -67,7 +67,7 @@ class SubscriptionLine<TData> {
.then((old) => updator(old))
.then((data) => {
const last = this._dataSubject.value;
- if (this._destroyer != null && last !== undefined) {
+ if (this._destroyer != null) {
this._destroyer(last);
}
this._dataSubject.next(data);
@@ -82,9 +82,11 @@ export interface ISubscriptionHub<TKey, TData> {
export class SubscriptionHub<TKey, TData>
implements ISubscriptionHub<TKey, TData> {
+ // If setup is set, update is called with setup immediately after setting default value.
constructor(
public keyToString: (key: TKey) => string,
- public creator: (key: TKey) => Promise<TData>,
+ public defaultValueProvider: (key: TKey) => TData,
+ public setup?: (key: TKey) => Promise<TData>,
public destroyer?: (key: TKey, data: TData) => void
) {}
@@ -95,9 +97,10 @@ export class SubscriptionHub<TKey, TData>
const line = (() => {
const savedLine = this.subscriptionLineMap.get(keyString);
if (savedLine == null) {
- const { destroyer } = this;
+ const { setup, destroyer } = this;
const newLine = new SubscriptionLine<TData>(
- () => this.creator(key),
+ () => this.defaultValueProvider(key),
+ setup != null ? () => setup(key) : undefined,
destroyer != null
? (data) => {
destroyer(key, data);
diff --git a/Timeline/ClientApp/src/app/data/timeline.ts b/Timeline/ClientApp/src/app/data/timeline.ts
index f2c3fdda..7ade8f56 100644
--- a/Timeline/ClientApp/src/app/data/timeline.ts
+++ b/Timeline/ClientApp/src/app/data/timeline.ts
@@ -131,6 +131,7 @@ export class TimelineService {
TimelinePostInfo[]
>(
(key) => key,
+ () => [],
async (key) => {
return (
await getHttpTimelineClient().listPost(
@@ -148,8 +149,12 @@ export class TimelineService {
return this._postListSubscriptionHub;
}
- private _postDataSubscriptionHub = new SubscriptionHub<PostKey, BlobWithUrl>(
+ private _postDataSubscriptionHub = new SubscriptionHub<
+ PostKey,
+ BlobWithUrl | null
+ >(
(key) => `${key.timelineName}/${key.postId}`,
+ () => null,
async (key) => {
const blob = (
await getHttpTimelineClient().getPostData(
@@ -165,11 +170,11 @@ export class TimelineService {
};
},
(_key, data) => {
- URL.revokeObjectURL(data.url);
+ if (data != null) URL.revokeObjectURL(data.url);
}
);
- get postDataHub(): ISubscriptionHub<PostKey, BlobWithUrl> {
+ get postDataHub(): ISubscriptionHub<PostKey, BlobWithUrl | null> {
return this._postDataSubscriptionHub;
}
@@ -275,8 +280,8 @@ export function usePostDataUrl(
timelineName,
postId,
},
- ({ url }) => {
- setUrl(url);
+ (data) => {
+ setUrl(data?.url);
}
);
return () => {
diff --git a/Timeline/ClientApp/src/app/data/user.ts b/Timeline/ClientApp/src/app/data/user.ts
index 1be5cd3e..dec9929f 100644
--- a/Timeline/ClientApp/src/app/data/user.ts
+++ b/Timeline/ClientApp/src/app/data/user.ts
@@ -233,8 +233,12 @@ export class UserNotExistError extends Error {}
export type AvatarInfo = BlobWithUrl;
export class UserInfoService {
- private _avatarSubscriptionHub = new SubscriptionHub<string, AvatarInfo>(
+ private _avatarSubscriptionHub = new SubscriptionHub<
+ string,
+ AvatarInfo | null
+ >(
(key) => key,
+ () => null,
async (key) => {
const blob = (await getHttpUserClient().getAvatar(key)).data;
const url = URL.createObjectURL(blob);
@@ -244,7 +248,7 @@ export class UserInfoService {
};
},
(_key, data) => {
- URL.revokeObjectURL(data.url);
+ if (data != null) URL.revokeObjectURL(data.url);
}
);
@@ -265,7 +269,7 @@ export class UserInfoService {
);
}
- get avatarHub(): ISubscriptionHub<string, AvatarInfo> {
+ get avatarHub(): ISubscriptionHub<string, AvatarInfo | null> {
return this._avatarSubscriptionHub;
}
}
@@ -284,8 +288,8 @@ export function useAvatarUrl(username?: string): string | undefined {
const subscription = userInfoService.avatarHub.subscribe(
username,
- ({ url }) => {
- setAvatarUrl(url);
+ (info) => {
+ setAvatarUrl(info?.url);
}
);
return () => {