我有一个提供翻译管道的小库。如果我使用Observables,一切都很好。相关代码在这里:
https://gitlab.com/tobias47n9e/angular-fluent/-/blob/master/projects/angular-fluent/src/lib/fluent.pipe.ts#L32
this.localizationChanges.subscribe(() => {
this.fluentService
.translationObservable(key, args, getLocale(args))
.subscribe(value => this.value = value);
});
我想切换到Promises,所以管道只在加载区域设置并找到翻译后才切换值。但是,如果我将代码更改为以下内容,应用程序甚至无法再加载(它编译得很好(。
this.localizationChanges.subscribe(() => {
this.fluentService
.translate(key, args, getLocale(args))
.then(value => this.value = value);
});
这是Angular中不允许的吗?为什么它会编译,然后显示一个空页面,甚至没有打印错误消息?
首先,您可以使用RXJS或promise来实现这一点,但无论哪种方式,都有意为异步编程腾出空间,所以当您的transform
方法在最后同步返回this.value
时,我认为您没有达到预期效果?我猜它正在编译但你认为它不起作用的原因是它在起作用,但在你使用它之前没有计算出正确的值
为了保持在可观测值中,它应该返回一个可观测值。
transform(key: string, args?: any): Observable<string | null> {
if (!this.localizationChanges) {
this.localizationChanges = this.fluentService.localizationChanges;
}
return this.localizationChanges.pipe(
switchMap(() => this.fluentService
.translationObservable(key, args, getLocale(args))
)
);
}
然后在你的模板中,将| async
链接到它的末尾。async
管道将负责订阅、取消订阅、告诉组件在每次可观察到的源发出或更改时刷新,等等。
switchMap
使得fluentService.translationObservable
的任何仍在等待的结果在每次localizationChanges
发射时被丢弃,用新的呼叫代替。
如果您只想发出一个值,那么promise就是一种选择。在这种情况下,你可能想要
async transform(key: string, args?: any): Promise<string | null> {
if (!this.localizationChanges) {
this.localizationChanges = this.fluentService.localizationChanges;
}
return this.localizationChanges.toPromise().then(
() => this.fluentService.translate(
key, args, getLocale(args)
)
);
}
然后在模板中,将| async
链接到它的末尾,而不是重新创建那段代码。
如果我很好地理解这个问题,那么您的代码就有一个基本问题如果我使用Observables";是一个非常特殊的案例的结果。
让我们看看这个非常精简的版本的代码
function translationObservable(key) {
return of("Obs translates key: " + key);
}
function transform(key: string, args?: any): string | null {
let retValue: string;
const localizationChanges: BehaviorSubject<null> = new BehaviorSubject<null>(
null
);
localizationChanges.subscribe(() => {
translationObservable(key).subscribe((value) => (retValue = value));
});
return retValue;
}
console.log(transform("abc")); // prints "Obs translates key: abc"
如果你运行这个代码,你最终会在控制台上打印出一条消息。
这段代码之所以有效,有一个原因,那就是我们正在同步使用Observables。换句话说,代码是逐行执行的,因此分配retValue = value
出现在返回retValue
之前。
但是承诺本质上是异步的。因此,传递给then
方法的任何逻辑都将异步执行,即在Javascript引擎的另一个后续循环中执行。
这意味着,如果我们在上面的例子中使用Promise而不是Observable,我们将不会得到任何打印的消息
function translationPromise(key) {
return Promise.resolve("Promise translates key: " + key);
}
let retValue: string;
function transform(key: string, args?: any): string | null {
const localizationChanges: BehaviorSubject<null> = new BehaviorSubject<null>(
null
);
localizationChanges.subscribe(() => {
translationPromise(key).subscribe((value) => (retValue = value));
});
return retValue;
}
console.log(transform("abc")); // prints undefined
// some time later it prints the value returned using Promises
setTimeout(() => {
console.log(retValue);
}, 100);
总结一下,您的代码可能只有在使用of
运算符创建Observable时才有效(由于不涉及异步操作,因此它可以同步工作(,但我怀疑它在必须调用异步功能(如获取区域设置文件(时是否有效。
如果你想构建一个异步工作的Angular管道,你需要遵循@JSmart523的答案
如前所述,在您的代码中,您正在订阅订阅中的Observable。这被认为与Observables不一致。