+7

Angular và setTimeout 0 - Anh không thể sống thiếu em!

Hôm nay mình xin được đổi gió một tý, sau một khoản thời gian dài bận bịu không có time viết bài. Mấy hôm nay ngồi làm việc mà vợ cứ bật phim ngôn tình làm mình bị ám ảnh. Nổi hứng nên xin được mạn phép kể một câu chuyện theo phong cách ngôn tình về Angular và setTimeout 0. Các bạn còn chần chừ gì mà không cùng mình khám phá ngay nào!

1. Angular và setTimeout 0: Tình yêu bắt đầu từ đâu?

Để hiểu vì sao Angular và setTimeout 0 lại không thể sống thiếu nhau, trước tiên các bạn cần phải hiểu rõ về nhân vật chính của chúng ta. Đầu tiên, "anh chàng" Angular là một framework phát triển ứng dụng web phía client rất nổi tiếng, do Google tạo ra và duy trì (Đúng kiểu good boy IT lương 3k$). Trong khi đó, "cô nàng" setTimeout 0 là một hàm trong JavaScript cho phép chúng ta thực thi một hàm sau một khoảng thời gian cụ thể, nếu đặt thời gian là 0 thì hàm sẽ được thực thi ngay lập tức sau khi tất cả các hàm hiện tại đã thực thi xong.

Cùng mình xem qua một ví dụ cơ bản với setTimeout 0 nhé!

console.log("Trước setTimeout");

setTimeout(() => {
  console.log("Trong setTimeout");
}, 0);

console.log("Sau setTimeout");

Chắc chắn các bạn sẽ nhận thấy rằng kết quả sẽ là:

Trước setTimeout
Sau setTimeout
Trong setTimeout

Thế mới thú vị chứ! Dù cho thời gian chờ của setTimeout là 0, nhưng câu lệnh trong hàm setTimeout vẫn chờ cho tất cả các câu lệnh trước đó hoàn thành mới được thực thi.

"Vậy liên quan gì tới Angular?" các bạn có thể thắc mắc. Đây chính là điểm thú vị! Angular sử dụng một cơ chế gọi là Zone.js để theo dõi các thay đổi trong ứng dụng và cập nhật giao diện phù hợp. Mà Zone.js thì lại theo dõi các hoạt động bất đồng bộ thông qua các hàm như setTimeout, Promise, XMLHttpRequest... Chính vì vậy, setTimeout 0 chính là một "công cụ" cực kỳ hữu ích để chúng ta "ép" Angular cập nhật giao diện ngay lập tức.

Nào, hãy cùng mình đi sâu vào ngữ cảnh cụ thể của việc sử dụng setTimeout 0 trong Angular nhé!

2. Angular và setTimeout 0: Một mối tình không thể tách rời

Giả sử bạn đang làm việc với một ứng dụng Angular và bạn cần thực hiện một hoạt động nào đó sau khi Angular đã cập nhật giao diện, chẳng hạn như lấy kích thước của một phần tử DOM sau khi nó đã được render. Bạn có thể nghĩ rằng, chúng ta chỉ cần đặt mã đó trong hàm ngAfterViewInit(), nhưng không, cuộc sống không hề đơn giản như vậy, các bạn à!

Ví dụ, xem đoạn mã sau:

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Chào các bạn!</div>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv: ElementRef;

  ngAfterViewInit() {
    console.log('Chiều cao của div: ', this.myDiv.nativeElement.offsetHeight);
  }
}

Khi bạn chạy mã này, bạn sẽ thấy rằng chiều cao của div được log ra trước khi Angular thực sự render nó, do đó kết quả không chính xác. Bạn có thể thử thay đổi kích thước của div và xem kết quả, chắc chắn nó sẽ làm bạn ngạc nhiên!

"Vậy làm sao để giải quyết vấn đề này?" - Các bạn có thể hỏi. Đúng, đây chính là lúc "cô nàng" setTimeout 0 sẽ xuất hiện và giải cứu chúng ta!

Cùng xem đoạn mã sau:

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Chào các bạn!</div>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv: ElementRef;

  ngAfterViewInit() {
    setTimeout(() => {
      console.log('Chiều cao của div: ', this.myDiv.nativeElement.offsetHeight);
    }, 0);
  }
}

Bằng cách sử dụng setTimeout 0, chúng ta "ép" Angular phải chờ cho tất cả các công việc hiện tại hoàn thành (bao gồm cả việc render div của chúng ta) trước khi thực hiện công việc tiếp theo. Và bây giờ, khi bạn chạy mã này, bạn sẽ thấy rằng chiều cao của div được log ra đúng như bạn mong đợi, cho dù bạn thay đổi kích thước của nó như thế nào.

Đó là lý do mà mình nói Angular và setTimeout 0 không thể sống thiếu nhau được. Mối tình này không chỉ giúp chúng ta giải quyết những vấn đề khó khăn trong quá trình phát triển ứng dụng, mà còn mang đến cho chúng ta những hiểu biết sâu sắc hơn về cách Angular hoạt động. Bạn thấy đấy, dù là lập trình, nhưng vẫn đầy rẫy những câu chuyện tình yêu thú vị như thế này đúng không nào? 😃)

3. Lưu ý khi sử dụng setTimeout 0 trong Angular

Tuy "mối tình" này có vẻ rất lãng mạn, nhưng cũng không phải lúc nào cũng mặn nồng đâu nhé. Cần lưu ý rằng, sử dụng setTimeout 0 có thể dẫn đến một số vấn đề nếu chúng ta không cẩn thận.

Performance: SetTimeout sẽ đặt công việc của bạn vào hàng đợi và chờ đến khi tất cả công việc khác hoàn thành. Nếu bạn sử dụng quá nhiều setTimeout 0, ứng dụng của bạn có thể trở nên chậm chạp hơn.

Memory Leaks: Nếu bạn không cẩn thận, việc sử dụng setTimeout có thể dẫn đến rò rỉ bộ nhớ. Điều này xảy ra khi bạn đặt timeout nhưng quên không hủy nó trước khi component được hủy.

Unintended Side Effects: Vì setTimeout 0 đặt công việc của bạn vào cuối hàng đợi, nên nếu có bất kỳ thay đổi nào đối với dữ liệu mà bạn dựa vào trong thời gian chờ đợi, hàm callback có thể hoạt động không đúng như mong đợi.

Vậy làm thế nào để tránh những vấn đề này? Đầu tiên, hãy hạn chế việc sử dụng setTimeout 0 chỉ khi thực sự cần thiết. Thứ hai, luôn nhớ hủy timeout khi không cần thiết nữa, đặc biệt là khi component được hủy.

Dưới đây là ví dụ về cách hủy một timeout:

import {AfterViewInit, Component, ElementRef, OnDestroy, ViewChild} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Chào các bạn!</div>`,
})
export class AppComponent implements AfterViewInit, OnDestroy {
  @ViewChild('myDiv') myDiv: ElementRef;

  private timeoutId;

  ngAfterViewInit() {
    this.timeoutId = setTimeout(() => {
      console.log('Chiều cao của div: ', this.myDiv.nativeElement.offsetHeight);
    }, 0);
  }

  ngOnDestroy() {
    clearTimeout(this.timeoutId

);
  }
}

Trong đoạn mã này, chúng ta lưu trữ ID của timeout và sau đó sử dụng nó để hủy timeout khi component được hủy. Nhờ vậy, chúng ta có thể ngăn chặn rò rỉ bộ nhớ và đảm bảo ứng dụng của chúng ta luôn hoạt động một cách hiệu quả nhất.

4. Kết luận

Angular và setTimeout 0, một mối tình lãng mạn nhưng cũng không kém phần thử thách. Mặc dù họ có thể giúp chúng ta giải quyết nhiều vấn đề phức tạp, nhưng cũng cần phải cẩn thận để tránh các vấn đề có thể xảy ra. Hy vọng sau bài viết này, các bạn đã hiểu hơn về cách sử dụng setTimeout 0 trong Angular và cách để làm cho "mối tình" này trở nên êm đềm hơn. (Cảm ơn bạn đã đọc tới đây và cố nuốt những dòng văn của 1 thằng chưa bao giờ được quá 5 điểm môn văn.)


English Version

Today, I'd like to change the topic a bit after a long busy period without time to write. These days, while I was working, my wife kept watching romantic movies, which haunted me. So, I decided to tell a romantic story in the style of romance novels about Angular and setTimeout 0. Why hesitate? Let's explore together!

1. Angular and setTimeout 0: Where does love begin?

To understand why Angular and setTimeout 0 cannot live without each other, first, you need to understand our main characters. Firstly, "the guy" Angular is a famous client-side web application development framework created and maintained by Google (like a good boy in IT earning $3k). On the other hand, "the girl" setTimeout 0 is a function in JavaScript that allows us to execute a function after a specific time delay. If the delay is set to 0, the function will be executed immediately after all the current functions have finished executing.

Let's take a look at a basic example with setTimeout 0!

console.log("Before setTimeout");

setTimeout(() => {
  console.log("Inside setTimeout");
}, 0);

console.log("After setTimeout");

Surely, you will notice that the result is:

Before setTimeout
After setTimeout
Inside setTimeout

How interesting! Even though the setTimeout delay is 0, the statements inside the setTimeout function still wait for all the previous statements to complete before being executed.

"What does it have to do with Angular?" you may wonder. This is where it gets interesting! Angular uses a mechanism called Zone.js to track changes in the application and update the appropriate interface. And Zone.js tracks asynchronous activities through functions like setTimeout, Promise, XMLHttpRequest, and more. That's why setTimeout 0 is a useful "tool" to "force" Angular to update the interface immediately.

So, let's delve into the specific context of using setTimeout 0 in Angular!

2. Angular and setTimeout 0: An inseparable love

Suppose you are working with an Angular application and you need to perform an action after Angular has updated the interface, such as getting the size of a DOM element after it has been rendered. You might think that you can simply put the code in the ngAfterViewInit() function, but no, life is not that simple, my friends!

For example, take a look at the following code:

import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Hello, everyone!</div>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv: ElementRef;

  ngAfterViewInit() {
    console.log('Height of the div: ', this.myDiv.nativeElement.offsetHeight);
  }
}

When you run this code, you will see that the height of the div is logged before Angular actually renders it, resulting in an incorrect value. You can try resizing the div and see the result. It will definitely surprise you!

"So, how can we solve this problem?" you may ask. Yes, this is where our "girl" setTimeout 0 will come to the rescue!

Let's take a look at the following code:

import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Hello, everyone!</div>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv: ElementRef;

  ngAfterViewInit() {
    setTimeout(() => {
      console.log('Height of the div: ', this.myDiv.nativeElement.offsetHeight);
    }, 0);
  }
}

By using setTimeout 0, we "force" Angular to wait for all the current tasks to complete (including rendering our div) before executing the next task. And now, when you run this code, you will see that the height of the div is logged correctly as you expected, no matter how you resize it.

That's why I say Angular and setTimeout 0 cannot live without each other. This love story not only helps us solve difficult issues during application development but also provides us with a deeper understanding of how Angular works. You see, even in programming, there are plenty of interesting love stories like this, right? 😃)

3. Considerations when using setTimeout 0 in Angular

Although this "relationship" seems romantic, it's not always sweet and passionate. It's important to note that using setTimeout 0 can lead to some issues if we are not careful.

Performance: setTimeout puts your task in a queue and waits until all other tasks have finished. If you use too many setTimeout 0, your application may become slower.

Memory Leaks: If you're not careful, using setTimeout can lead to memory leaks. This happens when you set a timeout but forget to cancel it before the component is destroyed.

Unintended Side Effects: Because setTimeout 0 puts your task at the end of the queue, if there are any changes to the data you rely on during the waiting time, the callback function may not work as expected.

So, how can we avoid these issues? First, limit the use of setTimeout 0 only when necessary. Second, always remember to cancel the timeout when it's no longer needed, especially when the component is destroyed.

Here's an example of how to cancel a timeout:

import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Hello, everyone!</div>`,
})
export class AppComponent implements AfterViewInit, OnDestroy {
  @ViewChild('myDiv') myDiv: ElementRef;

  private timeoutId;

  ngAfterViewInit() {
    this.timeoutId = setTimeout(() => {
      console.log('Height of the div: ', this.myDiv.nativeElement.offsetHeight);
    }, 0);
  }

  ngOnDestroy() {
    clearTimeout(this.timeoutId);
  }
}

In this code, we store the ID of the timeout and then use it to cancel the timeout when the component is destroyed. This way, we can prevent memory leaks and ensure our application always operates efficiently.

4. Conclusion

Angular and setTimeout 0, a romantic relationship with its fair share of challenges. Although they can help us solve many complex issues, we need to be cautious to avoid potential problems. I hope that after reading this article, you have a better understanding of how to use setTimeout 0 in Angular and how to make this "relationship" smoother. (Thank you for reading this far and enduring the words of someone who has never scored more than 5 in the subject of literature.)


日本語版

今日はちょっと風変わりなことをしましょう。長い間忙しくて記事を書く時間がなかったのですが、ここ数日仕事をしていると妻が常に恋愛ドラマを再生しているので、私はトラウマになっています。そこで、AngularとsetTimeout 0に関する恋愛ストーリーをご紹介します。みなさんもぜひ一緒に探検しましょう!

1. AngularとsetTimeout 0: 恋のはじまりはどこから?

AngularとsetTimeout 0がお互いになくてはならない理由を理解するためには、まず主要なキャラクターについてよく理解する必要があります。まず最初に、「彼」と呼ばれるAngularは、Googleが開発しメンテナンスしている非常に有名なクライアント側のウェブアプリケーションフレームワークです(ちょっとIT系のいい子で、給料は3,000ドルです)。一方、「彼女」と呼ばれるsetTimeout 0は、JavaScriptの関数で、特定の時間の経過後に関数を実行することができます。時間を0に設定すると、現在実行中のすべての関数が終了した後にすぐに実行されます。

では、setTimeout 0の基本的な例を見てみましょう!

console.log("setTimeoutの前");

setTimeout(() => {
  console.log("setTimeoutの中");
}, 0);

console.log("setTimeoutの後");

きっとみなさんは次の結果が得られることに気付くでしょう:

setTimeoutの前
setTimeoutの後
setTimeoutの中

面白いですね!setTimeoutの待ち時間が0であっても、setTimeout内の文は、それ以前のすべての文が完了するのを待ってから実行されます。

では、Angularとは何の関係があるのでしょうか?と疑問に思われるかもしれません。これが面白いところです! Angularは、アプリケーションの変更を追跡し、適切にインターフェースを更新するためにZone.jsと呼ばれるメカニズムを使用しています。そして、Zone.jsはsetTimeout、Promise、XMLHttpRequestなどの非同期の活動を追跡します。そのため、setTimeout 0は、Angularにインターフェースを即座に更新するための非常に便利な「ツール」なのです。

それでは、AngularでsetTimeout 0を使用する具体的なコンテキストに深入りしてみましょう!

2. AngularとsetTimeout 0: 分かちがたい愛

仮に、Angularのアプリケーションを開発しているとして、Angularがインターフェースを更新した後に特定の操作を実行する必要がある場合、例えば、レンダリングされたDOM要素のサイズを取得する場合など。みなさんは、これをngAfterViewInit()メソッドにコードを配置すれば良いと思うかもしれませんが、そう簡単なことではありません!

たとえば、次のコードを見てみましょう:

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Hello everyone!</div>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv: ElementRef;

  ngAfterViewInit() {
    console.log('The height of the div: ', this.myDiv.nativeElement.offsetHeight);
  }
}

このコードを実行すると、Angularが実際にそれをレンダリングする前にdivの高さがログに出力されるため、正確な結果が得られません。divのサイズを変更して結果を見てみると、驚くことでしょう!

では、「どのように問題を解決するのか?」と思われるかもしれません。そうです、ここがsetTimeout 0が登場し、私たちを救ってくれるタイミングです!

次のコードを見てみましょう:

import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Hello everyone!</div>`,
})
export class AppComponent implements AfterViewInit {
  @ViewChild('myDiv') myDiv: ElementRef;

  ngAfterViewInit() {
    setTimeout(() => {
      console.log('The height of the div: ', this.myDiv.nativeElement.offsetHeight);
    }, 0);
  }
}

setTimeout 0を使用することで、Angularに「待ってもらい」、(私たちのdivのレンダリングを含む)すべての現在のタスクが完了するのを待ってから次のタスクを実行させることができます。そして、今度はこのコードを実行すると、どのようにdivの高さが期待通りにログに出力されるかが分かります。

これが私が言ったように、AngularとsetTimeout 0がなくてはならない理由です。この愛の関係は、アプリケーションの開発中に多くの複雑な問題を解決するだけでなく、Angularの動作についてより深い理解をもたらしてくれます。見ての通り、プログラミングにも恋愛のような面白い物語が溢れていますね! 😃)

3. AngularでsetTimeout 0を使用する際の注意点

この「恋愛」はロマンチックな一面もありますが、常に甘くはありません。注意が必要なのは、注意がないといくつかの問題が発生する可能性があるため、setTimeout 0を使用する場合です。

パフォーマンス: setTimeoutはタスクをキューに入れ、他のタスクが完了するまで待機します。あまりにも多くのsetTimeout 0を使用すると、アプリケーションのパフォーマンスが低下する可能性があります。

メモリリーク: 注意を払わない場合、setTimeoutの使用はメモリリークを引き起こす可能性があります。これは、タイムアウトを設定した後、コンポーネントが破棄される前にそれをクリアし忘れる場合に起こります。

意図しない副作用: setTimeout 0はタスクをキューの最後に追加するため、待機中に依存しているデータに何らかの変更があった場合、コールバック関数が予想通りに動作しない可能性があります。

では、これらの問題を回避するためにはどうすればよいのでしょうか?まず第一に、setTimeout 0の使用を本当に必要な場合に限定することです。第二に、必要なくなったタイムアウトは常にクリアすることを覚えておいてください、特にコンポーネントが破棄される場合には特にそうです。

以下は、タイムアウトをクリアする方法の例です:

import {AfterViewInit, Component, ElementRef, OnDestroy, ViewChild} from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<div #myDiv>Hello everyone!</div>`,
})
export class AppComponent implements AfterViewInit, OnDestroy {
  @ViewChild('myDiv') myDiv: ElementRef;

  private timeoutId;

  ngAfterViewInit() {
    this.timeoutId = setTimeout(() => {
      console.log('The height of the div: ', this.myDiv.nativeElement.offsetHeight);
    }, 0);
  }

  ngOnDestroy() {
    clearTimeout(this.timeoutId);
  }
}

このコードでは、timeoutのIDを保存し、コンポーネントが破棄されるときにそれをクリアするために使用しています。これにより、メモリリークが防止され、アプリケーションが常に効率的に動作することが保証されます。

4. 結論

AngularとsetTimeout 0、ロマンチックな愛の物語ですが、試練もあります。これらは私たちが複雑な問題を解決するのに役立つだけでなく、Angularの動作について深い理解を得るのに役立ちます。読み進めてくださり、1人の評価5未満の文学的な文章を受け入れてくださり、ありがとうございます。

Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.

Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.

Momo: NGUYỄN ANH TUẤN - 0374226770

TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)

image.png


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí