简体   繁体   English

Angular 使用 setTimeout 会延迟视图更新

[英]Angular using setTimeout delays the view update

Due to the apps database updates being so quick we have added a material progress bar to help with visual cues to indicate that something has happened.由于应用程序数据库更新如此之快,我们添加了一个材料进度条来帮助提供视觉提示,以指示发生了什么事。

Our logic is that we set the progressbar to a minimum delay of say 500ms.我们的逻辑是我们将进度条设置为 500 毫秒的最小延迟。 We set the showLoading to start the progressbar and we then perform the task and then call hideLoading to turn off the progressbar.我们设置 showLoading 来启动进度条,然后我们执行任务,然后调用 hideLoading 来关闭进度条。 If the minimum delay is surpassed the progressbar stops if not it will wait until the minimum delay time has elapsed and the setTimeout will take care of the stop.如果超过最小延迟,则进度条停止,否则它将等到最小延迟时间过去,并且 setTimeout 将负责停止。 To be clear this part is working.需要明确的是,这部分是有效的。

The issue we have is that when we perform the task and we want to update the ui ie.我们遇到的问题是,当我们执行任务并且我们想要更新 ui 即。 display the results in a table it doesnt update until the setTimeout has completed.在 setTimeout 完成之前它不会更新的表中显示结果。

I have put console.log(s) in the appropriate places and the task is running and returning results it is purley the view is not updating.我已将 console.log(s) 放在适当的位置,并且任务正在运行并返回结果,它是purley,视图没有更新。

Loader Service装载机服务

export class LoaderService {

private _isLoading = false;
private _inProgress = false;
private _delayFinished = false;

private minimumProgressDelay: number = 200;

public get isLoading() {
    return this._isLoading;
}

public showLoading(delay?: number) {
    this._isLoading = true;
    this._inProgress = true;
    this._delayFinished = true;
    delay = delay ? delay : this.minimumProgressDelay;

    setTimeout(() => {
        this._delayFinished = false;
        if (!this._inProgress) {
            this._isLoading = false;
        }
    }, delay);
}

public hideLoading() {
    this._inProgress = false;
    if (!this._delayFinished) {
        this._isLoading = false;
    }
}

} }

Progress Bar in Header component Header 组件中的进度条

<div *ngIf="showLoading">
  <mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>

Typical use of the loader装载机的典型用途

async search(): Promise<void> {
    this.uiService.loader.showLoading(500);

    await this.getResults();

    this.uiService.loader.hideLoading();
}

The getResults function basically does an async httprequest to get the results and then sets the data property for the table. getResults 函数基本上执行异步 httprequest 以获取结果,然后设置表的数据属性。

As previously explained the code all works excpet the update to the table is not updated until the delay is completed.如前所述,除表的更新外,代码的所有工作都在延迟完成之前不会更新。 eg.例如。 if we set it to 10000ms it does wait until the 10secs to show the results.如果我们将其设置为 10000 毫秒,它会等到 10 秒后才显示结果。

Your Loading Service您的装载服务

I'm a little confused about what you are trying to do, but I'll give it my best shot to explain what is going on.我对你想要做什么有点困惑,但我会尽力解释发生了什么。 You say you don't want the service to wait for 10s before moving on.您说您不希望服务在继续之前等待 10 秒。 But you litterally tell your service to timeout for 10s seemingly intentionally making the user wait for no reason.但是,您似乎故意让用户无缘无故地让您的服务超时 10 秒。

Did you perhaps mean to use setInterval instead of setTimeout ?您是否可能打算使用setInterval而不是setTimeout In that case you might want to use timer instead, it allows you to set both an initial delay and a interval time .在这种情况下,您可能想要使用timer ,它允许您设置初始延迟间隔时间 But even then I do not understand your code.但即使那样我也不明白你的代码。 It doesn't seem like you are trying to poll to the endpoint of any API of a back end service.您似乎没有尝试轮询后端服务的任何 API 的端点。

As Drenai points out, and rightly so, it looks like you are trying to create a way to very slowly observe some variable in a service.正如 Drenai 指出的那样,您似乎正在尝试创建一种方法来非常缓慢地观察服务中的某些变量。 The way I see it none of the logic in your LoadingService is very useful except for maybe storing a boolean.我看到它的方式 LoadingService 中的任何逻辑都不是非常有用,除了可能存储一个布尔值。 But, you could just do that in the component itself.但是,您可以在组件本身中执行此操作。

This peace of code already makes it so the application will wait before setting loading back to false, which kind of makes the logic in the service redundant:这种代码的平静已经使应用程序在将加载设置回false之前等待,这使得服务中的逻辑变得多余:

