Skip to content

Commit 45c2dd0

Browse files
authored
Merge 1dbcffe into d095ad3
2 parents d095ad3 + 1dbcffe commit 45c2dd0

File tree

4 files changed

+105
-1
lines changed

4 files changed

+105
-1
lines changed

.changeset/early-nails-hope.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@firebase/component": minor
3+
---
4+
5+
Support onInit callback in provider

packages/component/src/provider.test.ts

+57
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,63 @@ describe('Provider', () => {
143143
expect((provider as any).instances.size).to.equal(1);
144144
return expect(servicePromise).to.eventually.deep.equal({ test: true });
145145
});
146+
147+
it('invokes onInit callbacks synchronously', () => {
148+
provider.setComponent(
149+
getFakeComponent(
150+
'test',
151+
() => ({ test: true }),
152+
false,
153+
InstantiationMode.EXPLICIT
154+
)
155+
);
156+
const callback1 = fake();
157+
provider.onInit(callback1);
158+
159+
provider.initialize();
160+
expect(callback1).to.have.been.calledOnce;
161+
});
162+
});
163+
164+
describe('onInit', () => {
165+
it('registers onInit callbacks', () => {
166+
provider.setComponent(
167+
getFakeComponent(
168+
'test',
169+
() => ({ test: true }),
170+
false,
171+
InstantiationMode.EXPLICIT
172+
)
173+
);
174+
const callback1 = fake();
175+
const callback2 = fake();
176+
provider.onInit(callback1);
177+
provider.onInit(callback2);
178+
179+
provider.initialize();
180+
expect(callback1).to.have.been.calledOnce;
181+
expect(callback2).to.have.been.calledOnce;
182+
});
183+
184+
it('returns a function to unregister the callback', () => {
185+
provider.setComponent(
186+
getFakeComponent(
187+
'test',
188+
() => ({ test: true }),
189+
false,
190+
InstantiationMode.EXPLICIT
191+
)
192+
);
193+
const callback1 = fake();
194+
const callback2 = fake();
195+
provider.onInit(callback1);
196+
const unregsiter = provider.onInit(callback2);
197+
unregsiter();
198+
199+
provider.initialize();
200+
expect(callback1).to.have.been.calledOnce;
201+
expect(callback2).to.not.have.been.called;
202+
});
146203
});
147204

148205
describe('Provider (multipleInstances = false)', () => {

packages/component/src/provider.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
InitializeOptions,
2323
InstantiationMode,
2424
Name,
25-
NameServiceMapping
25+
NameServiceMapping,
26+
OnInitCallBack
2627
} from './types';
2728
import { Component } from './component';
2829

@@ -37,6 +38,7 @@ export class Provider<T extends Name> {
3738
string,
3839
Deferred<NameServiceMapping[T]>
3940
> = new Map();
41+
private onInitCallbacks: Set<OnInitCallBack<T>> = new Set();
4042

4143
constructor(
4244
private readonly name: T,
@@ -250,9 +252,44 @@ export class Provider<T extends Name> {
250252
instanceDeferred.resolve(instance);
251253
}
252254
}
255+
256+
this.invokeOnInitCallbacks(instance, normalizedIdentifier);
257+
253258
return instance;
254259
}
255260

261+
/**
262+
*
263+
* @param callback - a function that will be invoked after the provider has been initialized by calling provider.initialize().
264+
* The function is invoked SYNCHRONOUSLY, so it should not execute any longrunning tasks in order to not block the program.
265+
*
266+
* @returns a function to unregister the callback
267+
*/
268+
onInit(callback: OnInitCallBack<T>): () => void {
269+
this.onInitCallbacks.add(callback);
270+
271+
return () => {
272+
this.onInitCallbacks.delete(callback);
273+
};
274+
}
275+
276+
/**
277+
* Invoke onInit callbacks synchronously
278+
* @param instance the service instance`
279+
*/
280+
private invokeOnInitCallbacks(
281+
instance: NameServiceMapping[T],
282+
identifier: string
283+
): void {
284+
for (const callback of this.onInitCallbacks) {
285+
try {
286+
callback(instance, identifier);
287+
} catch {
288+
// ignore errors in the onInit callback
289+
}
290+
}
291+
}
292+
256293
private getOrInitializeService({
257294
instanceIdentifier,
258295
options = {}

packages/component/src/types.ts

+5
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,8 @@ export interface NameServiceMapping {}
7575

7676
export type Name = keyof NameServiceMapping;
7777
export type Service = NameServiceMapping[Name];
78+
79+
export type OnInitCallBack<T extends Name> = (
80+
instance: NameServiceMapping[T],
81+
identifier: string
82+
) => void;

0 commit comments

Comments
 (0)