Javascirpt Quicktip - 5 tips gõ code JS để optimize performance
V8 engine là gì

V8 engine - một JS engine được sử dụng bởi Google Chrome để compile code JS sang maching code (đoạn script mà browser có thể hiểu được). Dựa vào những cách thức hoạt động của nó chúng ta có thể optimize code nhằm tăng đáng kể được hiệu suất khi brower chạy code của ae (~ 50% theo Session Stack)

Trước khi đến với những tips có một số keyword chúng ta cần nắm được, Đó là Hidden Class, và Inline Caching.

1, Hidden Class :

JS là prototype-based language: Không có class. Với JS, chúng ta có thể dễ dàng add và remove các property khỏi object sau khi object đã được khởi tạo (điều này rất khác biệt so với các ngôn ngữ như Java, C#).

Hầu hết các trình biên dịch JS sử dụng dictionary-like structures (hash function based) để lưu trữ vị trí của object property trong bộ nhớ. Điều này có nghĩa là mỗi property của object khi được lưu trữ trong memory sẽ được mark bằng 1 đoạn hash, điều này sẽ giúp việc chúng ta add hay remove property của object dễ dàng. Nhưng điều này sẽ ảnh hưởng đến việc khi chúng ta muốn get value của property đó, JS sẽ tra quyển từ điển chứa list các hash key đó để tìm ra value của propety giống như việc chúng ta tra từ điển tiếng anh vậy. Điều này sẽ làm cho việc truy xuất giá trị của property của object trong JS sẽ tốn kém hơn so với các ngôn ngữ Java và C#. Vì các object trong Java, C# không thêm hay add các property sau khi đã khởi tạo nên các property sẽ có offset cố định.

Để improve quá trình này, V8 đã sử dụng 1 phương pháp khác thay thế đó là hidden class. Hidden class đơn giản là copy cách làm việc với Object của java sang JS. Tức là trong thời gian compile code JS sang machine code, V8 sẽ tạo những object ẩn , cố định và không thể dynamic thêm bớt property.

Ví dụ

							function Point(x, y) {
								this.x = x;
								this.y = y;
							}
							var p1 = new Point(1, 2)
						


Trong ví dụ trên V8 sẽ tạo 1 hidden class gọi là C0 tương ứng với Object Point.

- Line 1, khi mới declare function Point, tương ứng object C0 sẽ được tạo và trống.

- Line 2, chúng ta define property x cho object Point. V8 sẽ tạo 1 hidden class thứ 2 gọi là C1 , C1 được tạo dựa theo C0.
C1 sẽ có vị trí trên memory nơi mà property có thể tìm thấy (liên quan đến object pointer) . Trong trường hợp này x được lưu trữ ở offset 0, điều này có nghĩa là khi view object point trong object thì vị trí đầu tiên là x. V8 sẽ mark V0 là một "class transition" , Lúc này hidden class đã được switch từ C0 sang C1

Quá trình này sẽ lặp lại tương tư khi line "this.y = y" được executed. Và sau quá trình này hidden class sẽ được update bằng C2.
Việc chuyển tiếp hidden class từ C0 sang C1 sang C2 phụ thuộc vào properties được add vào object.
Chúng ta sẽ xem 1 đoạn ví dụ việc add property không theo 1 thứ tự vào các object sẽ ảnh hưởng đến performance.

VD:

							function Point(x, y) {
									this.x = x;
									this.y = y;
							}
						
							var p1 = new Point(1, 2);
							p1.a = 5;
							p1.b = 6;
							var p2 = new Point(3, 4);
							p2.b = 7;
							p2.a = 8;
							
						


sau khi p1, p2 được gán cho 2 object Point mới được khởi tạo, thì ngay tại lúc này p1, p2 sẽ cùng có 1 hidden class, nhưng tiếp theo khi p1 được gán property a, p2 được gán property b thì đến khi kết thúc quá trình excute thì p1 p2 sẽ được gán cho 2 hidden class khác nhau Vì vậy trong những trường hợp như này, sẽ là tốt hơn nếu các dynamic property được khởi tạo cùng 1 thứ tự như vậy thì hidden class sẽ được tái sử dụng.

2, Inline Caching

Đây là cơ chế khi JS engine nhận thấy một function được dùng lại nhiều lần với cùng 1 loại object được truyền vào param. V8 sẽ cache lại hidden class của object đó. Điều này sẽ giúp bỏ qua trình được quá V8 xử lí để tìm cách access vào object's properties và thay vào đó là sử dụng thông tin đã được lưu trữ từ những quá trình xử lí trước đối với object được truyền vào param.

Vậy hidden class và inline caching liên quan với nhau như thế nào? Khi một method được gọi với một object đặc biệt, V8 engine sẽ phải thực hiện quá trình tìm kiếm đến một hidden class của object đó nhằm xác định offset để truy cập vào 1 property của object. Sau hai lần gọi thành công đến cùng một method của cùng một hidden class. V8 sẽ bỏ qua quá trình tìm tìm kiếm này mà đơn giản là add offset của property này đến object pointer của chính nó. Và các lần gọi đến method này sau này , V8 sẽ cho rằng hidden class không thay đổi và sẽ nhảy trực tiếp đến memory sử dụng offset đã được lưu trữ từ lần tìm kiếm trước đó.

Inline caching cũng nói lên tầm quan trọng của việc sử dụng các object share hidden class. Nếu chúng ta tạo hai object cùng loại nhưng khác kiểu hidden class, tức là add các property không theo một thứ tự nhất định (như ví dụ trong hidden class) thì chúng ta sẽ không thể sử dụng inline caching.

TLDR;

1, Methods : Nên sử dung lại một method nhiều lần sẽ tối ưu hết rất nhiều với việc sử dụng một method 1 lần. Vì thế hãy cố gắng chia nhỏ các function, mỗi function nên chỉ có 1 chức năng duy nhất (Pure function) để có thể re-use dễ dàng. tips này dựa theo tính năng Inline Caching của V8 engine.

2, Arrays : Tránh sử dụng các sparse array. Sparse Array là các mảng mà các element bên trong nó có key không phải nó các số incremental .

Ví dụ

							const a = [1, , 3, 4, 5];
							const b = new Array(5);
						


Việc sử dụng mảng dạng này sẽ tốn hiệu năng để access các element trong nó. Tránh khởi tạo trước các mảng lớn, hãy cứ để nó grow tự nhiên.
Không xóa element trong mảng bởi vì nó sẽ biến mảng thành Sparse Array. Thay vào đó hãy dùng Array.filter.

3, Inlining : Không nên sử dụng các function chỉ được gọi 1 lần. Với những case đó nên thay thế line mà gọi function đó thành body của function đó



4, Thứ tự của object dynamic properties khi khởi tạo 1 object:
Khi khởi tạo 1 object nhiều lần hãy cố gắng sắp xếp thứ tự của các property cùng 1 thứ tự , việc này sẽ giúp các hidden class có thể share giữa mỗi lần khởi tạo giúp tối ưu performance



5, Dynacmic Properties: Nên tránh việc thêm các property vào object sau khi đã khởi tạo chúng. Như ví dụ ở tip 4, việc sau khi khởi tạo ta add proprety "name", "color" vào Object Dog được gọi là Dynacmic Properties.

==> Thay vào đó hay truyền tất cả vào param khi khởi tạo 1 object. Bởi vì các Dynamic properties sẽ làm thay đổi và làm chậm các methods đã được optimized bởi hidden class.



Reference

https://blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e