Return 在执行任务时可观察 - Firebase 函数
Return observable while doing task - Firebase Functions
我的 Firebase Cloud Functions 中有一个函数需要 运行 抓取任务。当函数正在抓取 public 网站时,我需要 return 向消费者反馈进度。 (例如,“现在是 10%”、“现在是 30%”等)。
我想使用 Observables 但我得到了奇怪的结果,因为抓取函数是异步的,但它应该 return 立即观察到。
这是我的 Firebase 函数后端的简化代码:
exports.scrapeFunction = functions.region('europe-west2').https.onCall((data) => {
const res$ = new BehaviorSubject<Response>({
completion: 0,
completionMsg: 'One moment...',
error: undefined,
user: undefined,
});
scrape(data.id, res$);
return res$.asObservable();
});
const scrape = async (id: number, res$: BehaviorSubject<Response>) => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
res$.next({
completion: 10,
completionMsg: 'I\'m loading the browser...'
})
await page.goto('https://example.com');
res$.next({
completion: 20,
completionMsg: 'Page opened...'
})
/* Other scraping async functions... */
}
在我的前端,我有一个类似这样的代码:
response$ = Observable<Response> | undefined;
ngOnInit(): void {
const scrapeFunction= getFunctions(undefined, 'europe-west2');
const verifyClient = httpsCallable(functions, 'scrapeFunction');
const { data } = await scrapeFunction({ id: 0001 });
console.log('Data is', data);
this.response$ = (data as any).source as Observable<Response>;
this.response$.subscribe((res) => console.log(res));
return;
}
登录控制台我得到:
Data is
{source: {...}}
source:
closed: false
currentObservers: null
hasError: false
isStopped: false
observers: []
thrownError: null
_value: {completion: 0, completionMsg: 'One moment...'}
[[Prototype]]: Object
[[Prototype]]: Object
我也收到以下错误,因为该函数不是 return 我所知道的 Observable,而是第一个键为“source”的对象。
ERROR Error: Uncaught (in promise): TypeError: _this.response$.subscribe is not a function
TypeError: _this.response$.subscribe is not a function
at dashboard.component.ts:35:29
at Generator.next (<anonymous>)
at asyncGeneratorStep (asyncToGenerator.js:3:1)
at _next (asyncToGenerator.js:25:1)
at ZoneDelegate.invoke (zone.js:372:1)
at Object.onInvoke (core.js:28692:1)
at ZoneDelegate.invoke (zone.js:371:1)
at Zone.run (zone.js:134:1)
at zone.js:1276:1
at ZoneDelegate.invokeTask (zone.js:406:1)
at resolvePromise (zone.js:1213:1)
at zone.js:1120:1
at asyncGeneratorStep (asyncToGenerator.js:6:1)
at _next (asyncToGenerator.js:25:1)
at ZoneDelegate.invoke (zone.js:372:1)
at Object.onInvoke (core.js:28692:1)
at ZoneDelegate.invoke (zone.js:371:1)
at Zone.run (zone.js:134:1)
at zone.js:1276:1
at ZoneDelegate.invokeTask (zone.js:406:1)
有人能理解这种行为吗?
[更新 1]
我在 Firebase Functions 中编辑了我的 index.ts 文件,如下所示:
const res$ = new BehaviorSubject<Response>({
completion: 0,
completionMsg: 'One moment...',
});
exports.verifyClient = functions.https.onCall((data) => {
scrapeCheck(data.id);
return verifyClientRes$.asObservable();
});
const scrapeCheck = async (id: number) => {
await scrape(id, res$);
res$.complete();
return;
};
/* The scrape function is actually on an external file */
const scrape = (/* ... */) => {
/* ... */
}
** 但我在控制台上仍然遇到同样的错误。
[更新 2]
我创建了一个 StackBlitz 项目。你可以在这里找到它:
https://stackblitz.com/edit/wherescrypto?file=functions/src/index.ts
导致此错误的函数在“functions/src/index.ts”中,名为“verifyClient”
将 scrape 放入 setTimeout 中即可解决问题。以便在返回 observable 后调用 scrape。
exports.scrapeFunction = functions.region('europe-west2').https.onCall((data) => {
const res$ = new BehaviorSubject<Response>({
completion: 0,
completionMsg: 'One moment...',
error: undefined,
user: undefined,
});
setTimeout(() => scrape(data.id, res$));
return res$.asObservable();
});
查看一些可以帮助解决您遇到的问题的文档,我想知道您是否已经考虑过使用 realtime database
或 firestore
。
您必须将您的更新推送到某个地方,客户端应用程序可以通过这种方式看到它们。此 Whosebug question.
的评论中提到了此解决方案
我的 Firebase Cloud Functions 中有一个函数需要 运行 抓取任务。当函数正在抓取 public 网站时,我需要 return 向消费者反馈进度。 (例如,“现在是 10%”、“现在是 30%”等)。
我想使用 Observables 但我得到了奇怪的结果,因为抓取函数是异步的,但它应该 return 立即观察到。
这是我的 Firebase 函数后端的简化代码:
exports.scrapeFunction = functions.region('europe-west2').https.onCall((data) => {
const res$ = new BehaviorSubject<Response>({
completion: 0,
completionMsg: 'One moment...',
error: undefined,
user: undefined,
});
scrape(data.id, res$);
return res$.asObservable();
});
const scrape = async (id: number, res$: BehaviorSubject<Response>) => {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
res$.next({
completion: 10,
completionMsg: 'I\'m loading the browser...'
})
await page.goto('https://example.com');
res$.next({
completion: 20,
completionMsg: 'Page opened...'
})
/* Other scraping async functions... */
}
在我的前端,我有一个类似这样的代码:
response$ = Observable<Response> | undefined;
ngOnInit(): void {
const scrapeFunction= getFunctions(undefined, 'europe-west2');
const verifyClient = httpsCallable(functions, 'scrapeFunction');
const { data } = await scrapeFunction({ id: 0001 });
console.log('Data is', data);
this.response$ = (data as any).source as Observable<Response>;
this.response$.subscribe((res) => console.log(res));
return;
}
登录控制台我得到:
Data is
{source: {...}}
source:
closed: false
currentObservers: null
hasError: false
isStopped: false
observers: []
thrownError: null
_value: {completion: 0, completionMsg: 'One moment...'}
[[Prototype]]: Object
[[Prototype]]: Object
我也收到以下错误,因为该函数不是 return 我所知道的 Observable,而是第一个键为“source”的对象。
ERROR Error: Uncaught (in promise): TypeError: _this.response$.subscribe is not a function
TypeError: _this.response$.subscribe is not a function
at dashboard.component.ts:35:29
at Generator.next (<anonymous>)
at asyncGeneratorStep (asyncToGenerator.js:3:1)
at _next (asyncToGenerator.js:25:1)
at ZoneDelegate.invoke (zone.js:372:1)
at Object.onInvoke (core.js:28692:1)
at ZoneDelegate.invoke (zone.js:371:1)
at Zone.run (zone.js:134:1)
at zone.js:1276:1
at ZoneDelegate.invokeTask (zone.js:406:1)
at resolvePromise (zone.js:1213:1)
at zone.js:1120:1
at asyncGeneratorStep (asyncToGenerator.js:6:1)
at _next (asyncToGenerator.js:25:1)
at ZoneDelegate.invoke (zone.js:372:1)
at Object.onInvoke (core.js:28692:1)
at ZoneDelegate.invoke (zone.js:371:1)
at Zone.run (zone.js:134:1)
at zone.js:1276:1
at ZoneDelegate.invokeTask (zone.js:406:1)
有人能理解这种行为吗?
[更新 1]
我在 Firebase Functions 中编辑了我的 index.ts 文件,如下所示:
const res$ = new BehaviorSubject<Response>({
completion: 0,
completionMsg: 'One moment...',
});
exports.verifyClient = functions.https.onCall((data) => {
scrapeCheck(data.id);
return verifyClientRes$.asObservable();
});
const scrapeCheck = async (id: number) => {
await scrape(id, res$);
res$.complete();
return;
};
/* The scrape function is actually on an external file */
const scrape = (/* ... */) => {
/* ... */
}
** 但我在控制台上仍然遇到同样的错误。
[更新 2]
我创建了一个 StackBlitz 项目。你可以在这里找到它: https://stackblitz.com/edit/wherescrypto?file=functions/src/index.ts
导致此错误的函数在“functions/src/index.ts”中,名为“verifyClient”
将 scrape 放入 setTimeout 中即可解决问题。以便在返回 observable 后调用 scrape。
exports.scrapeFunction = functions.region('europe-west2').https.onCall((data) => {
const res$ = new BehaviorSubject<Response>({
completion: 0,
completionMsg: 'One moment...',
error: undefined,
user: undefined,
});
setTimeout(() => scrape(data.id, res$));
return res$.asObservable();
});
查看一些可以帮助解决您遇到的问题的文档,我想知道您是否已经考虑过使用 realtime database
或 firestore
。
您必须将您的更新推送到某个地方,客户端应用程序可以通过这种方式看到它们。此 Whosebug question.
的评论中提到了此解决方案