await this.getResults();

You could push these booleans to a BehaviorSubject and observe is from anywhere if that is what you are trying to accomplish.您可以将这些布尔值推送到BehaviorSubject并从任何地方观察,如果这是您想要完成的。

In the service:在服务中:

export class LoadingService {
  private loadingSubject = new BehaviorSubject(false);

  get loading$() {
    return this.loadingSubject.asObservable();
  }

  showLoading() {
    this.loadingSubject.next(true)
  }

  hideLoading() {
    this.loadingSubject.next(false)
  }
}

To observe the boolean in your component:要观察组件中的布尔值:

ngOnInit() {
  this.loadingService.loading$.subscribe(
    value => {
      this.loading = value
    }
  )
}

I created a Stackblitz to show it just works.我创建了一个Stackblitz来展示它是有效的。 Maybe I understood you wrong and you can use this as a startingpoint to create a minimal reproduction of your problem.也许我理解错了,您可以以此为起点来最小化重现您的问题。

Polling轮询

In case you ARE trying to get data from a back end, check this question about polling and using timer to do so.如果您尝试从后端获取数据,请检查有关轮询和使用timer的问题。

Resolver Service解析服务

In case you wanted to grab data when routing I would advice using a Resolver.如果您想在路由时获取数据,我建议您使用解析器。

You make a resolver that calls your service:您制作了一个调用您的服务的解析器:

export class DataResolverService implements Resolve<DataResolved> {
  
  constructor(
    private dataService: DataService
  ) {}

  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): DataResolved | Observable<DataResolved> | Promise<DataResolved> {
    return this.dataService.getData()
    .pipe(
      map(data => ({ data })),
      catchError(error => {
        const message = `Retrieval error: ${error}`
        console.error(message)
        return of({ data: [], error: message } as DataResolved)
      })
    )
  }
}

An example data service:示例数据服务:

export class DataService {
  private dataUrl = 'api/data';

  constructor(private http: HttpClient) {}

  getData() {
    return this.http.get<Data[]>(this.dataUrl);
  }
}

Then you add the resolver to your route:然后将解析器添加到您的路由中:

{
  path: '',
  component: SomeComponent,
  resolve: { resolvedData: DataResolverService },
}

In your component you can now either get the resolvedData described above from a router snapshot or you can subscribe to the route's data:在您的组件中,您现在可以从路由器快照中获取上述已解决的数据,也可以订阅路由的数据:

export class SomeComponent implements OnInit {
  data: Data[];

  constructor(private route: ActivatedRoute) {}

  ngOnInit() {
    this.data = this.route.snapshot.data['resolvedData'].data;
  }
}

To know when to show a spinner you can now just subscribe to your router's events:要知道何时显示微调器,您现在只需订阅路由器的事件:

export class AppComponent implements OnInit {
  loading = true;

  constructor(private router: Router) {}

  ngOnInit() {
    this.router.events.subscribe((routerEvent: Event) => {
      this.checkRouterEvent(routerEvent);
    });
  }

  checkRouterEvent(routerEvent: Event): void {
    if (routerEvent instanceof NavigationStart) {
      this.loading = true;
    } else if (
      routerEvent instanceof NavigationEnd ||
      routerEvent instanceof NavigationCancel ||
      routerEvent instanceof NavigationError
    ) {
      this.loading = false;
    }
  }
}

Here's the full example on Stackbitz of this as well.这也是Stackbitz上的完整示例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 多个 setTimeout 的执行顺序没有角度延迟 - Execution order of multiple setTimeout without delays in angular 使用setTimeout强制创建新元素之间的延迟 - Using setTimeout to force delays between creating new elements Javascript:如何使用setTimeout延迟确保使用多个嵌套循环的顺序执行? - Javascript: How to ensure sequential execution with multiple nested loops using setTimeout delays? 在来自子进程的数据事件中使用 setTimeout 是否有原因导致任意长的延迟? - Is there a reason using setTimeout within an on-data event from a child process causes arbitrarily long delays? React必须使用setTimeout调用才能正确更新视图 - React must call with setTimeout to update view correctly setTimeout()回调的JavaScript执行顺序具有不同的延迟 - JavaScript execution order of setTimeout() callbacks with different delays 在循环内对setTimeout延迟应用缓动 - Applying easing to setTimeout delays, within a loop 在具有不同延迟的嵌套setTimeout循环之间交替 - Alternating between nested setTimeout loops with different delays setTimeout / setInterval有多个延迟来执行代码 - setTimeout/setInterval with multiple delays to execute code 使用setTimeout与比较更新循环上的时间戳 - using setTimeout vs comparing timestamp on an update loop
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM