Tuk*_*ler 5 event-loop synchronous promise angular angular-changedetection
我有一个执行昂贵的同步任务的函数。在我的情况下,它是通过 pdfkit 生成的客户端 pdf,但让我们用 while-loop sleep 来模拟它。
我想在运行任务之前显示一个“加载”微调器,并在完成后隐藏它。
如果一切都同步运行,Angular 将没有机会在一切结束之前运行更改检测循环,所以我想我只需要找到一种方法来异步运行它。
我试着把它包装在一个承诺中,所以假设我有:
sleep(ms) {
return new Promise((resolve, reject) => {
const expire = (new Date()).getTime() + ms;
while ((new Date()).getTime() < expire);
resolve();
});
}
Run Code Online (Sandbox Code Playgroud)
但是我是否使用 .then() 调用运行它:
run() {
this.running = true;
this.sleep(2000).then(() => {
this.running = false;
});
}
Run Code Online (Sandbox Code Playgroud)
或使用异步/等待:
async run() {
this.running = true;
await this.sleep(2000);
this.running = false;
}
Run Code Online (Sandbox Code Playgroud)
在函数结束之前不会检测到更改,并且不会显示任何内容。
我想问题是 Javascript 仍然是单线程的,并且 promise 在创建时仍然会立即运行,所以一切基本上仍然是同步运行的。
但即使使用 ChangeDetectorRef.detectChanges() 强制更改检测也无济于事。
到目前为止,我发现的唯一解决方案是在 setTimeout hack 中运行它:
setTimeoutRun() {
this.running = true;
setTimeout(() => {
this.sleep(2000);
this.running = false;
}, 100);
}
Run Code Online (Sandbox Code Playgroud)
但它看起来不像是正确的正式解决方案。
setTimeout 真的是唯一的方法吗?
Plunker:https ://embed.plnkr.co/ywsIhulPMqjqwzaMxVjn/
如果您的作业是同步的,那么您的加载逻辑也需要同步。除了利用事件循环之外,没有其他方法(据我所知)setTimeout。
换句话说,您不能执行类似的操作this.loading = true,因为这必须等待更改检测运行。您必须显式启动加载逻辑(手动将加载器元素添加到 DOM,以便它立即可见,等等)。
否则,根据定义,它必须等到您的长同步作业完成后才能开始加载,因为加载程序逻辑本身是异步的,因此只有在当前执行(即您的同步作业)完成后才会被调用。
例如:
@Component({...})
export class MyComponent implements OnInit {
constructor(private loadingService: LoadingService) {}
ngOnInit() {
// Start synchronous loader...
this.loadingService.start();
// By the time code reaches here, loader should be visible.
// Do expensive synchronous task...
this.expensiveSynchronousTask().then(() => {
// Stop synchronous loader...
this.loadingService.stop();
});
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1147 次 |
| 最近记录: |