<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
        <title><![CDATA[NTH Blog]]></title>
        <description><![CDATA[NTH Blog]]></description>
        <link>https://hungvn.com</link>
        <generator>RSS for Node</generator>
        <lastBuildDate>Tue, 02 Jun 2026 15:40:26 GMT</lastBuildDate>
        <atom:link href="https://hungvn.com/feed.xml" rel="self" type="application/rss+xml"/>
        <pubDate>Tue, 02 Jun 2026 15:40:26 GMT</pubDate>
        <copyright><![CDATA[All rights reserved 2026]]></copyright>
        <item>
            <title><![CDATA[Running express.js server over HTTPS]]></title>
            <description><![CDATA[
HTTPS is everywhere and more often than not we need to spin an https server or two. Here's how you can do it for your local express.js dev server:

## 1\. Generate a self-signed certificate

```bash
openssl req -nodes -new -x509 -keyout server.key -out server.cert
```

## 2\. Enable HTTPS in Express

Add something like this to your index.js

```javascript
var fs = require("fs");
var https = require("https");
var app = express();

app.get("/", function (req, res) {
  res.send("hello world");
});

https
  .createServer(
    {
      key: fs.readFileSync("server.key"),
      cert: fs.readFileSync("server.cert"),
    },
    app
  )
  .listen(3000, function () {
    console.log("Example app listening on port 3000! Go to https://localhost:3000/");
  });
```

Now run a command _node index.js_ and your server should be available at address _https://localhost:3000_.

- Note:
  In Chrome, put in chrome://flags/#allow-insecure-localhost in the address bar.
  Enable the option that says "Allow invalid certificates for resources loaded from localhost".
  Restart Chrome, and it should allow the site.
]]></description>
            <link>https://hungvn.com/blog/running-express.js-server-over-https</link>
            <guid isPermaLink="true">https://hungvn.com/blog/running-express.js-server-over-https</guid>
            <pubDate>Thu, 27 Feb 2020 06:59:28 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Scrum cho người mới bắt đầu - Phần cuối: Các sự kiện trong Scrum]]></title>
            <description><![CDATA[
Ở phần này nội dung chúng ta sẽ đi là các sự kiện trong Scrum. Chúng ta sẽ cùng nhau tìm hiểu về các nội dung như sau:

- Sprint
- Lập kế hoạch Sprint
- Scrum Daily
- Tổng kết sprint
- Cải tiến sprint

Các sự kiện trong Scrum hình thành theo một thứ tự lặp đi lặp lại các công việc nhằm xây dựng một thói quen làm việc hiệu quả. Mỗi sự kiện Scrum là cơ hội để cộng tác nhóm. Các sự kiện này đều có giới hạn thời gian tối đa (time boxed). Điều này đảm bảo thời lượng vừa đủ để tránh láng phí thời gian không cần thiết cho sự kiện. Hãy nhìn vảo bảng sơ lược các sự kiện trước khi đi sâu vào nó nhé. bảng

## Sprint

Sprint là gì ? Là trái tim của Scrum. Sự kiện này có time box không vượt quá 1 tháng. Thông thường thì một Sprint có thể kéo dài từ 1 tuần tới 2 tuần. Các nhóm phải quyết định độ dài ổn định cho nhóm của mình dựa trên điều kiện thực tế. Các phần tăng trưởng của sản phẩm có thể phát hành được sản xuất gói gọn trong khung thời gian này. Trong suốt quá trình phát triển sản phẩm, Sprint được khuyến nghị giữ khung thời gian cố định. Một Sprint mới bắt đầu ngay khi một Sprint kết thức. Một sprint sẽ chứa các sự kiện còn lại của scrum như lập kế hoạch sprint, daily meating, tổng kết, cải tiến sprint. Khi một sprint đã bắt đầu, chúng ta cần lưu ý những điều sau:

- Không cho phép bất kì sự thay đổi nào ảnh hưởng tới mục tiêu của Sprint
- Thành phần Nhóm phát triển được giữ nguyên.
- Mục tiêu chất lượng không được cắt giảm.

Tuy vậy, sprint có thể bị huỷ khi kết thúc khung thời gian. Chỉ có PO mới đủ thầm quyền kết thúc Sprint. Một sprint có thể bị huỷ nếu mục tiêu của sprint không còn phù hợp nữa. Điều này xảy ra khi công ty chuyển hướng kinh doanh hoặc khi tình thế công nghệ có sự thay đổi. Nhìn chung, Sprint có thể bị huỷ nếu nó không còn mang lại điều gì có ích. Thế nhưng, do thời gian mỗi Sprint tương đối ngắn, nên việc huỷ một Sprint không mất mấy khi xảy ra. Khi sprint bị huỷ, các phầm sản phẩm đã hoàn chỉnh được xem xét lại. Các hạng mục trong backlog chưa hoàn tất sẽ được ước lượng lại và trả về product backlog để phát triển tiếp. Việc huỷ sprint sẽ gây lãng phí tài nguyên, do mọi người phát mất thời gian công sức lên kết hoạch cho sprint mới. Việc huỷ đó đôi khi còn gây tâm lý cho Nhóm phát triển ít nhiều nữa. Thực tế thì mình đã được trải nghiệm việc huỷ sprint, tất cả công việc dừng lại và đem đưa lại về backlog. Cả tuần của sprint đó gần như cả team không làm gì mà chờ đợi kế hoạch được lên, rất là chán luôn .\_.

## Lập kế hoạch sprint

Khi một sprint bắt đầu, thì buổi Planing Meeting sẽ được thực hiện để xác định mục tiêu và chọn ra các task cần làm. Sự kiện này chia làm hai phần, phần một tất nhiên là chọn task và phần 2 là quyết định cách thức hoàn thành các task đó. Trong buổi planing meeting chúng ta sẽ lần lượt trả lời các câu hỏi sau:

- Mục tiêu của Sprint này là gì ?
- Sprint này phải chuyển giao cái gì ?
- Làm sao để đạt được điều đó

Toàn bộ nhóm Scrum bắt buộc phải tham gia phần thứ nhất của sự kiện. ở phần thứ 2 PO có thể vắng mặt nhưng phải luôn sẵn sàng hỗ trợ nhóm phát triển làm rõ các hạng mục khi cần thiết. Buổi planing meeting kéo dài thường 2 giờ đồng hồ. Thời gian dành cho 2 này được chia đều cho nhau, mỗi phần chiếm một nửa.

### Phần 1: Làm gì trong Sprint này?

Đáp án của câu hỏi này chính là mục tiêu và danh sách các backlog được lựa chọn cho sprint. Phần này bắt đầu bằng việc PO trình bày mục tiêu momg muốn đạt được trong Sprint này. Sau đó PO làm rõ thêm các hạng mục ở phần trên của Product backlog để cả nhóm hiểu kỹ về các mục đó. Trong trường hợp, số lượng backlog ở sprint này so với sprint trước khác nhau, PO phải có trách nhiệm làm rõ. Căn cứ vào mục tiêu sprint và năng lực hiện có, nhóm phát triển sẽ lựa chọn những mục mà họ tin có thể hoàn thành trong Sprint này, bắt đầu từ những hạng mục đứng đầu trong Product Backlog - nói cách khách, họ bắt đầu với những hạng mục có độ ưu tiên cao do PO sắp xếp. Đây là cách làm chủ chốt trong Scrum: nhóm phát triển quyết định có bao nhiêu hạng mục sẽ được hoàn thành, thay vì được giao bởi PO. Điều này sẽ giúp nhóm phát triển đưa racacs dự báo tin cậy hơn do họ làm việc đó căn cứ vào những phân tích và lập kế hoạch của chính bản thân họ.

Để quyết định những hạng mục nào của Product Backlog sẽ triển khai trong Sprint này. Nhóm phát triển xem xét tốc độ trung bình của mình trong các sprint trước kết hợp với những yếu tố bất ngờ ở sprint này để tính đưa ra số lượng backlog cho sprint này. Ví dụ: Trong sprint trước, nhóm phát triển 7 người đã hoàn thành 80 point. Mà trong sprint này có người xin nghỉ phép 3 ngày. Vậy khả năng của nhóm không thể đạt được 80 point như trước. Do đó chỉ lựa chọn số lượng hạng mục đủ làm với tổng point là nhỏ hơn 80.

Ở đây phần trên chúng ta có nói đến việc tốc độ của sprint (velocity). Tốc độ đó được tính bằng số lượng đơn vị được hoàn thành trong mỗi Sprint. Nếu bạn dùng đơn vị là point, thì tốc độ chính là số điểm mà nhóm hoàn thành sau mỗi Sprint. Qua thời gian, tốc độ của nhóm có thể tương đối ổn định. Đó là tiền đề quan trọng có thể phỏng đoán được khối lượng công việc của nhóm trong mỗi Sprint.

Nếu nhóm phát triển muốn lựa chọn một vài hạng mục có độ ưu tiên thấp ở phía dưới của Product backlog họ cần thảo luận với PO. Điều này thường xảy ra khi có sự phụ thuộc giữa các hạng mục hoặc nhóm cảm thấy mục đó có độ ưu tiên thấp nhưng phù hợp để phát triển cùng với các mục khác đã lựa chọn. Kết thúc phần 1, nhóm phát triển và PO thống nhất lại mục tiêu và danh sách backlog . Mục tiêu của sprint là một đoạn mô tả ngắn về kết quả kỳ vọng đạt được sau khi sprint kết thúc. Mục tiêu của sprint đóng vai trò định hướng nhóm Phát triển trong suốt quá trình diễn ra Sprint và đồng thời giúp nhóm đưa ra được những quyết định hợp lý nhằm đạt được mục tiêu này. Một ví dụ về Mục tiêu Sprint là :"Xây dựng chức năng mua hàng bao gồm: Xem danh sách sản phẩm, thêm sản phẩm vào giỏ hàng, xem giỏ hàng, loại bỏ sản phẩm khỏi gior hàng, hiển thị thanh toán".

### Phần 2: Làm sao để hoàn thành công việc đã chọn

Phần 2 của buổi lập kế hoạch Sprint với mục đích trả lời cho câu hỏi: Làm sao để hoàn thành công việc đã chọn? Kết quả của phần này đó là Sprint Backlog - tức là bằng công việc được Nhóm phát triển sử dụng trong suốt sprint, bao gồm các task trong Backlog đã lựa chọn và danh sách công việc tương tứng với từng hạng mục đó. Nhóm phát triển bắt đầu thiết kế hệ thống và lên danh sách các công việc cần làm. Đối với mỗi hạng mục trong danh sách đã lựa chọn, nhóm sẽ tách thành các công việc cụ thể. Các công việc này phải đảm bảo đủ nhỏ để hoàn thành trong vài giờ. Mộ số loại công việc thường được thấy là: design mockup, viết test, nghiên cứu kĩ thuật, triển khai tính năng v.v...Tất cả các công việc này đều phải được nhóm ước lược thời gian để hoàn thành. Thường được tính qua đơn vị point và được quyết định qua Planing Poker( một loại bài để quyết định số point cho một task). Những point này sẽ được cập nhập trong Sprint Backlog đồng thời cũng được sử dụng để tạo biểu độ Sprint Burndown nhằm theo dõi tiến độ Sprint. Sau mỗi ngày làm việc, các thành viên sẽ cập nhập đồng thời Sprint Backlog và biểu đồ với các giá trị mới. Nếu nhóm thấy rằng lược công việc quá nhiêu hay quá ít so với khả năng của nhóm họ có thể trao đổi với PO để loại bỏ bới các hạng mục.

## Daily Scum

Sau khi một sprint bắt đầu thì cũng có một sự kiện bắt đầu theo đó là daily scrum. Đây là sự kiện quan trọng diễn ra hàng ngày trong suốt quá trình phát triển. Thời lượng là 15p cho mỗi buổi nhằm mục đích trao đổi tiến độ công việc giữa các thành viên trong nhóm, lên kết hoạch cho công việc trong ngày hôm nay. Nó còn có một tên gọi khác quen thuộc hơn đó là daily meeting. Trong buổi này mỗi thành viên sẽ trả lời 3 câu hỏi:

- Tôi đã làm được gì vào hôm qua ?
- Tôi sẽ làm gì trong hôm nay ?
- Tôi đang gặp những khó khăn gì ?

Để đảm bảo không "cháy" time box mỗi thành viên nên chỉ trả lời 3 câu hỏi trên và không lan man thảo luận sâu khi phát hiện ra vấn đề nào đó. Và Daily meeting khuyến nghị người tham gia đứng thay vì ngồi để tăng sự tập trung.

## Tổng kết Sprint

Buổi tổng kết sprint sẽ được tiến hành khi thời gian triển khai sprint đã hết. Đây là hoạt động thanh tra và thích nghi đối với sản phẩm đang được xây dựng. Kết thúc buổi này, lộ trình sản phẩm và Product Backlog có thể được điều chỉnh để phù hợp với tình hình phát triển. Tham sự buổi này gôm có nhóm phát triển, PO, SM. Ngoài ra PO có thể mời thêm khách hàng để có thể đưa đánh giá. Tất cả những người tham dự đều hoàn toàn tự do trong việc đặt câu hỏi và đong góp. Khung thời gian cho sự kiện này thường là 1 giờ - 2 giờ. Nội dung trong buổi này là nhóm phát triển và PO trao đổi với nhau để tìm hiểu về tình hình và ghi nhận các khuyến nhị của nhau. Đây là cơ hội để PO lắm được sản phẩm. Còn với nhóm phát triển đây là cơ hội để tìm hiểu và nắm tình hình của PO và thị trường. Nội dung củ tổng kết sprint sẽ gồm:

- PO trình bày mục tiêu Sprint
- Nhóm phát triển trình bày kết quả đã hoàn thành
- Trực tiếp sử dụng sản phẩm và đưa đóng góp.

Ở trong buổi này, chúng ta chú ý không trình bày những tính năng chưa hoàn thành. Những phản hổi nhận được có thể được đánh giá lại độ ưu tiên cho các backlog. Tổng kết không hoàn toàn chỉ là demo sản phẩm, mà demo sản phẩm chỉ là một nội dung trong buổi này. Nếu tập chung cho việc demo sẽ bỏ qua đi những nội dung quan trọng khác đến việc thảo luận và cộng tác giữa các thành viên tham gia. Từ đó gây hiểu nhầm và thực hiên sai mục tiêu thực sự của buổi tổng kết.

# Cải tiến sprint

Và sau khi tiến hành tổng kết xong, chúng ta sẽ có buổi cải tiến sprint. Mục đích của sự kiện này là thanh tra và thi thích quy trình làm việc. Nói cách khác là tìm cách để sprint sau tốt hơn. Nhóm phát triển và SM bắt buộc phải tham gia buổi này. PO có thể có, có thể không. Thời gian đối đa cho buổi này là 2 tiếng. Ở buổi này, cần có một người đứng ra làm vai trò hỗ trợ và đó là SM. Hoạt động chính là:

- Liệt kê những điểm đã làm tốt
- Liệt kê những điểm đã làm chưa tốt
- Đưa ra một vài hành động cải thiện
- Kế hoạch cải thiện cho sprint sau Có rất nhiều kĩ thuật có thể dùng cho buổi này nhưng đơn giản và phổ biến nhất là Glad-Sad-Mad. Glad-Sad-Mad là một kĩ thuật để thực hiện buổi cải tiến dựa trên việc phân loại các ý kiến của thành viên thành 3 nhóm: Glad (vui) - Sad( buồn) - Mad( tức giận). Những hạng mục nào mà thành viên cảm thấy hài lòng thì sẽ phân loại vào Glab. Những task họ cảm thấy chưa hài lòng và có thể cải tiến được thì đưa vào mục Sad. Những hạng mục nào gây cản trở nghiêm trọng và mình móng muốn loại bỏ nó ngay thì đưa vào mục MaD. Cụ thể cách tiến thành nó như sau:

1.  Chuẩn bị

- Để bắt đầu cần chuẩn bị một tấm bảng đủ lớn được chia thành 3 cột.
- Những mẩu giấy nhớ và bút

2.  Thu nhập dữ liệu Sm yêu cầu thành viên ghi tất cả những quan sát của mình vào mảnh giấy nhớ. Mỗi ý kiên trên từng mảnh riêng biệt, sau đó dán lên các cột tương ứng. Hoạt động này cần sử dụng từ 10- 15p
3.  Tổng hợp thông tin Người hỗ trợ gom các ý kiến trùng nhau lại thành một hoặc loại bỏ, sau đó , các thành viên sẽ bỏ phiếu để lựa chọn ra những hạng mục mà mình muốn thảo luận. Cách phổ biến nhất là bỏ phiếu chấm, tức là mỗi thành viên lựa chọn tối đa 3 hạng mục bằng cách ghi một dấu châm vào tờ giấy của mình. Người hỗ trợ sẽ sắp xếp lại trật tư các tờ giấy dựa trên kết quả dấu chấm đó.
4.  Thảo luận và đưa ra hành động cải tiến Sau đó, cả nhóm sẽ lần lượt thảo luận từng hạng mục cho đến khi không còn hạng mục nào nữa, hoặc đã hết thời gian đóng khung. Việc thảo luận nên tập trung vào việc đưa ra hành động cải tiển trong thời gian tới.

# Tổng kết

Ở bài viết này, chúng ta đã cùng đi tìm hiểu về các sự kiện trong Scum cũng như có thể áp dụng cho những dự án nhỏ hiện tại. Ở mức beginner thì mình nghĩ 4 bài viết của mình đã là đủ. Tuy rằng nội dung có hơi khô khan, nhưng đưa cho mọi người các nhìn theo mình là chuẩn về Scrum. Và mình sẽ dừng chuỗi bài viết đó tại đây, để chuyển sang những chủ đề khác vào lần sau. Cảm ơn mọi người đã đón nhận 4 bài viết vừa qua.
]]></description>
            <link>https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-cuoi-cac-su-kien-trong-scrum</link>
            <guid isPermaLink="true">https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-cuoi-cac-su-kien-trong-scrum</guid>
            <pubDate>Mon, 20 Jan 2020 11:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Scrum cho người mới bắt đầu - Phần 3: Nhóm scrum]]></title>
            <description><![CDATA[
Tiếp nối phần số 2 của seri này, ở phần 3, chúng ta sẽ cùng tìm hiểu về :

- Nhóm liên chức năng và tự tổ chức
- Các giai đoạn phát triển của nhóm làm việc
- Nhóm scrum
- ScrumMaster
- Product Owner
- Nhóm Phát triển (team)
- Các nghề nghiệp đặc thù Scrum. Thôi không lan man nữa, let's go.

## Nhóm tự tổ chức và liên chức năng

Trong các tuyên ngôn của Agile có một câu là "**Cá nhân và tương tác** hơn là quy trình và công cụ". Bí quyết thành công của Scrum nằm ở các cá nhân và sự tương tác qua lại giữa các cá nhân trong nhóm Scrum. Nhóm Scrum bao gồm Product Owner, Nhóm phát triển và ScrumMaster. Nhóm Scrum là nhóm tự tổ chức (self-origanizing) và liên chức năng(cross-functional). Nhóm tự tổ chức tự mình chọn cách thức tốt nhất để hoàn thành công việc chứ không bị chỉ đạo bảo ai đó bên ngoài nhóm. Nhóm liên chức năng có đủ kĩ năng cần thiết để hoàn thành công việc mà không phụ thuộc vào bất kì người ngoài nào khác ngoài nhóm. Mô hình nhóm trong Scrum được thiết kế để tối ưu hoá sự linh hoạt, sáng tạo và năng suất. Nhóm Scrum chuyển giao sản phẩm theo phân đoạn lặp đi lặp lại và tăng dần, tối đa hoá cơ hội cho các phản hồi. Việc chuyển giao tăng dần các gói sản phẩm đạt tiêu chuẩn "hoàn thành" đảm bảo một phiên bản có thể sử dụng được của sản phẩm.

**TỰ TỔ CHỨC** có nghĩa là nhóm cùng ra quyết định, cùng tổ chức công việc thông qua bàn bạc, phân công ngang hàng hướng đến mục tiêu chung. Trong nhóm tự tổ chức, không ai giao việc cho ai, mà chủ động lập kế hoạch, phân chia công việc hợp lý dựa trên các vai trò được định nghĩa rõ ràng từ trước. Các vai trò này được trao quyền để hoàn thành công việc.

**LIÊN CHỨC NĂNG** là một cơ cấu nhóm không quá mới mẻ và không phải Scrum phát minh ra. Đó là một nhóm bao gồm nhiều cá nhân với các chuyên môn khác nhau đủ năng lực được kết hợp cùng làm việc hướng tới một mục tiêu chung. Trong đội dự án, các cá nhân có thể đến từ nhiều phòng ban chức năng khác nhau, cũng có thể xuất phát từ bên ngoài (khách hàng, chuyên gia tư vấn). Nhưng khi đã thành một team, thì các các nhân làm việc tập trung cho đội như là một đơn vị để hoàn tất mục tiêu chung. bên trong nhóm liên chức năng không có nhóm nhỏ khác. Ví dụ: một nhóm Scrum được thành lập với 1 PO, 2 SM, 2 Tester, 5 Programer, 1 Design sẽ không phân chia chức năng thành các nhóm nhỏ khác như Tesing, Develoment, ... nữa, mà chi có 1 nhóm duy nhất với các nhân có chuyên môn khác nhau, hợp thành một đội thống nhất để làm việhc hướng tới sản phẩm cần phát triển. Ngoài lề chút, khác với nhóm liên chức năng, nhóm chức năng thường chỉ phụ trách 1 loại công việc đặc thù và có tính cô lập cao.

## Các giai đoạn phát triển nhóm.

![](https://images.viblo.asia/6b32ad16-8de6-4c11-93f7-136ac032a108.png)
Một nhóm cộng tác trải qua những giai đoan khác nhau từ khi được bắt đầu thành lập cho tới khi hoạt động ổn định theo thời gian. Việc nhận diện các giai đoạn của nhóm là quan trọng để đưa ra quyết định chính xác nhằm đảm bảo nhóm đạt được hiệu quả tốt nhất.

Tuckman ( một nhà tâm lý học người Mỹ) đã đưa ra một mô hình để giải thích các giai đoạn này. Mô hình Tuckman chia chặng đường đó thành 4 chặng là **Hình Thành - Sóng Gió - Ổn Định - Hiệu Xuất Cao - Thoái Trào** ScrumMaster có vai trò rất quan trọng đối với việc xây dựng và phát triển nhóm. Nhiệm vụ của vai trò là quan sát để biết nhóm của mình đang ở giai đoạn nào để có những hành động hỗ trợ cần thiết nhằm đẩy nhanh sự phát triển hoặc duy trì sự ổn định của nhóm. Tìm các giải pháp tháo gỡ những trở ngại đối với nhóm trong quá trình phát triển.

## SCUMMASTER

ScumMaster là một vai trò then chốt trong nhóm Scrum có trách nhiệm đảm bảo Scrum được vận hành đúng bằng việc tuân thủ nguyên lý, các kĩ thuật và quỹ tác Scum nhằm hướng đến kết quả tốt nhất. ScrumMaster là người tháo gỡ khó khăn và tạo điều kiện cho nhóm làm việc tốt nhất có thể, huấn luyện đội nhóm thành thục Scrum và hưởng lợi ích từ Scrum. Scummaster không trực tiếp tham giao vào công việc làm ra sản phẩm những là chất kết dính để các bên phối hợp với nhau tạo ra sản phẩm tốt. ScrumMaster không phải là quản lý của nhóm mà là một lãnh đạo theo phong cách phục vụ. Với vai trò là lãnh đạo phục vụ, Scrummaster cung cấp các dịch vụ cho Product Owner, Nhóm Phát Triển và Tổ Chức.

### Với Nhóm Phát Triển, ScumMaster phục vụ theo nhiều cách như sau:

- Đào tạo căn bản Scrum cho trường hợp thành viên chưa lắm rõ.
- Đảm bảo nhóm phát triển thực hiện tốt cho các sự kiện trong Scrum, bao gồm việc tuân thủ khung thời gian, đúng mục đích và nội dung cho từng sự kiện.
- Hỗ trợ nhóm phát triển tìm kiếm và sử dụng hiệu quả công cụ hỗ trợ phát triển , như công cụ để quản lý backlog, duy trì biểu đồ của Sprint, hệ thống mã nguồn, kiểm thử...
- Bảo vệ nhóm phát triển trước những can thiệp bên ngoài trong quá trình triển khai một Sprint. Ví dụ, giải thích rõ cho PO những tác hại mà việc này gây ra cho nhóm phát triển và sản phẩm khi PO muốn thay đổi hạng mục backlog đã lựa chọn cho 1 sprint đang diễn ra, đồng thời hướng dẫn PO đưa các thay đổi về sprint sau.
- Đảm bảo thông tin được minh bạch và thông suốt trong nhóm phát triển, chẳng hạn như thông qua việc nhắc nhở nhóm luôn cập nhập Sprint Backlog , đảm bảo nhóm phát triển thực hiện đúng sự kiện Scrum hàng Ngày.
- Đảm bảo nhóm phát triển có đầy đủ tài nguyên cần thiết phục vụ sản phẩm. Ví dụ như không giam làm việc, các công cụ hỗ trợ và những tài nguyên khác khi có nhu cầu.
- Tìm kiếm sự giúp đỡ từ chuyên gia bên ngoài khi nhóm phát triển gặp khó khăn.

### Với PO, ScumMaster phục vụ theo nhiều cách như sau:

- Tìm kiếm các kĩ thuật để quản lý hiệu quả Product backlog
- Giao tiếp tích cực với nhóm phát triển về tầm nhìn, mục đích vvf các hạng mục của product backlog
- Dạy cho nhóm phát triển biết cách tạo ra các hạng mục ProductBacklog thật rõ ràng và đơn giản
- HIểu rõ việc lập kế hoạch dài hạn sản phẩm trong một môi trường thực nghiệm
- Hiểu rõ và thực hành sự linh hoạt
- Thúc đẩy các sự kiện Scrum theo yêu cầu hoặc khi cần thiết.

Vậy tóm lại công việc của ScrumMaster là

- Tổ chức các cuộc họp: như Planing meeting, Daily meeting, Reto, Demo v.v...
- Thanh tra, thu nhập và minh bạch hoá thông tin: Để tìm ra nguyên nhân của 1 vấn đề, ScrumMaster còn phải thành tạo và liên tự sử dụng 5WHYs để tìm ra các thúc đẩy nhóm tiến lên. Các thông tin quan sát được, điều tra được cần lưu trữ và tổ chức khoa học để tiện bề truy xuất
- Loại bỏ trở ngại: sư dụng 5WHYS để tìm những phương án cho những tình huống khó khăn. ngoài ra SM có thể duy trì một danh sách trở ngại (Impediment Backlog) và cùng với các bên để tháo gỡ dần dần.
- Tìm kiếm cải tiến
- Huấn luyện cho nhóm: thông qua các buổi seminar, workshop, coaching

## PRODUCT OWNER

PO là một trong ba vai trò Scum. Vai trò này chịu trách nhiệm định hướng sản phẩm trong suôt quá trình sản xuất. Nhiệm vụ của PO là tối ưu hoá giá trị của sản phẩm thông qua việc tận dụng tốt nhất khả năng sản xuất của Nhóm Phát Triển. Để đảm đương tốt vai trò này, PO cần là người có hiểu biết về tầm nhìn của sản phẩm. Có thể PO chưa biết cụ thể sẽ làm những gì nhưng có hiểu biết sâu sắc tại sao lại xây dựng sản phẩm này. PO là một người duy nhất, không phải là một nhóm người. Điều này không có nghĩa là một mình PO phải làm mọi việc mà có thể trao đổi, nhận sự hỗ trợ từ những người khác. Tuye nhiên PO vẫn là người đại diện duy nhất và chịu trách nhiệm về sdanr phẩm đang xây dựng. Cụ thể PO là người duy nhất chịu trách nhiệm quản lý Product Backlog - nơi lưu trữ các hạng mục cần phát triển của sản phẩm. Ngoài việc quản lý, PO còn phải tích tự tham gia vào các cuộ họp của nhóm để cung cấp thông tin cần thiết, chủ đọng quản lý một kế hoạch phát hành cho sản phẩm.

Nhưng nhiệm vụ chính của PO là:

- Công việc đầu tiên của PO là tìm hiểu và phân tích kĩ về sản phậm dự định phát triển, lên danh sách các tính năng mong muốn bằng việc liệt kê chung trong Product Backlog. Đây là danh sách các hạng mục mà nhóm phát triển dựa vào để làm việc và chuyển thành các tính năng của sản phẩm thật. Danh sách này không phải là cô định mà được điều chỉnh trong suốt qua trình phát triển của sản phẩm sao cho phù hợp nhất.
- Các hạng mục của Product Backlog sẽ được PO đánh giá giá trị và săp xếp. Hạng mục nào có giá trị cao hơn sẽ đươc đưa lên trên để sản xuất sớm nhất. Khái nhiệm giá trị ở đây phụ thuộc vào rất nhiều yếu tốt, ví dụ như lợi nhuận, mong muốn kahchs hàng và mục tiêu chiếc lực, v.v...
- Nhiệm vụ thứ 3 của PO là tối ưu hoá lợi nhuận trên vốn đầu tư. Trong khi, khả năng sản xuất của Nhóm Phát Triển thường có một giới hạn nhất định, PO là người luôn phải tìm cách để sử dụng tốt nhất khả năng này. vì vậy, ngoài việc sắp xếp các hạng mục trong Product backlog thì Po cũng cần phải biết nói "không" để laoij bỏ những mạng mục không cần thiết.
- PO phải giữu cho Product backlog luôn được minh bạch,. rõ ràng đối với tất cả mọi người .
- Một nhiệm vụ nữa của PO là giải thích cho Nhóm Phát Triển hiểu rõ hạng mục Của Product backlog. Điều này đảm bảo nhóm phát triển hiểu đúng và đầy đủ về từng hạng mục mà họ triển khai.
- Nhiệm vụ cuối cùng là theo dõi tiến độ phát triênmr của sản phẩm.

**Sự thành công của PO phu thuộc vào những yếu tố như:**

- PO cần được trao quyền rả quyết định. Các quyết định này cần phải được tôn trọng. Chúng được thể hiện thông qua nội dùng và trật tự của các hạng mục trong một Product Backlog . Nhóm Phát triển chỉ làm việc dựa trên Product Backlog này chứ không phải làm theo bất cứ yêu cầu nào khác, cho dù yêu cầu đó xuất phát từ bất cứ ai.
- PO phải hiểu biết về lĩnh vực sản phẩm đang xây dựng. Điều này cần thiết để giữ đúng hướng đi trong quá trình phát triển, đưa ra các quyết định, lựa chọn, thêm hay loại bỏ các tính năng nhằm giữ cho Nhóm phát triển luôn làm việc trên những hạng mục cần thiết và sản phẩm luôn mang lại giá trị cao.
- PO phải có đủ thời gian cho công việc của mình. Tốt nhất anh ta là người làm việc fulltime cho một sản phẩm duy nhất để tránh suy giảm hiệu quả công việc.
- PO phải có kĩ năng giao tiếp và thương lượng tốt. Quá Trình pt sản phẩm đòi hỏi PO trao đổi và cộng tác thường xuyên với NHÓM PHÁT TRIỂN và các bên liên quan, cùng với đólà thương lượng để đưa ra quyết định ảnh hướng đến sản xuất và sản phẩm. Do đó , các kĩ năng này rất quan trọng để đảm bảo công việc PPO có thể đạt kết quả cao nhất.

## NHÓM PHÁT TRIỂN

Cuối cùng, nhóm phát triển là đội ngũ trực tiếp làm ra sản phẩm, nhóm này bao gồm các thành viên có nhiệm vụ chuyển giao phần tăng trường có thể chuyển giao được ở cuối mỗi Sprint. Nhóm phát triển trong Scrum cũng là một nhóm tự tổ chức và liên chức năng. Nhóm được trao quyền để tự định hướng và đưa ra các quyết định liên quan đến công việc của sản xuất. Tự tổ chức là nhóm tự toàn quyền quyết định công cụ, kĩ thuật để hoàn thành sản phẩm. Nhóm tự lựa chọn hạng mục từ danh sách đã sắp xếp của BackLog sao cho phù hợp với khả năng sản xuất của mình. Đây là một khách khác việt so với một số mô hình phát triển khác. Trong mỗi hạng mục, nhóm sẽ là người ước lượng kích thước tốt nhất bởi vì họ biết về công việc và yếu tố liên quan tới đó. Nhóm phát triển thường xuyên theo dõi tiến độ công việc để biết khả năng của mình tốc độ sản xuất, tình hình đạt được và các cột mocos quan trọng của sản phẩm. Nhờ đó để dễ dàng điểu chinh cho hợp lý trong quá trình sản xuất. Nhóm phát triển không có sự phân chia chức danh hay vai trò, tất cả các thành viên có vai trò giống nhau. Mỗi thành viên thường có thể mạnh ở một vài kĩ năng nhất định và những kĩ năng đó góp lại trở thành kĩ năng chung của nhóm chứ không còn là của riêng cá nhân nào

Một đặc điểm quan trọng của nhóm phát triển đó là tính liên chức năng. Liên chức năng đối với nhóm phát triển có nghĩa là nhóm được trang bị đầy đủ các kĩ năng cần thiết để hoàn thành công việc và chuyển giao phần tăng trưởng ở cuối mỗi Sprint mà không cần sự hỗ trợ từ bên ngoài. Đặc điểm này là quan trọng vì nó giúp nhóm phát triển thể hoạt động độc lập, trở thành một đơn vị sản xuất hoàn chỉnh, tổ chức vận hành và chuyển giao sản phẩm có chất lượng. Đặc điểm này giúp nhóm phát triển đưa ra các quyết định nhanh chóng, kịp thời mà không phụ thuộc và chờ đợi từ các cá nhân, đơn vị bên ngoài.

Ngoài việc trực tiếp làm ra sản phẩm, sự am hiểu của nhóm phát triển về sản phẩm là rất quan trọng để đi đến thành công. Đặc biệt là đối với các sản phẩm mới. Ở đó, sản phẩm là cả một quá trình tìm tòi, thử nghiệm, điều chỉnh mà ngay cả Product Owner và các bên liên quan đều không biết rõ rrafng từ trước.

## Tổng kết

Phần 3 của seri đã giúp của bạn tìm hiểu các nhóm Scrum , ở phần sau, chúng ta sẽ cùng tìm hiểu các sự kiện trong Scrum nhé.

_Kham thảo: Sách Cẩm năng Scrum Cho Người mới bắt đầu_
]]></description>
            <link>https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-3-nhom-scrum</link>
            <guid isPermaLink="true">https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-3-nhom-scrum</guid>
            <pubDate>Wed, 15 Jan 2020 02:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Scrum cho người mới bắt đầu - Phần 2: Scrum cơ bản]]></title>
            <description><![CDATA[
# Scrum là gì ?

Đôi khi được gọi là một phương pháp Agile, Scrum là khung làm việc linh hoạt được sử dụng phổ biến nhất đến nỗi nhiều người lầm tưởng Agile chính là Scrum hay Scrum chính là Agile. Nhưng Scrum chỉ là một trong số hơn chục phương pháp cụ thể chia sẻ các giá trị được phát biểu trong Tuyên ngôn Agile ( [Agile cơ Bản](https://viblo.asia/p/scrum-cho-nguoi-moi-bat-dau-phan-1-tong-quan-ve-agile-XL6lAXQBZek)). Theo tài liệu hướng dẫn Scrum, Scrum là khung làm việc (framework) để phát triển sản phẩm hoặc quản lý các dự án phức tạp theo cách thực tặp và tăng trưởng. Quá trình phát triển được thực hienej thông qua các phân đoạn nối tiếp nhau. Khung làm việc Scrum bao gồm các giá trị cốt lõi , vai trò, sự kiện, tương tác và các quy tắc để gắn kết tất cả thành một thể thống nhất. Scrum là khung làm việc linh hoạt, dễ hiểu nhưng khó tinh thông. Một số hiểu lầm Scrum là bộ công cụ hay biện pháp thực hành nên cho rằng mình cứ có Sprint Backlog hay thực hiện Scrum hằng ngày thì gọi là Scrum. Hiểu lầm khác , Scrum là phép thần để giải quyết các vấn đề của tổ chức hay dự án. Để sử dụng Scrum cần sự thay đổi sâu sắc trong các nghĩa, cách làm chứ không dừng lại ở việc có một số công cụ hay thực hiện một sự kiện. Ở những phần sau của bài viết này, mình sẽ giúp bạn tìm hiểu toàn cảnh khung làm việc Scrum nhé.

# Sơ lược lịch sử Scrum

Sơ lược một chút về lịch sử Scrum nhé các bạn.

- Takeuchi và Nonaka là những người rất lớn cho sự ra đời của Scrum với bài viết " The New Product Development Game" trên Harvard Business Review năm 1986
- Jeff Sutherland lần đầu giới thiệu Scrum tại công ty Easel vào năm 1993
- Ken Schwaber cùng Jeff Sutherland thuyết trình về Scrum tại sự kiện OOPSLA năm 1995
- Và năm 2001, Tuyên ngôn phát triển phần mềm linh hoạt và Liên minh Agile ra đời.
- Tới năm 2002, Liên minh Scrum được thành lập
- Và 8 năm sau đó, Ken Schwaber và Jeff Sutherland cùng xây dựng định nghĩa Scrum với phiên bản đầu tiên.

# Lợi ích khi dùng Scrum

Đã có nhiều báo cacos cho thấy Scrum được sử dụng rộng rãi không chỉ trong lĩnh vực phát triển phần mềm mà còn loang ra cả những dự án sản xuất phần cứng , các đội nhóm marketing hay giáo dục.

### 1\. Độ trực quan

Với phương pháp truyền thống, phải đến giai đoạn cuối mới thấy được sản phầm, còn trước đó không có sản phẩm thật. Từ khi bắt đầu phát triển tính trực quan ngày càng giảm. Với Scrum, ngay từ đầu, chung ta chuyển giao những phần tăng trưởng hoạt động tốt của sản phầm và việc chuyển giao là liên tục và đều đặn, độ trực quan được duy trì cao nhất.

### 2\. Giá trị chuyển giao

Với phương pháp truyền thống, khách hàng đợi đến cuối để có thể bắt đầu nhận được giá trị từ sản phẩm bới việc dành nhiều thời gian để lập kế hoạc và thông công dự án mà không đưa ra được một sản phẩm thực sự, Do đó giá trị họ nhận được ban đầu rất thấp. Ngược lại, Scrum tập chung chuyển giao các tính năng hoàn chỉnh của sản phẩm ngay từ đầu. Do đó, ngay trong giai đoạn sản xuất, khách hàng đã nhận được giá trị, Những giá trị này càng ngày càng được tích luỹ và lớn dần theo tiến độ dự án

### 3\. Rủi ro

Với phương pháp truyển thống, chúng ta đặt được vào độ chính xác của kế hoạch ban đầu mặc dù khi đó chung ta có nhiều giả định như con người, công nghệ, môi trường kinh doanh không thay đổi hoặc chúng ta biết đủ những yếu tố này do đó rủi ro rất cao cho tới khi kết thúc. Với Scrum, mức độ rủi ro giảm rất nhanh . Chìa khoá ở đây chính là việc lặp và tăng trưởng cùng với sự thanh tra thích nghi liên tực.Những yếu cố tiềm ẩn rủi ro liên quan đến sản phẩm , công nghệ, con người đều được phát hiện và điều chỉnh sớm

### 4\. Khả năng thay đổi

Với phương pháp truyền thống không sẵn sàng cho việc thay đổi với chúng được thực hiện theo một kế hoạch chi tiết và cụ thể từ giai đoạn đầu, sau đó bám sát từng chi tiết kế hoạch. Chi phí cho sự thay đổi rất lớn đặc biệt ở giai đoạn sau. Còn với Scrum, luôn chủ động đón nhận thay đổi. Chung ta không dành nhiều công sức cho lập kế hoạc cho những giả định mà luôn chuẩn bị cho mọi sự phía trược, do đó chi phí cho thay đổi thấp.

# Khung làm việc Scrum

Khung làm việc Scrum gồm các vai trò của nhóm Scrum, những giải định (Arifact) được làm ra, các sự kiện Scrum cùng các quy tắc ràng buộc cách thực làm việc, Tất cả chúng xây dựng dựa trên một giá trị nhất quan với các giá trị Agile các các trị cốt lõi của Scrum

#

Vai trò

Giá đỉnh

Sự kiện

Ý nghĩa

Định ra tách nhiệm của tùng thành viên

Các công cụ hoặc sản phẩm do nhóm Scrum làm ra

Các cuộc họp cơ chế cộng tác có cấu trúc để cộng tác hiệu quả hướng đến mục tiêu chung

\* Product Owner  
\* Scrum Master  
\* Nhóm phát triển

\* Gói tăng trưởng  
\* Product Backlog  
\* Sprint Backlog

\* Sprint  
\* Lập kế hoạch Sprint  
\* Scrum hàng ngày  
\* Tổng kết Sprint  
\* Cải tiến Sprint

Giả sự ban đang là thành viên của một nhóm Scrum. Sáng thứ hai, bạn sẽ cùng nhóm làm việc ngồi với nhau, họp lập kế hoạc để quyết định cả đội sẽ làm gì trong Sprint tới và làm như thế nào (Planing meeting). Sau đó các cộng việc đưa chia sẻ ra thành công việc cụ thể ( Break Task). Hằng ngày từ thứ ba đến ngày cuối cùng của sprint, các bạn sẽ lựa chọn việc làm phù hợp với bản thân và thực hiện. Vào đầu giờ sáng mỗi, cả nhóm sẽ đứng lại để Daily Meeting cùng xem lại tiến độ của cả nhóm, thông báo các khó khăn gặp phải khi làm việc. Cuộc họp đó chỉ diễn ra trong 15p hàng ngày. Vào ngày cuối cùng của sprint, cả team sẽ ngồi ra soát lại công việc, xem kế hoạch đã đề ra xem có hoàn tất không. Sau đó sẽ đánh giá và đưa ra cách để cải tiến công việc cho một sprint sau. Và công việc này sẽ lặp đi lặp lại cho tới khi dự án được xong. Đó là hình dung đơn giản về nhịp độ làm việc của một nhóm Scrum trong một Sprint. Trong mô tả trên, nhóm Scrum đóng khung hoạt động của mình trong một Sprint ( thường 1-2 tuần). Buổi họp cuối Sprint sẽ ra soát hoạt động của Sprint còn gọi là Petrospective Meeting. Và buổi họp hàng ngày được gọi là Daily Meeting và chỉ diễn ra trong 15 phút đầu giờ. Bảng công việc sẽ được tập hợp trong Sprint Backlog. Trong nhóm, có các thành viên là

- Product Owner: chịu trách nhiệm quản lý danh sách những yêu cầu công việc ( BackLog)
- Scrum Master chịu trách nhiệm tổ chức cách thức làm việc theo Scrum cho cả nhóm
- Team: những người có đủ chuyên môn để hoàn thành mục tiêu mà cả nhóm đề ra

Trên đây chúng ta đã có những hình dung đơn giản hoá về một nhóm làm việc theo Scum trong vào 1 Sprint. ở mức đổ tổng uqna chúng ta thấy nhịp làm việc này rất gần gũi với các làm việc của những nhóm làm việc gắn kết và chuyên ghiệp. Mô tả hình hoá của quy trình trên được thể hiện rõ ràng qua ảnh. Các bạn có thể coi và đối chứng chi chi tiết.
![](https://images.viblo.asia/16a87da1-96c9-4239-bc52-602180a2c48f.gif)

# 3 trụ cột của Scrum

Để áp dụng Scrum chuẩn chúng ta cần lắm rõ 3 trụ cột của Scrum đó là

### 1\. Minh bạch

Muốn thành công với Scrum, thông tin liên quan tới quá trình phát phải mình bạch và thông suost. Các thông tin đó có thể là: tầm nhìn về sản phầm, yêu cầu khách hàng, tiến độ công việc, những khúc mắc, rào cản v.v.. Từ đó mọi người ở các vai trò khác nhau có đủ thông tin cần thiết để tiến hành các quyết định có giá trị để nâng cao hiệu quả công việc. Các công cụ và cuộ họp trong Scrum luôn đảm bảo thông tin được minh bạch cho các bên,

### 2\. Thanh tra

Công tác thanh tra liên tục các hoạt động của Scrum đảm bảo cho việc phát hiện các vấn đề cũng như giải pháp để thông tin đa dạng và hữu ích đến được với các bên tham gia. Truy két kĩ cang và liên tục là cơ chết khởi đầu cho việc thích nghi và các cải tiến lục tục trong Scrum

### 3\. Thích nghi

Dựa trên các thông tin minh bạch hoá từ các quá trình thanh tra và làm việc, Scrum có hể phản hồi các thay đổi một cách tích cực, nhò đó mang lại thành công cho dự án. Các nỗ lực minh bạch và thanh tra để hướng tới hành động thích ứng nhanh chóng hiệu hiệu.

# 5 giá trị của Scrum

- Dũng cảm: Để một người dám nói ra vấn đề của mình và chấp nhận rất nhiều loại rủi ro khi thay đổi cam kết, họ cần là người dũng cảm. Về cơ bản, những giá trị khác không thể có nếu bạn không có sự dũng cảm
- Tập trung: Mọi người tập trung vào công việc trong Sprint và Mục tiêu Sprint của nhóm. Khi nhóm phát triển đã cam kết với những việc trong Sprint , họ cần phải tập trung để hoàn thành những gì mà mình đã cam kết.
- Cam kết: Mỗi thành viên cam kết với các thanh viên khác về những điều mình làm và công việc đã được chọn ở buổi Lập kế Hoạch Sprint. Ngoài ra chúng ta liênc tục cải tiến tức là thay đổi để trở thành một các nhân tốt hơn, nhóm tốt hơn và tổ chức tốt hơn. Chúcng ta luôn phải thay đổi để giữ vứng lợi thế cạnh tranh và phục vụ khách hàng. Thực hiện thay đổi bao giờ cũng rất khó kahwn, do đó chỉ với sự cam kết chung ta mới có thể làm được
- Cởi mở: Mọi thứ cần phải rõ ràng, minh bạch để mọi người có thể làm việc hiệu quả. Phát triển phần mềm rất phức tạp, một người không thể nìn và hiểu được hết tất cả nhiều mọi vấn đề. Do đó nếu mọi người không cở mở với nhau, thông tin bị che giấu rất nhiều và hiệu quả công việc khó lòng nâng cao
- Tôn trọng: Khi thiếu tôn trọng, mọi người khó thành thật trong chia sẻ. Ví dụ một người không biết một điều gì đó, khi hỏi người khác. Người trả lời thay vì mong muốn giúp đỡ để người hỏi trở nên tố hơn, độc lập hơn lại phàn nàn, đánh giá người hỏi thì lần sau người hỏi sẽ khó mà cở mở và nói sự thật được. Không tôn trọng, khó có sự cở mở

# Tổng kết

Ở phần 2 của chuỗi bài Scrum cho người mới bắt đầu, chúng ta đã đi tìm hiểu về khung làm việ của Scrum, lợi ích cũng như các giá trị của Scrum. ở phần số 3, chung ta sẽ đi sâu vao từng nhóm Scrum để tìm hiểu rõ hơn họ làm gì trong đó,. tổ chức với nhau như thế nào. Hẹn gặp lại các bạn ở phần 3.

Tham khảo: Sách Scrum Cơ bản - NXB Thế Giới
]]></description>
            <link>https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-2-scrum-co-ban</link>
            <guid isPermaLink="true">https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-2-scrum-co-ban</guid>
            <pubDate>Sat, 11 Jan 2020 08:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Scrum cho người mới bắt đầu - Phần 1: Tổng quan về Agile]]></title>
            <description><![CDATA[
Hiện nay, các công ty phần mềm thường áp dụng mô hình phát triển phần mềm Scrum. Vậy Scrum là gì ?. Scrum là một bộ khung với các công cụ, vai trò và qui trình rõ ràng dựa trên các nguyên lý Agile. Chính vì thế để tìm hiểu kĩ về scrum trước tiên chúng ta cần lắm rõ thứ mà Scrum dựa vào đó là nguyên lý Agile. Và nội dung của phần 1 trong serial bài viết là tìm hiểu về nguyên lý Agile.

# Những vấn đề phổ biến trong phát triển sản phẩm và quản trị dự án phần mềm

Ngành phát triển phần mềm đã có hơn nửa thế kỉ hình thành và phát triển, qui trình phát triển phần mềm truyền thống hay còn gọi là water fall được mô tả như sau:
![](https://images.viblo.asia/2b866886-ca3b-4ba6-b7ed-4c13308a6861.png)
Đây là quá trình được thực hiện tuần tự từ đầu tới cuối. Tuy nhiên, rất nhiều những vấn đề cứ không ngừng lặp lại, làm đau đầu đội ngũ phát triển và nhà quản trị. Dưới đây là một số vấn đề tiêu biểu:

- Theo cách thức phát triển cũ, dự án được lập kế hoạch cẩn thẩn và được tiến hành với nhiều khâu, trong thời gian đó khách hàng sẽ ngồi chờ. Các bên chỉ nhận được các báo cáo chứ không được phần mềm để dùng. THông tin về sản phẩm rất mù mờ, không minh bạch trong tiến độ với khách hàng. Điều này gây làm cho bên lo lắng và không cách nào cung cấp các phản hồi có ý nghĩa, khó hợp tác với đội phát triển cho ra sản phẩm tốt nhất.
- Kế hoạch đã định, nhưng nhiều rủi ro xuất hiện: lỗi xuất hiện ngày càng nhiều, hiểu sai yêu cầu, khó khăn về mặt công nghệ, không làm việc như kỳ vọng
- Sản phẩm thiếu ổn định do không kiểm soát được chất lượng. Nhiều dự án, mọi công việc hoàn thành nhưng giai đoạn tích hợp và ổn định hệ thống thật là thảm hoạ không bao giờ kết thức.
- Kế hoạch tuy được lên sẵn, nhưng không có nghĩa là không sai sót. Điều này làm ra tốn thời gian hơn cho việc lập kế hoạch.
- Khi mọi thứ đã được chuẩn bị xong, khách hàng bỗng cao hứng đổi yêu cầu, điều này làm nhóm khó xử bởi họ không biết làm thế nào do việc thay đổi rất khó.
- Sản phẩm bất ôn định do mã nguồn càng nhiều sau một khoảng thời gian phát triển. Kế hoạch bị phá vỡ, chất lượng ngày một giảm, tất cả mọi người phải chịu thêm các áp lức khiến cho các lập trình viên không vui vẻ gì.

# Agile ra đời

Tại thập kỉ 80 của thế kỉ XX, chứng kiến một thời kì khủng khoảng phương pháp luận phát triển phần mềm, do tỉ lệ thất bại của các dự án phần mềm quá cao. Rất nhiều các phương pháp phát triển phần mềm với truy trình nhẹ và linh hoạt hơn ra đời. Vào tháng 2/2001, 17 nhà phát minh và thực hạnh đã họp nhau tại Hoa kì để thoải luận và đi tới thống nhất cho ra đời Agile, đánh dấu một xu thế mới cho phát triển phần mềm. Sau một khoảng thời gian dài ra mắt, Agile đã cải thiện dáng kể khả năng thành công của các dự áo.'. Minh chứng cho điều đó thì theo báo cáo năm 2015 của Standish Group đã cho thấy dự án Agile có tỉ lệ thành công cao hơn gấp 3 lần so với dự án truyền thống.
![](https://images.viblo.asia/b4765608-1883-4b39-ac16-27dbcbe8af2d.jpg)
Vậy Agile có những gì, Agile đưa ra các tuyên ngôn phát triển phần mềm linh hoạt như sau:

- **Cá nhân và tương tác** hơn là quy trình và công cụ
- **Phần mềm có thể chạy được** hơn là tài liệu đầy đủ
- **Cộng tác với khách hàng** hơn là đảm phán hợp đồng
- **Phản hồi với thay đổi** hơn là bám sát kế hoạch

Bên cạnh đó Agile còn đi kèm 12 nguyên lý như sau:

1.  Ưu tiên cao nhất của chúng ta là thoả mãn khách hàng thông qua việc chuyển giao sớm và liên túc các phần mềm có giá trị
2.  Chào đón việc thay đổi yêu cầu, thậm chí rất muonj trong quá trình phát triển. Các quy trình linh hoạt tận dụng sự thay đổi cho các lợi thế cạnh tranh của khách hàng
3.  Thường xuyên chuyển giao phần mềm chạy tốt tới khách hàng, từ vài tuần tới vài tháng ưu tiên cho các khoảng thời gian ngắn
4.  Bên kinh doanh và nhà phát triển làm việc cùng nhau hàng ngày trong suốt dự án
5.  Xây dựng các dự án xung quanh những các nhân có động lực. Cúng cấp cho họ môi trường và sự hỗ trợ cần thiết , và tin tưởng học để hoàn thành công việc
6.  Phương pháp hiệu quả nhất để truyền đạt là đối thoại trực tiếp
7.  Phần mềm chạy tốt là thước đó chính của tiến độ
8.  Quy trình linh thoạt thức đẩy phát triển bền vứng.
9.  Liên tục quan tâm đến các kĩ thuật và thiế kế tố để gia tăng sự linh hoạt
10. Sự đơn giản là cần thiết
11. Kiến trúc tốt nhất, yêu cầu tốt nhất và thiết kế tốt nhất sẽ được làm bởi các nhóm tự tổ chức
12. Nhóm phát triển sẽ thương xuyên suy nghĩ về việc làm sao để trở nên hiệu quả hơn sau đó họ sẽ điều chỉnh và thay đổi hành vi của mình cho phù hợp.

_Những giá trị trên không chỉ là thứ mà nhóm tác giả của Agile dự định cung cấp ra để phục vụ cho tuyên ngôn mà rồi sau đó đi vào dĩ vãng. CHúng là các giá trị căn cứ vào để làm việc. Bản thân mỗi phương phát linh hoạt đều tiếp cận các trị trên theo các cách thức khác nhau, nhưng tất cả các phương pháp này đề có tiến trình biện pháp thực hành cụ thể để nuôi dưỡng một hoặc nhiều trong số các giá trị đó._

## Cá nhân và tương tác

Các nhân và tương tác giưã họ là cốt yếu để nhóm đạt được hiệu suất cao. Các nghiên cứu về sự bão hoà giao tiếp trong dự án cho thấy rằng, khi không có vấn đề giao tiếp, nhóm có thể thực hiện công việc tốt hơn 50 lần so với mức trung bình trong lĩnh vực của mình. Để tạo điều kiện cho giao tiếp các phương pháp linh hoạt thường xuyên sử dụng chu trình thanh tra và thích nghi. Chu trình này diễn ra hằng ngày với lập trình cặp (pair- programing), hàng giờ và tích hợp liên tực qua các buổi sơ kết và cải tiến. Tuy vậy, tăng tần suất phản hồi và giao tiếp là không đủ để loại bỏ các vấn đề giao tiếp. Chu kỳ thanh tra và thích nghi hoạt đông tốt chỉ khi các thành viên trong nhóm thể hiện những hành vi quan trong sau:

- Tôn trọng giá trị của mỗi cá nhân
- Trung thực trong giao tiếp
- Minh bạch về dữ liệu, hoạt động và quyết định
- Tin tưởng vào sự hỗ trợ của mỗi cá nhân với nhóm
- Cam kết với nhóm các mục tiêu của nhóm Để thức đẩy các hành vi này, nhà quản trị linh hoạt phải cung cấp môi trường hỗ trợ và tạo điện kiện thuận lợi để các thanh viên trong nhóm thể hiện mình. Chỉ khi đó nhóm mới có thể phát huye hết tiềm năng của mình. Tuy vậy, hầu hết các nhóm tránh né sự thật, sự minh bạch và tin tưởng vào chuẩn mực văn hoá hoặc những kinh nghiệm tiêu cực từ các xung đột xuất phát từ truyền thống trước đây. Để chống lại những khuynh hướng này, người lánh đảo và thành viên phải tạo điều kiện cho những xung đốt tích cực. Làm vậy không chỉ giúp tạo ra hành vi sinh lời mà ocn đem lại lợi ích khác nhau.
- Cải tiến quy trình thuộc vào nhóm trong việc tạo ra danh sách trở ngại hoặc vấn đề trong tổ chức, đối mặt với chúng một cách trung thực, sau đó loại bỏ chúng khỏi hệ thống
- Đổi mới chỉ xay ra với việc tự dao trao đổi các ý tưởng mâu thuẫn nhau.
- Hướng các nhóm tới mực tiêu chung đòi hỏi nhóm phải đối mặt và giải quyết các vấn đề xung đột
- Cam kết làm việc cùng nhau chỉ xảy ra khi mọi người đồng ý với mực tiêu chung và sau đó đấu tranh cho sự tiến bộ của bản thân.

## Phần mềm chạy tốt

Phần mềm chạy tốt là một trong những khác biệt lớn mà phát triển linh hoạt mang lại. Tất cả các phương pháp linh hoạt thể hiện ở Agile bằng cách nhận mạnh việc cung cấp một phần nhỏ của phần mềm chạy tốt tới khách hàng sau một khoảng thời gian nhất định, Tất cả các nhóm Agile phải xác lập những già họ muốn nói là phần mềm chạy tốt, thường được biết như "Định nghĩa của hoàn thành" ( Define of Done). Ở mức độ cao, một phần của chức năng hoàn thành chỉ khi các tính năng của chúng vượt qua tất cả các kiểm thức và có thể vận hành bởi người dùng cuối. Ở mức thấp hơn, các nhóm phải vượt qua những kiểm thự đơn vị (unit test) và kiểm thử hệ thống. Các nhóm tốt nhất còn bao gồm việc kiểm thử tích hợp, kiểm thư hiệu năng và kiểm thử chấp nhận của khách hàng trong Define of Done đối với một chức năng.

## Cộng tác với khách hàng

Trong thập kỷ qua, tỉ lệ thành công của các dự án tăng hơn 2 lần trên toàn thế giới. Điều nay được cho là vì các dự án nhỏ hơn và mức đổ chuyển giao thường xuyên đã cho pháp khách hàng cung cấp các thông tin phản hồi về phần mềm hoát động một cách đều đặn hơn. Các tác giả của Agile đã làm sáng tỏ điều này khi họ nhấn mạnh rằng việc khách hàng tham gia vào quá trình phát triển phần mềm là hết sức cần thiết cho sự thành công của dự án. Ví dụ, mỗi nhóm Scrum đầu tiên có hàng ngàn khách hàng. Sẽ là không khả thi nếu cho phép tất cả khahcs hàng tham giao vào quá trình phát triển phần mềm, vì vậy họ chọn ra một đại sứ khách hàng được gọi là PO (Product Owner) để đại diện cho không chỉ tất cả khách hàng trong trường hợp này mà có bao gồm các nhàn quản lý, dịch vụ khách hàng và các bên liên khách khác. PO có trách nhiệm cập nhập danh sách yêu cầu về sản phẩm sau mỗi thời điểm mà nhóm Scrum phát hành phiên bản sản phẩm chạy tốt, có tính đến yếu tố thực thế cùng phản hồi của khách hàng và các bên liên quan. Điều này cho phép khách hàng có thể định hình sản phẩm phần mềm đang tạo ra.

## Phản hồi với thay đổi

Phản hồi với thay đổi là cần thiết cho việc tạo ra một sản phẩm làm hài lòng khách hàng cũng như mang lại những giá trị kinh doanh. Dữ liệu ngành công nghiệp cho thấy hơn 60% các yêu cầu về sản phẩm hay dự án bị thay đổi suốt qua trình phát triển phần mềm. Ngay cả những dự án truyền thống kết thúc đúng thời gian, trong giới hạn kinh phí, tính năng theo kế hoạch nhưng khách hàng thường không hài lòng vì những gì họ thấy không đúng như những gì họ muốn. _Luật Humphrey nói rằng khách hàng không bao giờ biết những gì họ muốn cho đến khi họ thấy phần mềm hoạt động_ Nếu khách hàng không thấy phần mềm hoạt động cho đến khí kết thúc dự án, sẽ là quá muộn cho việc kết hợp các thông tin phản hồi của họ ở thời điểm này. Phương pháp phát triển linh hoạt tìm kiếm sự phản hồi của khách hàng trong suốt dự án để có thể kết hợp thông tin phản hồi và thông tin mới ngay khi sản phẩm đang được phát triển.

# Tổng kết

Agile không phải là một qui trình hoàn thiện mà chỉ là tập hợp các nguyên lý chung mà chúng ta nên tuân theo để phát triển phần mềm một cách uyển chuyển tinh gọn. Dựa theo nguyên lý của agile người ta đã đề ra những khung qui trình phát triển phần mềm mà phổ biến nhất là Scrum. Vậy Scrum có gì mời các bạn đợi tới phần 2 : Scum Cơ Bản. Ở phần 2 các bạn sẽ cùng giải đáp các câu hỏi như Scrum là gì ? Lợi ích của Scrum ? Nó diễn ra như thế nào v.v.... Vậy các bạn hãy chờ đợi phần 2 nhé !

Tham khảo: Sách Scrum Cơ bản - NXB Thế Giới
]]></description>
            <link>https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-1-tong-quan-ve-agile</link>
            <guid isPermaLink="true">https://hungvn.com/blog/scrum-cho-nguoi-moi-bat-djau-phan-1-tong-quan-ve-agile</guid>
            <pubDate>Sat, 04 Jan 2020 10:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Những câu lệnh command Developer nên biết]]></title>
            <description><![CDATA[
The command line makes our life so much easier since we can automate several mundane tasks and make things run smoother. Instead of clicking around in the Graphical User Interface _(GUI),_ we can fire off a couple of commands and call it job done.

A Unix shell is a command-line interpreter or shell that provides a command-line user interface for Unix-like operating systems. The shell is both an interactive command language and a scripting language and is used by the operating system to control the execution of the system using shell scripts.

Every Linux or Mac-based operating system has a command-line installed by default, usually under the name “Terminal.” The command line _(CLI)_ lets us easily move and rename files, sort through data, and navigate around the computer.

Without further ado, here are 11 command line tricks that will make your life easier.

---

# 1\. grep

```
$ grep "some string" file
```

The grep command searches for patterns in each file. It also looks for patterns separated by newline characters, and grep prints each line that matches a pattern.

![](https://miro.medium.com/max/1780/1*ovG5it9EJTZ0JG3tdOgclA.png)

The _-i_ option enables us to search for a string case-insensitively in the given file. It matches words like “REACT,” “REact,” and “react.”

```
$ grep -i "REact" file
```

We can find the number of lines that matches the given string/pattern with the _-c_ _(count)_ flag.

```
$ grep -c "react" index.js
```

![](https://miro.medium.com/max/1564/1*-KL9UvoB8RR4NKkUfHNBoQ.png)

Here’s a fun and an educational comic about the _grep_ command I found on the internet.

![](https://miro.medium.com/max/2400/1*ZkpszLnLQFRFp_cVO_Ldmw.jpeg)

In addition, the variant programs _egrep_ and _fgrep_ are the same as  
_grep -E_ and _grep -F_, respectively. These variants are deprecated,  
but are provided for backward compatibility.

You can do a lot with _grep_— read the documentation for an in-depth dive [here](http://man7.org/linux/man-pages/man1/grep.1.html).

---

# 2\. ls

```
$ ls
```

_ls_ lists files and directories in the current active path. If the _pathname_ is a file, _ls_ displays information on the file according to the requested options. If the _pathname_ is a directory, ls displays information on the files and subdirectories therein.

![](https://miro.medium.com/max/2248/1*JthCA8XeIN22yScYBJlRIw.png)

You might have noticed the files are being shown as a grey color, while the folders are blueish. This is to help us make a distinction between folders and files.

---

# 3\. pwd

```
$ pwd
```

![](https://miro.medium.com/max/1748/1*E1zXuIQ6X0aaTtVC0wZ_nw.png)

The _pwd_ command is a command-line utility for printing the current working directory. The output will print the full system path of the current working directory to standard output. By default, the _pwd_ command ignores symlinks, although the full physical path of a current directory can be shown with an option.

---

# 4\. cat

```
$ cat somefile.js
```

![](https://miro.medium.com/max/2144/1*SL7g1NHsb7dKgwmoYBySkQ.png)

The _cat_ command has three related functions with regard to a text file:

- Displaying them
- Combining copies
- Creating new ones

The most common use of cat is to read the contents of files, and _cat_ is often the most convenient program for this purpose.

In the following example, the standard output of cat is redirected using the output redirection operator (which is represented by a rightward pointing angular bracket) to file2:

```
$ cat somefile > somefile2
```

![](https://miro.medium.com/max/2296/1*NxLOMigqozU5EvxVdr1f7Q.png)

---

# 5\. echo

```
$ echo "some text"
```

The _echo_ command in Linux is used to display a line of text/string that’s passed as an argument. The _echo_ is a built-in command that’s mostly used in shell scripts and batch files to output status text to the screen or a file.

![](https://miro.medium.com/max/2088/1*1bMjVqwhueQP5hvyMMdDKA.png)

---

# 6\. touch

```
$ touch somefile
```

The _touch_ command is used to create a file without any content. The _touch_ command can be used when the user doesn’t have data to store at the time of file creation.

![](https://miro.medium.com/max/1528/1*RIrUCSW4TT_cJrnGy9ighQ.png)

Notice how we’re using _touch_ to create the file and _cat_ to look inside the file. Since the newly created _index2.js_ file is empty, the cat returns nothing.

Here are the main differences between _cat_ and*touch*:

- _cat_— Used to create the file with the content.
- _touch_— Creates a file without any content or empty files. Remember, the file created using _touch_ command is empty. This command is useful when the user doesn’t have data to store at the time of file creation.

---

# 7\. mkdir

```
$ mkdir some-directory
```

As you guessed it, mkdir creates a new empty directory in the current active path. Instead of clicking around in your text editor or GUI, use this command to create new folders.

![](https://miro.medium.com/max/2184/1*FsxDBW5HDWJn9kHsw0My7A.png)

_Note:_ Notice how we can peek inside the directory with the previous _ls_ command.

## 7.1 rm

```
$ rm someFile
```

Rm stands for remove, which does exactly what it says it does. Removes, or in other words, deletes a file.

![](https://miro.medium.com/max/2148/1*damLEKdyWY7aBPILFELVNg.png)

By default, the _rm_ command doesn’t remove directories. You need to pass the _-rf_ flag to remove directories.

```
$ rm -rf some-directory
```

![](https://miro.medium.com/max/2272/1*gXTLAllsEVTdWHCcDw83WQ.png)

_Note:_ This removes the directory unconditionally, whether the directory has content inside or not.

## 7.2 rmdir

```
$ rmdir some-directory
```

The _rmdir_ command removes the directory if there’s no content inside the directory.

![](https://miro.medium.com/max/1880/1*aUJ0VbrVb_cTUf0okMxmWA.png)

---

# 8\. tail

```
$ tail somefile
```

The _tail_ command reads a file and outputs the last part of it (the “tail”).

![](https://miro.medium.com/max/2804/1*Xvo2zdyDZqj4QhTHF0TLTg.png)

The _tail_ command is useful when going through crash reports or previous history logs. Here’s an example of its usefulness when working with file logs.

```
# tail /var/log/messages
Mar 20 12:42:22 hameda1d1c dhclient\[4334\]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x280436dd)
Mar 20 12:42:24 hameda1d1c avahi-daemon\[2027\]: Registering new address record for fe80::4639:c4ff:fe53:4908 on eth0.\*.
Mar 20 12:42:28 hameda1d1c dhclient\[4334\]: DHCPREQUEST on eth0 to 255.255.255.255 port 67 (xid=0x280436dd)
Mar 20 12:42:28 hameda1d1c dhclient\[4334\]: DHCPACK from 10.76.198.1 (xid=0x280436dd)
Mar 20 12:42:30 hameda1d1c avahi-daemon\[2027\]: Joining mDNS multicast group on interface eth0.IPv4 with address 10.76.199.87.
Mar 20 12:42:30 hameda1d1c avahi-daemon\[2027\]: New relevant interface eth0.IPv4 for mDNS.
Mar 20 12:42:30 hameda1d1c avahi-daemon\[2027\]: Registering new address record for 10.76.199.87 on eth0.IPv4.
Mar 20 12:42:30 hameda1d1c NET\[4385\]: /sbin/dhclient-script : updated /etc/resolv.conf
Mar 20 12:42:30 hameda1d1c dhclient\[4334\]: bound to 10.76.199.87 -- renewal in 74685 seconds.
Mar 20 12:45:39 hameda1d1c kernel: usb 3-7: USB disconnect, device number 2
```

---

# 9\. wget

```
$ wget someurl
```

GNU Wget is a [free software](https://www.gnu.org/philosophy/free-sw) package for retrieving files using HTTP, HTTPS, FTP, and FTPS — the most widely-used internet protocols. It’s a non-interactive command-line tool, so it may easily be called from scripts, CRON jobs, terminals without X-Windows support, etc.

![](https://miro.medium.com/max/2880/1*nbzEhCeVUxT2-Px0oQbszQ.png)

GNU Wget has many features to make retrieving large files or mirroring entire web or FTP sites easy, including:

- Can resume aborted downloads using REST and RANGE
- Can use filename wild cards and recursively mirror directories
- NLS-based message files for many different languages
- Optionally converts absolute links in downloaded documents to relative so that downloaded documents may link to each other locally
- Runs on most UNIX-like operating systems as well as Microsoft Windows
- Supports HTTP proxies
- Supports HTTP cookies
- Supports persistent HTTP connections
- Unattended / background operation
- Uses local file timestamps to determine whether documents need to be re-downloaded when mirroring
- GNU Wget is distributed under the [GNU General Public License](https://www.gnu.org/licenses/gpl.html).

Read the [official GNU documentation](https://www.gnu.org/software/wget/) for more information.

---

# 10\. find

```
$ find path -name filename
```

The _find_ command lets you quickly lookup a file or directory. It’s useful when you’re working on a big project with hundreds of files and multiple directories.

![](https://miro.medium.com/max/1696/1*j291SZcYXSaPtdvqipX6sg.png)

## Search for files of a particular type

The _find_ command also lets you search for the same type of files in a directory (and its subdirectories). For example, the following command will search for all _.js_ files in your current working directory.

```
$ find . -name "*.js"
```

![](https://miro.medium.com/max/1992/1*_i8_TEIElXAAyXy-F1JQmA.png)

---

# 11\. mv

```
$ mv somefile /to/some/other/path
```

The _mv_ command moves files or directories from one place to another. The _mv_ command supports moving single files, multiple files, and directories.

![](https://miro.medium.com/max/2360/1*TdqoyPUFrdBvI2Ws7cfyfQ.png)

---

# Conclusion

Thanks for reading, I hope you learned something new. If you know a handy command-line trick, please let’s grow together and post it in the responses.

If you want to learn more about shell commands, I suggest grabbing the _“_[_Linux for beginners_](https://amzn.to/2QazBku)_”_ book. Stay curious and hungry!
]]></description>
            <link>https://hungvn.com/blog/nhung-cau-lenh-command-developer-nen-biet</link>
            <guid isPermaLink="true">https://hungvn.com/blog/nhung-cau-lenh-command-developer-nen-biet</guid>
            <pubDate>Thu, 26 Dec 2019 08:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[So sánh Redux và React Context]]></title>
            <description><![CDATA[
React context has been there for a while. With the coming of React hooks, it's now much better. It has so many advantages, including the fact that the context API doesn't require any third-party libraries. We can use it in React apps to manage our state like redux.

In this article, we're going to manage our state with React context, to see by ourselves if it's better than redux regarding state's management.

**Note**: This article covers only the context API. We're going to build the same project with React context.

## Prerequisites

To be able to follow along, you have to know at least the basics to advance features of React and particularly React hooks. A good grasp of redux can also help.

## Setting Up the Project

If you're good to go, we can now create a new React app by running:

```javascript
npx create-react-app react-context-hooks-example
```

Then, we have to create some files.

- Add a _containers_ folder in the _src_, then create _Articles.js_ file.

```javascript
import React, { useState } from "react";

import Article from "../components/Article/Article";

const Articles = () => {
  const [articles, setArticles] = useState([
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ]);

  return (
    <div>
      {articles.map(article => (
        <Article key={article.id} article={article} />
      ))}
    </div>
  );
};

export default Articles;
```

- Add a _components_ folder in the _src_, then create _AddArticle/AddArticle.js_ and _Article/Article.js_.
- In the _Article.js_

```javascript
import React from "react";

import "./Article.css";

const article = ({ article }) => (
  <div className="article">
    {" "}
    <h1>{article.title}</h1> <p>{article.body}</p>{" "}
  </div>
);

export default article;
```

- In the _AddArticle.js_

```javascript
import React, { useState } from "react";

import "./AddArticle.css";

const AddArticle = () => {
  const [article, setArticle] = useState();

  const handleArticleData = e => {
    setArticle({
      ...article,
      [e.target.id]: e.target.value,
    });
  };
  const addNewArticle = e => {
    e.preventDefault();
    // The logic will come later
  };

  return (
    <form onSubmit={addNewArticle} className="add-article">
      <input type="text" id="title" placeholder="Title" onChange={handleArticleData} />
      <input type="text" id="body" placeholder="Body" onChange={handleArticleData} />
      <button>Add article</button>
    </form>
  );
};
export default AddArticle;
```

- In the _App.js_

```javascript
import React, { Fragment } from "react";

import AddArticle from "./components/AddArticle/AddArticle";
import Articles from "./containers/Articles";

function App() {
  return (
    <Fragment>
      <AddArticle />
      <Articles />
    </Fragment>
  );
}
export default App;
```

_So, if you've done with all the instructions above, we can move on and start implementing the context API._

## Create a context

A context helps us to handle state without passing down props on every component. Only the needed component will consume the context. To implement it, we need to create (it's optional) a new folder named _context_ in our project, and add this code below to _aricleContext.js_.

- In _context/aricleContext.js_

```javascript
import React, { createContext, useState } from "react";

export const ArticleContext = createContext();
const ArticleProvider = ({ children }) => {
  const [articles, setArticles] = useState([
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ]);

  const saveArticle = article => {
    const newArticle = {
      id: Math.random(), // not really unique but it's just an example
      title: article.title,
      body: article.body,
    };
    setArticles([...articles, newArticle]);
  };

  return (
    <ArticleContext.Provider value={{ articles, saveArticle }}>{children}</ArticleContext.Provider>
  );
};

export default ArticleProvider;
```

The React library gives us access to a method called _createContext_. We can use it to as you might guess create a context. Here, we pass nothing to our context _ArticleContext_, but you can pass as argument object, array, string, etc. Then we define a function which will help us distribute the data through the _Provider_. We give to our _Provider_ two values: the list of articles and the method to add an article. By the way, _articles:articles_ and _saveArticle:saveArticle_ is the same as _articles_ and _saveArticle_ it's just a convenient syntax in case it confuses you.

Now we've a context, however, we need to provide the context in order to consume it. To do that, we need to wrap our higher component with _ArticleProvider_ and _App.js_ might be the perfect one. So, let's add it to _App.js_.

## Provide the context

- In _App.js_

```javascript
import React from "react";

import AddArticle from "./components/AddArticle/AddArticle";
import Articles from "./containers/Articles";
import ArticleProvider from "./context/articleContext";

function App() {
  return (
    <ArticleProvider>
      <AddArticle />
      <Articles />
    </ArticleProvider>
  );
}
export default App;
```

As you see here, we first import our context provider _ArticleProvider_ and wrap components which need to consume the context. Now what about consuming the context? and how we can do that. You might be surprised how easy it is to consume the context with hooks. So, let's do that.

## Consume the context

We're going to consume the context in two components: _Articles.js_ and _AddArticle.js_.

- In _Articles.js_

```javascript
import React, { useContext } from "react"
import { ArticleContext } from "../context/articleContext"
import Article from "../components/Article/Article"

const Articles = () => {
 const { articles } = useContext(ArticleContext)  return (
    <div>
      {articles.map(article => (
        <Article key={article.id} article={article} />
      ))}
    </div>
  )
}

export default Articles
```

With React hooks, we've now access to the _useContext_ hook. And as you might guess, it will help us consume the context. By passing our context _ArticleContext_ as argument to _useContext_, it gives us access to our state holden in _articleContext.js_. Here, we just need _articles_. Therefore, we pull it out and map through our articles and show them. Now, let's move on to _AddArticle.js_.

- In _AddArticle.js_

```javascript
import React, { useState, useContext } from "react";

import { ArticleContext } from "../../context/articleContext";
import "./AddArticle.css";

const AddArticle = () => {
  const { saveArticle } = useContext(ArticleContext);
  const [article, setArticle] = useState();

  const handleArticleData = e => {
    setArticle({
      ...article,
      [e.target.id]: e.target.value,
    });
  };

  const addNewArticle = e => {
    e.preventDefault();
    saveArticle(article);
  };

  return (
    <form onSubmit={addNewArticle} className="add-article">
      <input type="text" id="title" placeholder="Title" onChange={handleArticleData} />
      <input type="text" id="body" placeholder="Body" onChange={handleArticleData} />
      <button>Add article</button>
    </form>
  );
};
export default AddArticle;
```

As the previous case, here again we use _useContext_ to pull out _saveArticle_ from our context. With that, we can now safely add a new article through the React Context.

We now manage our whole application's state through the React Context. However, we can still improve it through another hook named _useReducer_.

## Enhance the context with useReducer

The _useReducer_ hook is an alternative to _useState_. It's mostly use for the more complex state. _useReducer_ accepts a reducer function with the initial state of our React app, and returns the current state, then dispatches a function.

This will be much more clear, when we start implementing it. Now, we've to create a new file _reducer.js_ in our context folder and add this code block below.

- In _reducer.js_

```javascript
export const reducer = (state, action) => {
  switch (action.type) {
    case "ADD_ARTICLE":
      return [
        ...state,
        {
          id: Math.random(), // not really unique but it's just an example
          title: action.article.title,
          body: action.article.body,
        },
      ];
    default:
      return state;
  }
};
```

As you can see, the function _reducer_ receives two parameters: _state_ and _action_. Then, we check if the type of action is equal to _ADD_ARTICLE_ (you can create a constant or file to avoid mistyping), if it's the case add a new article to our state. This syntax might be familiar if you've used redux. Now, the logic to add a new article is handled by the reducer. We've not done yet, let's add it to our context file.

```javascript
import React, { createContext, useReducer } from "react";

import { reducer } from "./reducer";

export const ArticleContext = createContext();

const ArticleProvider = ({ children }) => {
  const [articles, dispatch] = useReducer(reducer, [
    { id: 1, title: "post 1", body: "Quisque cursus, metus vitae pharetra" },
    { id: 2, title: "post 2", body: "Quisque cursus, metus vitae pharetra" },
  ]);

  return (
    <ArticleContext.Provider value={{ articles, dispatch }}>{children}</ArticleContext.Provider>
  );
};

export default ArticleProvider;
```

Here, we start by importing the _useReducer_ hook and our function _reducer_. As i mention earlier, _useReducer_ takes a function. Therefore, we've to pass our reducer function to it and as second argument the initial state of our application. Now _useReducer_ gives us access to our _articles_ and a _dispatch_ function (you can name it whatever you like). And we can now, update our provider with these new values given by _useReducer_.

You can already see that our context file is now much cleaner. By renaming the function which add a new article to _dispatch_, we've now to update a little bit our _AddArticle.js_ file.

- In _AddArticle.js_

```javascript
import React, { useState, useContext } from "react";

import { ArticleContext } from "../../context/articleContext";
import "./AddArticle.css";

const AddArticle = () => {
  const { dispatch } = useContext(ArticleContext);
  const [article, setArticle] = useState();

  const handleArticleData = e => {
    setArticle({
      ...article,
      [e.target.id]: e.target.value,
    });
  };

  const addNewArticle = e => {
    e.preventDefault();
    dispatch({ type: "ADD_ARTICLE", article });
  };

  return (
    <form onSubmit={addNewArticle} className="add-article">
      <input type="text" id="title" placeholder="Title" onChange={handleArticleData} />
      <input type="text" id="body" placeholder="Body" onChange={handleArticleData} />
      <button>Add article</button>
    </form>
  );
};
export default AddArticle;
```

Now, instead of pulling out _saveArticle_, now we get the _dispatch_ function. It expects a type of action _ADD_ARTICLE_ and a value _article_ which will be the new article. With that, our project is now managed through the context API and React Hooks.

## Redux VS the React Context: Who wins?

You can now clearly see the difference between Redux and React Context through their implementations on our project. However, Redux is far from dead or be killed by React Context. Redux is such boilerplate and require a bunch of libraries. But it remains a great solution towards props drilling.

The context Api with hooks is much more easier to implement and will not increase your bundle size.

However who wins? in my opinion, for a low-frequency updates like locale, theme changes, user authentication, etc. the React Context is perfectly fine. But with a more complex state which has a high-frequency updates, the React Context won't be a good solution. Because, the React Context will triggers a re-render on each update, and optimizing it manually can be really tough. And there, a solution like Redux is much easier to implement.

You can find the finished project [here](https://github.com/ibrahima92/react-context-hooks-example)
]]></description>
            <link>https://hungvn.com/blog/so-sanh-redux-va-react-context</link>
            <guid isPermaLink="true">https://hungvn.com/blog/so-sanh-redux-va-react-context</guid>
            <pubDate>Mon, 16 Dec 2019 04:30:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sử dụng Google Sheets để lưu trữ dữ liệu web]]></title>
            <description><![CDATA[
Google Sheets is a very popular online spreadsheet application that anyone with a Google account can use totally free. It is very intuitive and even people with no prior experience to Spreadsheet applications will find it easy to use.

Web **[Content Management Systems](https://kinsta.com/knowledgebase/content-management-system/)** typically use the user friendly interface for the end user to manage a website content. The website manager does not have to depend on the developer for creation of new pages, posts, tags or the like. This added abstraction allows non developers to manage their websites easily. This is the reason why Content Management Systems like WordPress, Joomla and Drupal have become so popular.

Typically, Web Content Management Systems (CMS) are of two types. One using the traditional approach uses a relational database like MySQL for the backend storage. A more recent trend has seen database less CMS like [**Hugo**](https://gohugo.io/). These store the data in plain text files. For the end user or the website manager, there is no difference as the user friendly interface is visible to him/her regardless of the type of CMS he/she uses.

### When not to use a traditional CMS

For a rather complicated website, the use of a full-fledged content management system makes sense. There is a lot of content to be managed. There are plugins available to extend functionality. For single page websites or simpler ones with a few pages, using a traditional CMS is not a very smart thing to do.

The following points are important to consider --

1.  The header that a CMS loads is usually more feature rich -- meaning it has support for a lot more types of features that one may require. However, the included scripts are loaded by the CMS itself -- even if you don't use it. This adds to unnecessary bandwidth usage.
2.  A traditional RDBMS will be an additional overhead that allows database storage at the cost of speed. For a single page website, maintaining a fully functional database on the server for serving requests for each page visit is a waste of resources. A headless or static CMS that does not use a database will be faster and use far less resources.

### The advantage of using Google Sheets as backend

Google sheets is easily accessible and easy to use, even for those who have no development experience. The following advantages are worth noticing --

1.  Easy to use, no learning curve needed
2.  Accessible and platform independent. All one needs is a browser and a Google account.
3.  Version control is a part of the product offering. If there is an error, you can revert to a history version easily.
4.  Ability to share the sheets with those you want to with role based rights. This is analogous to sharing access credentials to a full CMS.

### How to use Google Sheets as a data source

This is fairly simple. You have multiple options to fetch information from Google Sheets. The Google Sheets API will give you access to all the data you need to view and manipulate.

**Step 1: **You can get a JSON response with the entire spreadsheet data. Publish the spreadsheet on the Web first.

![](http://img.thecodepost.org/2019/12/publish-google-sheets-to-web-menu-1024x548.png)

Click on File and click on Publish to Web

![](https://thecodepost.org/wp-content/uploads/2019/12/publish-google-sheets-to-web-1024x548.png)

You can share the link to the people who would be adding data to your site

![](https://thecodepost.org/wp-content/uploads/2019/12/get-google-sheets-id-1024x306.png)

Copy the sheet id starting from /d to the ending forward slash (excluding it)

**Step 2: **Now check out this URL -- https://spreadsheets.google.com/feeds/cells/SHEET_CODE/SHEET_NUMBER/public/full?alt=json

Open the Google Sheets and copy the sheet code and sheet number.

For example, my sheet is here https://docs.google.com/spreadsheets/d/1clakCW5TxaIAEhr7qujT5x3j3Sf7uGRiL-a4zjou4-I/

My sheet code is _1clakCW5TxaIAEhr7qujT5x3j3Sf7uGRiL-a4zjou4-I_ and my sheet number is 1.

Now feed them into the above URL and you will find a JSON response. -- https://spreadsheets.google.com/feeds/cells/1clakCW5TxaIAEhr7qujT5x3j3Sf7uGRiL-a4zjou4-I/1/public/full?alt=json_

![](https://thecodepost.org/wp-content/uploads/2019/12/Screenshot-from-2019-12-08-23-39-58.png)

You can get a JSON response from Google Sheets without using any third party tool

**Alternative Step 2: **The other option is to use third party APIs that actually filter out the unnecessary information (metadata) from the previous JSON response in point ii and provides the content of the sheet directly in simple JSON response.

**'[Tabletop js](https://github.com/jsoma/tabletop)**' is a good example that 'gives spreadsheets legs'.\\  
This is what I will use in this case. If you want to use the JSON response in point ii, you can do that. The advantage is that you will not have to load an extra JavaScript, but the extra effort is not worth it in my opinion.

### How to integrate Google Sheets as backend

Step 1: First create a static website using whatever tools you have at your disposal. A simple text editor should be fine. I am using Bootstrap for my basic styling requirements, so that it looks professional and familiar.

Step 2: Include the tabletop JavaScript in your page so that the Google Spreadsheet parsers can be used.

```javascript
<script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.5.1/tabletop.min.js"></script>
```

Step 3: Initiate a script block and store the path of the spreadsheet in a variable.

Follow up with a \_init() \_function with a key, callback and set simpleSheet to true.

Create a new function _showInfo_ and pass data and tabletop as arguments. This is interesting because tabletop (after _init()_) automatically holds the data of the sheet you assigned in the sheet variable in Step 2.

Step 4: Create a basic card based structure that will repeat for the number of rows there are with details.

```html
<div class="col-md-4">
  <h4 style="text-align:center;"></h4>
  <img class="img-thumbnail rounded mx-auto d-block" style="height:200px;" alt="" src=""</img>
  <p style="text-align: justify; text-justify: inter-word;"></p>
  <p><b>Status:</b></p>
  <p><b>Built Date: </b></p>
  <p><b>Destroyed Date: </b></p>
  <p><b>Destroyed by: </b></p>
  <p><a class="btn btn-outline-info href="#">View details</a></p>
</div>
```

**Step 5:** Now go back to the sheet and note down the column headers. This is how it looks now.

![](https://thecodepost.org/wp-content/uploads/2019/12/google-sheets-headers-1024x173.png)

Google Sheets Headers -- note that they are all lowercase. This helps Tabletop.

**Note: **Tabletop requires you to follow a simple guideline for naming column headers. The headers should be the first row and each of the header names should start with a small letter.

Accessing the data is simple. For instance if your header cell is named 'name', getting all names from the sheet will require you to iterate i over data\[i\].name.

Therefore for my headers in the sheet, the respective data fields are --

1.  data\[i\].no
2.  data\[i\].summary
3.  data\[i\].datebuilt
4.  data\[i\].destroyedby
5.  data\[i\].status
6.  data\[i\].details_link

So the **_Step 4_** can be re-written as --

```html
<div class="col-md-4">
  <h4 style="text-align:center;">'+data[i].name+'</h4>
  <img class="img-thumbnail rounded mx-auto d-block" style="height:200px;" alt="'+data[i].name+'" src="'+data[i].imagesrc+'"</img>
  <p style="text-align: justify; text-justify: inter-word;">' + data[i].summary + '</p>
  <p><b>Status:</b> '+ data[i].status + '</p>
  <p><b>Built Date: </b> '+ data[i].builtdate + '</p>
  <p><b>Destroyed Date: </b> '+ data[i].destroyeddate + '</p>
  <p><b>Destroyed by: </b> '+ data[i].destroyedby + '</p>
  <p><a class="btn btn-outline-info" target="_blank" href="'+data[i].details_link+'">View details</a></p>
</div>
```

**Step 6:**

Load the file up and access it over localhost. It should take a couple of seconds to actually fetch the data after loading the JavaScript, but the static content will be loaded in an instant. The appearance of the page to the end user can be further improved if the hero section of the page is enlarged to cover the entire page by default. By the time he is ready to scroll down, the images and relevant data will already be loaded.

![](https://thecodepost.org/wp-content/uploads/2019/12/google-sheets-as-cms-local-1024x526.png)

Change any data in the Google Sheets and you will see the changes done here as well

You can also debug the issues by simply enabling the Console of your browser's Developer Tools. The JSON response with the data object and its contents will be output there by default. If there is a parsing error, you can make sure the object returns the contents correctly.

![](https://thecodepost.org/wp-content/uploads/2019/12/data-object-from-google-sheets-1024x529.png)

The data array is output in the console

You can share the sheet with edit access to only those who you trust and your site will be up and running without depending on any other heavy server/database resource.

This may run into issues if there are too many records as AJAX like request will slow down to a crawl, so a pagination may be necessary. Using Apps Script on the Spreadsheet itself or conditional JavaScript logic in the page, this can be implemented.

I have hosted this on Github as well. You can [**find the site**](https://sarthakganguly.github.io/mutewitnesses/) and the [**code in the links herein**](https://github.com/sarthakganguly/mutewitnesses).
]]></description>
            <link>https://hungvn.com/blog/su-dung-google-sheets-dje-luu-tru-du-lieu-web</link>
            <guid isPermaLink="true">https://hungvn.com/blog/su-dung-google-sheets-dje-luu-tru-du-lieu-web</guid>
            <pubDate>Fri, 01 Nov 2019 10:30:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[JavaScript Design Patterns]]></title>
            <description><![CDATA[
In this article, we are going to talk about design patterns that can be and should be used to write better maintainable JavaScript code. I assume you have a basic understanding of JavaScript and concepts like classes (classes in JavaScript can be tricky), objects, prototypal inheritance, closures, etc.

This article is a long read as a whole because of the nature of the subject matter so I have tried to keep the sections self-contained. So, you as a reader can pick and choose specific parts (or in this case specific patterns) and ignore the ones you are not interested in or are well versed with. Now, let’s get started.

> Source code for the examples of all the design patterns explained here is available on **[GitHub](https://github.com/drenther/js-design-patterns)**

## Introduction

We write code to solve problems. Problems that usually have many similarities and when trying to solve them, we notice several common patterns. This is where design patterns come in.

> A **_design pattern_** is a term used in software engineering for a general reusable solution to a commonly occurring problem in software design.

The underlying concept of design patterns has been around in the software engineering industry since the very beginning, but they weren't really so formalized. [Design Patterns: Elements Of Reusable Object-Oriented Software](https://en.wikipedia.org/wiki/Design_Patterns) written by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides — the famous Gang of Four (GoF) was instrumental in pushing the formalized concept of design patterns in software engineering. Now, design patterns are an essential part of software development and have been so for a long time.

There were 23 design patterns introduced in the original book.

**Creational Patterns**

![](https://miro.medium.com/max/672/1*wPH4aXJ_Arv4jnliLUySyQ.png)

**Structural Patterns**

![](https://miro.medium.com/max/682/1*pD3iU_fQx56oDlIMMBnbNw.png)

**Behavioural Patterns**

![](https://miro.medium.com/max/673/1*weYSJ2_ZxVY8yZ8reEGq6g.png)

Design Patterns are beneficial for various reasons. They are proven solutions that the industry veterans have tried and tested. They are solid approaches that solve issues in a widely accepted way and reflect the experience and insights of the industry-leading developers that helped define them. Patterns also make your code more reusable and readable while speeding up the development process vastly.

Design patterns are by no means finished solutions. They only provide us with approaches or schemes to solve a problem.

> _**Note:** In this article, we will mainly talk about design patterns from an object-oriented point of view and in the context of their usability in modern JavaScript. That is why many classic patterns from GoF may be omitted and some modern patterns from sources like_ [**Addy Osmani’s Learn JavaScript Design Patterns**](https://addyosmani.com/resources/essentialjsdesignpatterns/book/) _will be included. The examples are kept simple for easier understanding and are hence not the most optimized implementation of their respective design patterns._

## Categories of Design Patterns

Design Patterns are usually categorized into three major groups.

### Creational Design Patterns

As the name suggests, these patterns are for handling object creational mechanisms. A Creational Pattern basically solves a problem by controlling the creation process of an object.

We will discuss the following patterns in details — **Constructor Pattern, Factory Pattern, Prototype Pattern** and **Singleton Pattern.**

### Structural Design Patterns

These patterns are concerned with class and object composition. They help structure or restructure one or more parts without affecting the entire system. In other words, they help obtain new functionalities without tampering with the existing ones.

We will discuss the following patterns in details — **Adapter Pattern, Composite Pattern, Decorator Pattern, Facade Pattern, Flyweight Pattern** and **Proxy Pattern.**

### Behavioural Design Patterns

These patterns are concerned with improving communication between dissimilar objects.

We will discuss the following patterns in details — **Chain of Responsibility Pattern, Command Pattern, Iterator Pattern, Mediator Pattern, Observer Pattern, State Pattern, Strategy Pattern** and **Template Pattern.**

## Creational Patterns

### Constructor Pattern

This is a class-based creational design pattern. Constructors are special functions that can be used to instantiate new objects with methods and properties defined by that function.

It is not one of the classic design patterns. In fact, it is more of a basic language construct than a pattern in most object-oriented languages. But in JavaScript, objects can be created on the fly without any constructor functions or “class” definition. Therefore, I think it is important to lay down the foundation for other patterns to come with this simple one.

Constructor pattern is one of the most commonly used patterns in JavaScript for creating new objects of a given kind.

In this example, we define a _Hero_ class with attributes like _name_ and _specialAbility_ and method like _getDetails_. Then, we instantiate an object _IronMan_ by invoking the constructor method with the _new_ keyword passing in the values for the respective attributes as arguments.

```javascript
// traditional Function-based syntax
function Hero(name, specialAbility) {
  // setting property values
  this.name = name;
  this.specialAbility = specialAbility;

  // declaring a method on the object
  this.getDetails = function () {
    return this.name + ' can ' + this.specialAbility;
  };
}

// ES6 Class syntax
class Hero {
  constructor(name, specialAbility) {
    // setting property values
    this._name = name;
    this._specialAbility = specialAbility;

    // declaring a method on the object
    this.getDetails = function () {
      return `${this._name} can ${this._specialAbility}`;
    };
  }
}

// creating new instances of Hero
const IronMan = new Hero('Iron Man', 'fly');

console.log(IronMan.getDetails()); // Iron Man can fly
```

### Factory Pattern

Factory Pattern is another class-based creational pattern. In this, we provide a generic interface that delegates the responsibility of object instantiation to its subclasses.

This pattern is frequently used when we need to manage or manipulate collections of objects that are different yet have many similar characteristics.

In this example, we create a factory class named _BallFactory_ that has a method that takes in parameters and depending on the parameters it delegates the object instantiation responsibility to the respective class. If the type parameter is *"football"* or *"soccer"* object instantiation is handled by _Football_ class but if it is _"basketball"_ object instantiation is handled by _Basketball_ class.

```javascript
class BallFactory {
  constructor() {
    this.createBall = function (type) {
      let ball;
      if (type === "football" || type === "soccer") ball = new Football();
      else if (type === "basketball") ball = new Basketball();
      ball.roll = function () {
        return `The ${this._type} is rolling.`;
      };

      return ball;
    };
  }
}

class Football {
  constructor() {
    this._type = "football";
    this.kick = function () {
      return "You kicked the football.";
    };
  }
}

class Basketball {
  constructor() {
    this._type = "basketball";
    this.bounce = function () {
      return "You bounced the basketball.";
    };
  }
}

// creating objects
const factory = new BallFactory();

const myFootball = factory.createBall("football");
const myBasketball = factory.createBall("basketball");

console.log(myFootball.roll()); // The football is rolling.
console.log(myBasketball.roll()); // The basketball is rolling.
console.log(myFootball.kick()); // You kicked the football.
console.log(myBasketball.bounce()); // You bounced the basketball.
```

### Prototype Pattern

This pattern is an object-based creational design pattern. In this, we use a sort of a “skeleton” of an existing object to create or instantiate new objects.

This pattern is specifically important and beneficial to JavaScript because it utilizes prototypal inheritance instead of a classic object-oriented inheritance. Hence, it plays to JavaScript’s strength and has native support.

In this example, we have a _car_ object that we use as the prototype to create another object _myCar_ with JavaScript’s _Object.create_ feature and define an extra property _owner_ on the new object.

```javascript
// using Object.create as was recommended by ES5 standard
const car = {
  noOfWheels: 4,
  start() {
    return "started";
  },
  stop() {
    return "stopped";
  },
};

// Object.create(proto[, propertiesObject])

const myCar = Object.create(car, { owner: { value: "John" } });

console.log(myCar.__proto__ === car); // true
```

### Singleton Pattern

Singleton is a special creational design pattern where only one instance of a class can exist. It works like this — if no instance of the singleton class exists then a new instance is created and returned but if an instance already exists then the reference to the existing instance is returned.

A perfect real-life example would be that of _mongoose_ (the famous Node.js ODM library for MongoDB). It utilizes the singleton pattern.

In this example, we have a _Database_ class that is a Singleton. First, we create an object _mongo_ by using the _new_ operator to invoke the _Database_ class constructor. This time an object is instantiated because none already exists. The second time, when we create the _mysql_ object, no new object is instantiated but instead the reference to the object that was instantiated earlier i.e. the _mongo_ object is returned.

```javascript
class Database {
  constructor(data) {
    if (Database.exists) {
      return Database.instance;
    }
    this._data = data;
    Database.instance = this;
    Database.exists = true;
    return this;
  }

  getData() {
    return this._data;
  }

  setData(data) {
    this._data = data;
  }
}

// usage
const mongo = new Database("mongo");
console.log(mongo.getData()); // mongo

const mysql = new Database("mysql");
console.log(mysql.getData()); // mongo
```

## Structural Patterns

### Adapter Pattern

This is a structural pattern where the interface of one class is translated into another. This pattern lets classes work together that could not otherwise because of incompatible interfaces.

This pattern is often used to create wrappers for new refactored APIs so that other existing old APIs can still work with them. This is usually done when new implementations or code refactoring (done for reasons like performance gains) result in a different public API while the other parts of the system are still using the old API and hence needs to be adapted to work together.

In this example, we have an old API i.e. _OldCalculator_ class and a new API i.e. _NewCalculator_ class. The _OldCalculator_ class provides an _operation_ method for both addition and subtraction while the _NewCalculator_ provides separate methods for addition and subtraction. The Adapter class _CalcAdapter_ wraps the _NewCalculator_ to add the _operation_ method to the public facing API while using its own addition and subtraction implementation under the hood.

```javascript
// old interface
class OldCalculator {
  constructor() {
    this.operations = function (term1, term2, operation) {
      switch (operation) {
        case "add":
          return term1 + term2;
        case "sub":
          return term1 - term2;
        default:
          return NaN;
      }
    };
  }
}

// new interface
class NewCalculator {
  constructor() {
    this.add = function (term1, term2) {
      return term1 + term2;
    };
    this.sub = function (term1, term2) {
      return term1 - term2;
    };
  }
}

// Adapter Class
class CalcAdapter {
  constructor() {
    const newCalc = new NewCalculator();

    this.operations = function (term1, term2, operation) {
      switch (operation) {
        case "add":
          // using the new implementation under the hood
          return newCalc.add(term1, term2);
        case "sub":
          return newCalc.sub(term1, term2);
        default:
          return NaN;
      }
    };
  }
}

// usage
const oldCalc = new OldCalculator();
console.log(oldCalc.operations(10, 5, "add")); // 15

const newCalc = new NewCalculator();
console.log(newCalc.add(10, 5)); // 15

const adaptedCalc = new CalcAdapter();
console.log(adaptedCalc.operations(10, 5, "add")); // 15;
```

### Composite Pattern

This is a structural design pattern that composes objects into tree-like structures to represent whole-part hierarchies. In this pattern, each node in the tree-like structure can be either an individual object or a composed collection of objects. Regardless, each node is treated uniformly.

![](https://miro.medium.com/max/373/1*yAkeYCKDaRQtMRAV2Kx5sA.png)

It is a bit complex to visualize this pattern. The easiest way to think about this is with the example of a multi-level menu. Each node can be a distinct option or it can be a menu itself which has multiple options as its child. A node component with children is a composite component while a node component without any child is a leaf component.

In this example, we create a base class of _Component_ that implements the common functionalities needed and abstracts the other methods needed. The base class also has a static method that utilizes recursion to traverse a composite tree structure made with its subclasses. Then we create two subclasses extending the base class — _Leaf_ that does not have any children and _Composite_ that can have children and hence have methods handling adding, searching and removing child functionalities. The two subclasses are used to create a composite structure i.e. a tree in this case.

```javascript
class Component {
  constructor(name) {
    this._name = name;
  }

  getNodeName() {
    return this._name;
  }

  // abstract methods that need to be overridden
  getType() {}

  addChild(component) {}

  removeChildByName(componentName) {}

  removeChildByIndex(index) {}

  getChildByName(componentName) {}

  getChildByIndex(index) {}

  noOfChildren() {}

  static logTreeStructure(root) {
    let treeStructure = "";
    function traverse(node, indent = 0) {
      treeStructure += `${"--".repeat(indent)}${node.getNodeName()}\n`;
      indent++;
      for (let i = 0, length = node.noOfChildren(); i < length; i++) {
        traverse(node.getChildByIndex(i), indent);
      }
    }

    traverse(root);
    return treeStructure;
  }
}

class Leaf extends Component {
  constructor(name) {
    super(name);
    this._type = "Leaf Node";
  }

  getType() {
    return this._type;
  }

  noOfChildren() {
    return 0;
  }
}

class Composite extends Component {
  constructor(name) {
    super(name);
    this._type = "Composite Node";
    this._children = [];
  }

  getType() {
    return this._type;
  }

  addChild(component) {
    this._children = [...this._children, component];
  }

  removeChildByName(componentName) {
    this._children = [...this._children].filter(
      component => component.getNodeName() !== componentName
    );
  }

  removeChildByIndex(index) {
    this._children = [...this._children.slice(0, index), ...this._children.slice(index + 1)];
  }

  getChildByName(componentName) {
    return this._children.find(component => component.name === componentName);
  }

  getChildByIndex(index) {
    return this._children[index];
  }

  noOfChildren() {
    return this._children.length;
  }
}

// usage
const tree = new Composite("root");
tree.addChild(new Leaf("left"));
const right = new Composite("right");
tree.addChild(right);
right.addChild(new Leaf("right-left"));
const rightMid = new Composite("right-middle");
right.addChild(rightMid);
right.addChild(new Leaf("right-right"));
rightMid.addChild(new Leaf("left-end"));
rightMid.addChild(new Leaf("right-end"));

// log
console.log(Component.logTreeStructure(tree));
/*
root
--left
--right
----right-left
----right-middle
------left-end
------right-end
----right-right
*/
```

### Decorator Pattern

This is also a structural design pattern that focuses on the ability to add behaviour or functionalities to existing classes dynamically. It is another viable alternative to sub-classing.

The decorator type behaviour is very easy to implement in JavaScript because JavaScript allows us to add methods and properties to object dynamically. The simplest approach would be to just add a property to an object but it will not be efficiently reusable.

In fact, there is a proposal to add decorators to the JavaScript language. Take a look at [**Addy Osmani’s post**](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) about decorators in JavaScript.

If you want to read about the proposal itself — it’s available [**here**](https://tc39.github.io/proposal-decorators/).

In this example, we create a _Book_ class. We further create two decorator functions that accept a book object and returns a "decorated" _book_ object — _giftWrap_ that adds one new attribute and one new function and _hardbindBook_ that adds one new attribute and edits the value of one existing attribute.

```javascript
class Book {
  constructor(title, author, price) {
    this._title = title;
    this._author = author;
    this.price = price;
  }

  getDetails() {
    return `${this._title} by ${this._author}`;
  }
}

// decorator 1
function giftWrap(book) {
  book.isGiftWrapped = true;
  book.unwrap = function () {
    return `Unwrapped ${book.getDetails()}`;
  };

  return book;
}

// decorator 2
function hardbindBook(book) {
  book.isHardbound = true;
  book.price += 5;
  return book;
}

// usage
const alchemist = giftWrap(new Book("The Alchemist", "Paulo Coelho", 10));

console.log(alchemist.isGiftWrapped); // true
console.log(alchemist.unwrap()); // 'Unwrapped The Alchemist by Paulo Coelho'

const inferno = hardbindBook(new Book("Inferno", "Dan Brown", 15));

console.log(inferno.isHardbound); // true
console.log(inferno.price); // 20
```

### Facade Pattern

This is a structural design pattern that is widely used in the JavaScript libraries. It is used to provide a unified and simpler public facing interface for ease of use that shields away from the complexities of its consisting subsystems or subclasses.

The use of this pattern is very common in libraries like jQuery.

In this example, we create a public facing API with the class _ComplaintRegistry_. It exposes only one method to be used by the client i.e. _registerComplaint_. It internally handles instantiating required objects of either _ProductComplaint_ or _ServiceComplaint_ based on the type argument. It also handles all the other complex functionalities like generating a unique ID, storing the complaint in memory, etc. But, all these complexities are hidden away using the Facade pattern.

```javascript
let currentId = 0;

class ComplaintRegistry {
  registerComplaint(customer, type, details) {
    const id = ComplaintRegistry._uniqueIdGenerator();
    let registry;
    if (type === "service") {
      registry = new ServiceComplaints();
    } else {
      registry = new ProductComplaints();
    }
    return registry.addComplaint({ id, customer, details });
  }

  static _uniqueIdGenerator() {
    return ++currentId;
  }
}

class Complaints {
  constructor() {
    this.complaints = [];
  }

  addComplaint(complaint) {
    this.complaints.push(complaint);
    return this.replyMessage(complaint);
  }

  getComplaint(id) {
    return this.complaints.find(complaint => complaint.id === id);
  }

  replyMessage(complaint) {}
}

class ProductComplaints extends Complaints {
  constructor() {
    super();
    if (ProductComplaints.exists) {
      return ProductComplaints.instance;
    }
    ProductComplaints.instance = this;
    ProductComplaints.exists = true;
    return this;
  }

  replyMessage({ id, customer, details }) {
    return `Complaint No. ${id} reported by ${customer} regarding ${details} have been filed with the Products Complaint Department. Replacement/Repairment of the product as per terms and conditions will be carried out soon.`;
  }
}

class ServiceComplaints extends Complaints {
  constructor() {
    super();
    if (ServiceComplaints.exists) {
      return ServiceComplaints.instance;
    }
    ServiceComplaints.instance = this;
    ServiceComplaints.exists = true;
    return this;
  }

  replyMessage({ id, customer, details }) {
    return `Complaint No. ${id} reported by ${customer} regarding ${details} have been filed with the Service Complaint Department. The issue will be resolved or the purchase will be refunded as per terms and conditions.`;
  }
}

// usage
const registry = new ComplaintRegistry();

const reportService = registry.registerComplaint("Martha", "service", "availability");
// 'Complaint No. 1 reported by Martha regarding availability have been filed with the Service Complaint Department. The issue will be resolved or the purchase will be refunded as per terms and conditions.'

const reportProduct = registry.registerComplaint("Jane", "product", "faded color");
// 'Complaint No. 2 reported by Jane regarding faded color have been filed with the Products Complaint Department. Replacement/Repairment of the product as per terms and conditions will be carried out soon.'
```

### Flyweight Pattern

This is a structural design pattern focused on efficient data sharing through fine-grained objects. It is used for efficiency and memory conservation purposes.

This pattern can be used for any kind of caching purposes. In fact, modern browsers use a variant of flyweight pattern to prevent loading same images twice.

In this example, we create a fine-grained flyweight class _Icecream_ for sharing data regarding ice-cream flavours and a factory class _IcecreamFactory_ to create those flyweight objects. For memory conservation, the objects are recycled if the same object is instantiated twice. This is a simple example of flyweight implementation.

```javascript
// flyweight class
class Icecream {
  constructor(flavour, price) {
    this.flavour = flavour;
    this.price = price;
  }
}

// factory for flyweight objects
class IcecreamFactory {
  constructor() {
    this._icecreams = [];
  }

  createIcecream(flavour, price) {
    let icecream = this.getIcecream(flavour);
    if (icecream) {
      return icecream;
    } else {
      const newIcecream = new Icecream(flavour, price);
      this._icecreams.push(newIcecream);
      return newIcecream;
    }
  }

  getIcecream(flavour) {
    return this._icecreams.find(icecream => icecream.flavour === flavour);
  }
}

// usage
const factory = new IcecreamFactory();

const chocoVanilla = factory.createIcecream("chocolate and vanilla", 15);
const vanillaChoco = factory.createIcecream("chocolate and vanilla", 15);

// reference to the same object
console.log(chocoVanilla === vanillaChoco); // true
```

### Proxy Pattern

This is a structural design pattern that behaves exactly as its name suggests. It acts as a surrogate or placeholder for another object to control access to it.

It is usually used in situations where a target object is under constraints and may not be able to handle all its responsibility efficiently. A proxy, in this case, usually provides the same interface to the client and adds a level of indirection to support controlled access to the target object to avoid undue pressure on it.

The proxy pattern can be very useful when working with network request heavy applications to avoid unnecessary or redundant network requests.

In this example, we will use two new ES6 features [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) and [Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect). A Proxy object is used to define custom behaviour for fundamental operations of a JavaScript object (remember, function and arrays are also object in JavaScript). It is a constructor method that can be used to create a _Proxy_ object. It accepts a _target_ object that is to be proxied and a _handler_ object that will define the necessary customization. The handler object allows defining some trap functions like _get_, _set_, _has_, _apply_, etc. that are used to add custom behaviour attached to their usage. _Reflect_, on the other hand, is a built-in object that provides similar methods that are supported by the handler object of Proxy as static methods on itself. It is not a constructor, it's static methods are used for interceptable JavaScript operations.

Now, we create a function that can be thought of as a network request. We named it as *networkFetch*. It accepts a URL and responds accordingly. We want to implement a proxy where we only get the response from the network if it is not available in our cache otherwise we just return a response from the cache. The _cache_ global variable will store our cached responses. We create a proxy named _proxiedNetworkFetch_ with our original _networkFetch_ as the _target_ and use apply method in our _handler_ object to proxy the function invocation. The apply method gets passed on the _target_ object itself, this value as *thisArg* and the arguments passed to it in an array-like structure _args_. We check if the passed url argument is in the cache, if it exists in the cache we return the response from there, never invoking the original target function. If it does not, then we use the _Reflect.apply_ method to invoke the _target_ function with _thisArg_ (although it's not of any significance in our case here) and the arguments it was passed.

```javascript
// Target
function networkFetch(url) {
  return `${url} - Response from network`;
}

// Proxy
// ES6 Proxy API = new Proxy(target, handler);
const cache = [];
const proxiedNetworkFetch = new Proxy(networkFetch, {
  apply(target, thisArg, args) {
    const urlParam = args[0];
    if (cache.includes(urlParam)) {
      return `${urlParam} - Response from cache`;
    } else {
      cache.push(urlParam);
      return Reflect.apply(target, thisArg, args);
    }
  },
});

// usage
console.log(proxiedNetworkFetch("dogPic.jpg")); // 'dogPic.jpg - Response from network'
console.log(proxiedNetworkFetch("dogPic.jpg")); // 'dogPic.jpg - Response from cache'
```

## Behavioural Pattern

### Chain of Responsibility Pattern

This is a behavioural design pattern that provides a chain of loosely coupled objects. Each of these objects can choose to act on or handle the request of the client.

A good example of the chain of responsibility pattern is the event bubbling in DOM in which an event propagates through a series of nested DOM elements, one of which may have an “event listener” attached to listen and act on the event.

In this example, we create a class _CumulativeSum_ which can be instantiated with an optional _initialValue_. It has a method _add_ that adds the passed value to the _sum_ attribute of the object and returns the _object_ itself to allow chaining of _add_ method calls.

This is a common pattern that can be seen in jQuery as well where almost any method call on a jQuery object returns a jQuery object so that method calls can be chained together.

```javascript
class CumulativeSum {
  constructor(intialValue = 0) {
    this.sum = intialValue;
  }

  add(value) {
    this.sum += value;
    return this;
  }
}

// usage
const sum1 = new CumulativeSum();
console.log(sum1.add(10).add(2).add(50).sum); // 62

const sum2 = new CumulativeSum(10);
console.log(sum2.add(10).add(20).add(5).sum); // 45
```

### Command Pattern

This is a behavioural design pattern that aims to encapsulate actions or operations as objects. This pattern allows loose coupling of systems and classes by separating the objects that request an operation or invoke a method from the ones that execute or process the actual implementation.

The clipboard interaction API resembles the command pattern somewhat. If you are a Redux user, you have already come across the Command pattern. The actions, that allow the awesome time-travel debugging feature, are nothing but encapsulated operations that can be tracked to redo or undo operations. Hence, time-travelling made possible.

In this example, we have a class _SpecialMath_ that has multiple methods and a _Command_ class that encapsulates commands that are to be executed on its subject i.e. an object of the _SpecialMath_ class. The _Command_ class also keeps track of all the commands executed which can be used to extend its functionality to include undo and redo type operations.

```javascript
class SpecialMath {
  constructor(num) {
    this._num = num;
  }

  square() {
    return this._num ** 2;
  }

  cube() {
    return this._num ** 3;
  }

  squareRoot() {
    return Math.sqrt(this._num);
  }
}

class Command {
  constructor(subject) {
    this._subject = subject;
    this.commandsExecuted = [];
  }
  execute(command) {
    this.commandsExecuted.push(command);
    return this._subject[command]();
  }
}

// usage
const x = new Command(new SpecialMath(5));
x.execute("square");
x.execute("cube");

console.log(x.commandsExecuted); // ['square', 'cube']
```

### Iterator Pattern

It is a behavioural design pattern that provides a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Iterators have a special kind of behaviour where we step through an ordered set of values one at a time by calling _next()_ until we reach the end. The introduction of Iterator and Generators in ES6 made the implementation of iterator pattern extremely straightforward.

We have two examples below, first one _IteratorClass_ uses Iterator spec while the other one _iteratorUsingGenerator_ uses Generator functions.

The *Symbol.iterator* ( *Symbol* - a new kind of primitive data type) is used to specify the default iterator for an object. It is must be defined for a collection to be able to use *for...of* looping construct. In the first example, we define the constructor to store some collection of data and then define _Symbol.iterator_ which returns an object with _next_ method for iteration.

For the second case, we define a generator function passing it an array of data and return its elements iteratively using _next_ and _yield_. A generator function is a special type of function that works as a factory for iterators and can explicitly maintain its own internal state and yield values iteratively. It can pause and resume its own execution cycle.

```javascript
// using Iterator
class IteratorClass {
  constructor(data) {
    this.index = 0;
    this.data = data;
  }

  [Symbol.iterator]() {
    return {
      next: () => {
        if (this.index < this.data.length) {
          return { value: this.data[this.index++], done: false };
        } else {
          this.index = 0; // to reset iteration status
          return { done: true };
        }
      },
    };
  }
}

// using Generator
function* iteratorUsingGenerator(collection) {
  var nextIndex = 0;

  while (nextIndex < collection.length) {
    yield collection[nextIndex++];
  }
}

// usage
const gen = iteratorUsingGenerator(["Hi", "Hello", "Bye"]);

console.log(gen.next().value); // 'Hi'
console.log(gen.next().value); // 'Hello'
console.log(gen.next().value); // 'Bye'
```

### Mediator Pattern

It is a behavioural design pattern that encapsulates how a set of object interact with each other. It provides the central authority over a group of objects by promoting loose coupling by keeping objects from referring to each other explicitly.

In this example, we have _TrafficTower_ as Mediator that controls the way _Airplane_ objects interact with each other. All the _Airplane_ objects register themselves with a _TrafficTower_ object and it is the mediator class object that handles how an _Airplane_ object receives coordinates data of all the other _Airplane_ objects.

```javascript
class TrafficTower {
  constructor() {
    this._airplanes = [];
  }

  register(airplane) {
    this._airplanes.push(airplane);
    airplane.register(this);
  }

  requestCoordinates(airplane) {
    return this._airplanes.filter(plane => airplane !== plane).map(plane => plane.coordinates);
  }
}

class Airplane {
  constructor(coordinates) {
    this.coordinates = coordinates;
    this.trafficTower = null;
  }

  register(trafficTower) {
    this.trafficTower = trafficTower;
  }

  requestCoordinates() {
    if (this.trafficTower) return this.trafficTower.requestCoordinates(this);
    return null;
  }
}

// usage
const tower = new TrafficTower();

const airplanes = [new Airplane(10), new Airplane(20), new Airplane(30)];
airplanes.forEach(airplane => {
  tower.register(airplane);
});

console.log(airplanes.map(airplane => airplane.requestCoordinates()));
// [[20, 30], [10, 30], [10, 20]]
```

### Observer Pattern

It is a crucial behavioural design pattern that defines one-to-many dependencies between objects so that when one object (publisher) changes its state, all the other dependent objects (subscribers) are notified and updated automatically. This is also called PubSub (Publisher/Subscribers) or Event Dispatcher/Listeners Pattern. The Publisher is sometimes called Subject and the Subscribers are sometimes called Observers.

Chances are you are already somewhat familiar with this pattern if you have used addEventListener or jQuery’s on to write event handling code. It has its influences in Reactive Programming (think RxJS) as well.

In the example, we create a simple _Subject_ class that has methods to add and remove objects of _Observer_ class from subscriber collection. Also, a _fire_ method to propagate any changes in the _Subject_ class object to the subscribed Observers. The _Observer_ class, on the other hand, has its internal state and a method to update its internal state based on the change propagated from the _Subject_ it has subscribed to.

```javascript
class Subject {
  constructor() {
    this._observers = [];
  }

  subscribe(observer) {
    this._observers.push(observer);
  }

  unsubscribe(observer) {
    this._observers = this._observers.filter(obs => observer !== obs);
  }

  fire(change) {
    this._observers.forEach(observer => {
      observer.update(change);
    });
  }
}

class Observer {
  constructor(state) {
    this.state = state;
    this.initialState = state;
  }

  update(change) {
    let state = this.state;
    switch (change) {
      case "INC":
        this.state = ++state;
        break;
      case "DEC":
        this.state = --state;
        break;
      default:
        this.state = this.initialState;
    }
  }
}

// usage
const sub = new Subject();

const obs1 = new Observer(1);
const obs2 = new Observer(19);

sub.subscribe(obs1);
sub.subscribe(obs2);

sub.fire("INC");

console.log(obs1.state); // 2
console.log(obs2.state); // 20
```

### State Pattern

It is a behavioural design pattern that allows an object to alter its behaviour based on changes to its internal state. The object returned by a State pattern class seems to change its class. It provides state-specific logic to a limited set of objects in which each object type represents a particular state.

We will take a simple example of a traffic light to understand this pattern. The _TrafficLight_ class changes the object it returns based on its internal state which is an object of _Red_, _Yellow_ or _Green_ class.

```javascript
class TrafficLight {
  constructor() {
    this.states = [new GreenLight(), new RedLight(), new YellowLight()];
    this.current = this.states[0];
  }

  change() {
    const totalStates = this.states.length;
    let currentIndex = this.states.findIndex(light => light === this.current);
    if (currentIndex + 1 < totalStates) this.current = this.states[currentIndex + 1];
    else this.current = this.states[0];
  }

  sign() {
    return this.current.sign();
  }
}

class Light {
  constructor(light) {
    this.light = light;
  }
}

class RedLight extends Light {
  constructor() {
    super("red");
  }

  sign() {
    return "STOP";
  }
}

class YellowLight extends Light {
  constructor() {
    super("yellow");
  }

  sign() {
    return "STEADY";
  }
}

class GreenLight extends Light {
  constructor() {
    super("green");
  }

  sign() {
    return "GO";
  }
}

// usage
const trafficLight = new TrafficLight();

console.log(trafficLight.sign()); // 'GO'
trafficLight.change();

console.log(trafficLight.sign()); // 'STOP'
trafficLight.change();

console.log(trafficLight.sign()); // 'STEADY'
trafficLight.change();

console.log(trafficLight.sign()); // 'GO'
trafficLight.change();

console.log(trafficLight.sign()); // 'STOP'
```

### Strategy Pattern

It is a behavioural design pattern that allows encapsulation of alternative algorithms for a particular task. It defines a family of algorithms and encapsulates them in such a way that they are interchangeable at runtime without client interference or knowledge.

In the example below, we create a class _Commute_ for encapsulating all the possible strategies for commuting to work. Then, we define three strategies namely _Bus_, _PersonalCar_ and _Taxi_. Using this pattern we can swap the implementation to use for the _travel_ method of the _Commute_ object at runtime.

```javascript
// encapsulation
class Commute {
  travel(transport) {
    return transport.travelTime();
  }
}

class Vehicle {
  travelTime() {
    return this._timeTaken;
  }
}

// strategy 1
class Bus extends Vehicle {
  constructor() {
    super();
    this._timeTaken = 10;
  }
}

// strategy 2
class Taxi extends Vehicle {
  constructor() {
    super();
    this._timeTaken = 5;
  }
}

// strategy 3
class PersonalCar extends Vehicle {
  constructor() {
    super();
    this._timeTaken = 3;
  }
}

// usage
const commute = new Commute();

console.log(commute.travel(new Taxi())); // 5
console.log(commute.travel(new Bus())); // 10
```

### Template Pattern

This is a behavioural design pattern is based on defining the skeleton of the algorithm or implementation of an operation, but deferring some steps to subclasses. It lets subclasses redefine certain steps of an algorithm without changing the algorithm’s outward structure.

In this example, we have a Template class _Employee_ that implements _work_ method partially. It is for the subclasses to implement responsibilities method to make it work as a whole. We then create two subclasses _Developer_ and _Tester_ that extend the Template class and implement the required method to fill the implementation gap.

```javascript
class Employee {
  constructor(name, salary) {
    this._name = name;
    this._salary = salary;
  }

  work() {
    return `${this._name} handles ${this.responsibilities() /* gap to be filled by subclass */}`;
  }

  getPaid() {
    return `${this._name} got paid ${this._salary}`;
  }
}

class Developer extends Employee {
  constructor(name, salary) {
    super(name, salary);
  }

  // details handled by subclass
  responsibilities() {
    return "application development";
  }
}

class Tester extends Employee {
  constructor(name, salary) {
    super(name, salary);
  }

  // details handled by subclass
  responsibilities() {
    return "testing";
  }
}

// usage
const dev = new Developer("Nathan", 100000);
console.log(dev.getPaid()); // 'Nathan got paid 100000'
console.log(dev.work()); // 'Nathan handles application development'

const tester = new Tester("Brian", 90000);
console.log(tester.getPaid()); // 'Brian got paid 90000'
console.log(tester.work()); // 'Brian handles testing'
```

## Conclusion

Design patterns are crucial to software engineering and can be very helpful in solving common problems. But, this is a very vast subject and it is simply not possible to include everything about them in a short blog post. Therefore, I made the choice to shortly and concisely talk only about the ones I think can be really handy in writing modern JavaScript. To dive deeper, I suggest you take a look at these books -

1.  **[Design Patterns: Elements Of Reusable Object-Oriented Software](https://en.wikipedia.org/wiki/Design_Patterns) **by *Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides (Gang of Four)*
2.  [**Learn JavaScript Design Patterns** ](https://addyosmani.com/resources/essentialjsdesignpatterns/book/)by _Addy Osmani_
3.  **[JavaScript Patterns](https://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752)** by _Stoyan Stefanov_
]]></description>
            <link>https://hungvn.com/blog/javascript-design-patterns</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-design-patterns</guid>
            <pubDate>Tue, 08 Oct 2019 04:15:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách viết CV tốt hơn cho Web Developer]]></title>
            <description><![CDATA[
Tooi have met plenty of very talented engineers over the years who struggle to get called into interviews directly due to an unprofessional, sloppy or unfocused CV. I know when I started applying to jobs this was something I struggled with. So I’m hoping now that I have been on all sides of the interview process I can help other engineers get over the first hurdle.

_Skip to the end for a free CV template!_

Let’s first break it down section by section.

## Header

The header should include your name, contact details and a link to your GitHub — and if you have one, your personal website. It should also include a title matching the role you are applying for. I also like to include some bullet points of skills tailored for the role. For example, if you are applying for a Frontend role you should have something like:

_John Fakerson_

_Frontend Developer_

_Github — Website_

_Email_

_Phone_

_Agile development Practice ▪ JavaScript development ▪ HTML5 ▪ CSS3 ▪ Cross-browser compatibility_

## Intro

The intro should be brief and professional. It should be less of an introduction and more of a headline, a teaser that makes the reader feel like it’s worth reading on. You are better off having a single focused sentence here than rambling about how “enthusiastic” you are.

_A senior engineer with over 6 years experience in software development. Experienced in leading teams, mentoring engineers and software architecture._

## Technical Skills

Again sticking to the theme of being relevant, add a section about all of your relevant technical skills to the role. So for a frontend role, this might be suitable:

![](https://miro.medium.com/max/2632/1*1QpufvJSVV_WM7eSoIPlOw.png)

## Experience / Job History

If you are just looking for your first job, this section is always the most terrifying because you probably feel like you don’t have much worth mentioning. [John Sonmez](https://medium.com/u/56e8cba02b?source=post_page-----6d27f37d4e67----------------------) has a great video to help you get started with “no experience” or how you should build your experience section.

But for the rest of you…

This should be brief, focused and include relevant bullet points. It should follow a structure of — Company name, your job title, the date you started/finished and then a summary of the role finishing with bullet points with the technical skills you used in the role.

_**Professional Experience**_

_Fake Company 1 2012 — Present_

_.NET Developer_

_It was my responsibility to develop the online systems within Fake Company 1. This included management of the company’s cloud solution and involvement in the entire development lifecycle of their product. Etc…_

- _It was my responsibility to manage the design and development of all aspects of the company’s IT systems. This included managing the overall operation of the IT systems and software._
- _Team Size_
- _Projects_
- _Technologies used_
- _Continue on in this way._

Do this for each of your relevant roles and it’s an easy, digestible format for the reader.

## Education and Training

For a lot of companies, education or at least some technical coursework will be important to show that you are a capable learner. Although a degree is not always required for a role, you should definitely be including at the bare minimum some of the online courses and tutorials you have finished.

_**Education:**_

_2004–2005 Fake University of Ireland: Degree in Computer Science_

_2001–2004 Fake University of Ireland: Masters in Computer Science_

_**Technical Courses Completed:**_

_2002–2003 Udemy Course Java Course 1_

_2000–2001 Java College Java Course 2_

_1999–2000 Code Academy Java Course 3_

## Other

Most companies will also like to see that you are not just a one-dimensional coding robot, as it can also help with conversation starters in an interview. You can also throw in a little more about how you are staying up to date. For example, I always include a MeetUp I’m a member of, a sporty hobby and a nerdy hobby. Be creative here, you can grab someone’s attention with an odd hobby.

_**Other**_

- _Member of code for Ireland_
- _Fitness Enthusiast: Regularly attend the gym_
- _Computer Games_

## References

I don’t usually include references on the end of my CV but do include a “References available upon request”. If you have references from jobs (not your current role) it would be helpful to include them here as it might speed up the hiring process. Usually, references are used after a candidate has progressed through all of the stages of the interview.

# More Tips…

## Brief and to the point

Every section of your CV should be kept relevant and as brief as possible to show how you add value. You don’t need to have flowery language skills, you want to show your technical and interpersonal competencies as clearly as possible.

## Keep it up to date

I like to come back to my CV and keep it updated every few months. Sometimes an unexpected opportunity might come knocking and it’s good to be prepared. It’s also a nice way to track your experience so you know you are always constructively building on to your CV.

## Use a template

Job sites like Monster offer some great CV templates, and I think you should be using some sort of template to aid you so you don’t lose hours on formatting pointlessly. They are also great as guidelines for what to include to keep you on track. Your choice of font and layout are key to making sure a would-be employer carries on reading your CV. Simple formats work best. I have attached my own template for you to use and abuse [here](https://docs.google.com/document/d/1X-Vhjga7a5NLLbhJ5rdBIaNkygpIX2-9hJx9U6h9wys/edit?usp=sharing).

## Check and check again

Avoid errors at all costs. You might think you made no mistakes but you probably did somewhere. Check for date conflicts, make sure your email, phone number and links all work and are correct. Ask a friend proofread your CV when you think it is done. You should also be using tools like [Grammarly](https://app.grammarly.com/) to make your life a little easier.

It should go without saying but… use your spell-check.

**Now go forth and smite those job interviews!**

Grab your free CV template [here](https://docs.google.com/document/d/1X-Vhjga7a5NLLbhJ5rdBIaNkygpIX2-9hJx9U6h9wys/edit?usp=sharing).

If this helped or you have any improvements, please add some comments below ❤️
]]></description>
            <link>https://hungvn.com/blog/cach-viet-cv-tot-hon-cho-web-developer</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-viet-cv-tot-hon-cho-web-developer</guid>
            <pubDate>Thu, 12 Sep 2019 21:42:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về npm-link]]></title>
            <description><![CDATA[
Sometimes you need to work on application code and dependency at the same time. You might be the author of a dependency and don’t have good test coverage yet. The application can serve as an end-to-end test for the dependency. Maybe you need to debug an issue in your application and the problem seems to be in the dependency sources.

![](https://miro.medium.com/max/1418/0*wvDueqq35PXNE1qA)

You could make changes in node_modules and manually copy the changes to the git repository of the dependency once you are done. But there is a much cleaner approach: npm link.

## Usage

Package linking is a two-step process:

1.  Create a global symlink for a dependency with npm link. A **symlink**, short for symbolic link, is a shortcut that points to another directory or file on your system.
2.  Tell the application to use the global symlink with npm link some-dep.

```js
cd ~/projects/some-dep
npm link  # Step 1.
cd ~/projects/my-app
npm link some-dep  # Step 2.
```

![](https://miro.medium.com/max/1834/0*x8jMbWUMifff9Eao)

You can edit, transpile, run tests, or commit as usual in some-dep. All while my-app runs with the changes you made to some-dep. The symbolic links are local and will not be committed to git. When you are ready to share your code, publish a new version of some-dep or push to a branch that you specify in my-app’s package.json:

```js
cd ~/projects/my-app
npm install — save some-dep@fhinkel/some-dep#experimental-branch
```

## Debugging

If you use [VSCode](https://code.visualstudio.com/) and want to set breakpoints in some-dep, you need to enable symlinks in the debugger for my-app. Do so by setting

```js
"runtimeArgs": [
  "--preserve-symlinks"
]
```

in launch.json.

![](https://miro.medium.com/max/1600/0*H1TB22svP8POFP8p)

## Back to Normal

How do you switch back to _normal_ dependencies? When you don’t want to use the local version of some-dep anymore, delete the symlink. But careful, npm unlink is an alias for npm uninstall, it does not mirror the behavior of npm link.

```js
cd ~/projects/my-app
npm uninstall --no-save some-dep && npm install
```

You can clean up the global link, though its presence won’t interfere with my-app.

```js
cd ~/projects/some-dep
npm uninstall  # Delete global symlink
```

## Conclusion

I used npm link while working on dependencies of the [client libraries](https://github.com/googleapis/google-cloud-node) for Google Cloud Platform. All our libraries use the module @google-cloud/common. In some cases I needed to immediately see the changes in the larger libraries instead of in isolation in common.

**Mastering the two-step process of** **npm link** **is a useful addition to the toolset of any Node.js developer.** The process consists of running npm link in the dependency, and npm link some-dep in the application.
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-ve-npm-link</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-ve-npm-link</guid>
            <pubDate>Fri, 06 Sep 2019 22:10:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giải thích chi tiết về Javascript Modules]]></title>
            <description><![CDATA[
If you’re a newcomer to JavaScript, jargon like “module bundlers vs. module loaders,” “Webpack vs. Browserify” and “AMD vs. CommonJS” can quickly become overwhelming.

The JavaScript module system may be intimidating, but understanding it is vital for web developers.

In this post, I’ll unpack these buzzwords for you in plain English (and a few code samples). I hope you find it helpful!

_Note: for simplicity’s sake, this will be divided into two sections: Part 1 will dive into explaining what modules are and why we use them. Part 2 (posted next week) will walk through what it means to bundle modules and the different ways to do so._

# Part 1: Can someone please explain what modules are again?

Good authors divide their books into chapters and sections; good programmers divide their programs into modules.

Like a book chapter, modules are just clusters of words (or code, as the case may be).

Good modules, however, are highly self-contained with distinct functionality, allowing them to be shuffled, removed, or added as necessary, without disrupting the system as a whole.

# Why use modules?

There are a lot of benefits to using modules in favor of a sprawling, interdependent codebase. The most important ones, in my opinion, are:

**1) Maintainability:** By definition, a module is self-contained. A well-designed module aims to lessen the dependencies on parts of the codebase as much as possible, so that it can grow and improve independently. Updating a single module is much easier when the module is decoupled from other pieces of code.

Going back to our book example, if you wanted to update a chapter in your book, it would be a nightmare if a small change to one chapter required you to tweak every other chapter as well. Instead, you’d want to write each chapter in such a way that improvements could be made without affecting other chapters.

**2) Namespacing:** In JavaScript, variables outside the scope of a top-level function are global (meaning, everyone can access them). Because of this, it’s common to have “namespace pollution”, where completely unrelated code shares global variables.

Sharing global variables between unrelated code is a big [no-no in development](http://c2.com/cgi/wiki?GlobalVariablesAreBad).

As we’ll see later in this post, modules allow us to avoid namespace pollution by creating a private space for our variables.

**3) Reusability:** Let’s be honest here: we’ve all copied code we previously wrote into new projects at one point or another. For example, let’s imagine you copied some utility methods you wrote from a previous project to your current project.

That’s all well and good, but if you find a better way to write some part of that code you’d have to go back and remember to update it everywhere else you wrote it.

This is obviously a huge waste of time. Wouldn’t it be much easier if there was — wait for it — a module that we can reuse over and over again?

# How can you incorporate modules?

There are many ways to incorporate modules into your programs. Let’s walk through a few of them:

## Module pattern

The Module pattern is used to mimic the concept of classes (since JavaScript doesn’t natively support classes) so that we can store both public and private methods and variables inside a single object — similar to how classes are used in other programming languages like Java or Python. That allows us to create a public facing API for the methods that we want to expose to the world, while still encapsulating private variables and methods in a closure scope.

There are several ways to accomplish the module pattern. In this first example, I’ll use an anonymous closure. That’ll help us accomplish our goal by putting all our code in an anonymous function. (Remember: in JavaScript, functions are the only way to create new scope.)

**Example 1: Anonymous closure**

```js
(function () {
  // We keep these variables private inside this closure scope

  var myGrades = [93, 95, 88, 0, 55, 91];

  var average = function () {
    var total = myGrades.reduce(function (accumulator, item) {
      return accumulator + item;
    }, 0);

    return "Your average grade is " + total / myGrades.length + ".";
  };

  var failing = function () {
    var failingGrades = myGrades.filter(function (item) {
      return item < 70;
    });

    return "You failed " + failingGrades.length + " times.";
  };

  console.log(failing());
})();

// ‘You failed 2 times.’
```

With this construct, our anonymous function has its own evaluation environment or “closure”, and then we immediately evaluate it. This lets us hide variables from the parent (global) namespace.

What’s nice about this approach is that is that you can use local variables inside this function without accidentally overwriting existing global variables, yet still access the global variables, like so:

```js
var global = "Hello, I am a global variable :)";

(function () {
  // We keep these variables private inside this closure scope

  var myGrades = [93, 95, 88, 0, 55, 91];

  var average = function () {
    var total = myGrades.reduce(function (accumulator, item) {
      return accumulator + item;
    }, 0);

    return "Your average grade is " + total / myGrades.length + ".";
  };

  var failing = function () {
    var failingGrades = myGrades.filter(function (item) {
      return item < 70;
    });

    return "You failed " + failingGrades.length + " times.";
  };

  console.log(failing());
  console.log(global);
})();

// 'You failed 2 times.'
// 'Hello, I am a global variable :)'
```

Note that the parenthesis around the anonymous function are required, because statements that begin with the keyword _function_ are always considered to be function declarations (remember, you can’t have unnamed function declarations in JavaScript.) Consequently, the surrounding parentheses create a function expression instead. If you’re curious, you can [read more here](http://stackoverflow.com/questions/1634268/explain-javascripts-encapsulated-anonymous-function-syntax).

**Example 2: Global import**  
Another popular approach used by libraries like [jQuery](https://github.com/jquery/jquery/tree/master/src) is global import. It’s similar to the anonymous closure we just saw, except now we pass in globals as parameters:

```js
(function (globalVariable) {
  // Keep this variables private inside this closure scope
  var privateFunction = function () {
    console.log("Shhhh, this is private!");
  };

  // Expose the below methods via the globalVariable interface while
  // hiding the implementation of the method within the
  // function() block

  globalVariable.each = function (collection, iterator) {
    if (Array.isArray(collection)) {
      for (var i = 0; i < collection.length; i++) {
        iterator(collection[i], i, collection);
      }
    } else {
      for (var key in collection) {
        iterator(collection[key], key, collection);
      }
    }
  };

  globalVariable.filter = function (collection, test) {
    var filtered = [];
    globalVariable.each(collection, function (item) {
      if (test(item)) {
        filtered.push(item);
      }
    });
    return filtered;
  };

  globalVariable.map = function (collection, iterator) {
    var mapped = [];
    globalUtils.each(collection, function (value, key, collection) {
      mapped.push(iterator(value));
    });
    return mapped;
  };

  globalVariable.reduce = function (collection, iterator, accumulator) {
    var startingValueMissing = accumulator === undefined;

    globalVariable.each(collection, function (item) {
      if (startingValueMissing) {
        accumulator = item;
        startingValueMissing = false;
      } else {
        accumulator = iterator(accumulator, item);
      }
    });

    return accumulator;
  };
})(globalVariable);
```

In this example, **_globalVariable_** is the only variable that’s global. The benefit of this approach over anonymous closures is that you declare the global variables upfront, making it crystal clear to people reading your code.

**Example 3: Object interface**  
Yet another approach is to create modules using a self-contained object interface, like so:

```js
var myGradesCalculate = (function () {
  // Keep this variable private inside this closure scope
  var myGrades = [93, 95, 88, 0, 55, 91];

  // Expose these functions via an interface while hiding
  // the implementation of the module within the function() block

  return {
    average: function () {
      var total = myGrades.reduce(function (accumulator, item) {
        return accumulator + item;
      }, 0);

      return "Your average grade is " + total / myGrades.length + ".";
    },

    failing: function () {
      var failingGrades = myGrades.filter(function (item) {
        return item < 70;
      });

      return "You failed " + failingGrades.length + " times.";
    },
  };
})();

myGradesCalculate.failing(); // 'You failed 2 times.'
myGradesCalculate.average(); // 'Your average grade is 70.33333333333333.'
```

As you can see, this approach lets us decide what variables/methods we want to keep private (e.g. **_myGrades_**) and what variables/methods we want to expose by putting them in the return statement (e.g. **_average_** & **_failing_**).

**Example 4: Revealing module pattern**  
This is very similar to the above approach, except that it ensures all methods and variables are kept private until explicitly exposed:

```js
var myGradesCalculate = (function () {
  // Keep this variable private inside this closure scope
  var myGrades = [93, 95, 88, 0, 55, 91];

  var average = function () {
    var total = myGrades.reduce(function (accumulator, item) {
      return accumulator + item;
    }, 0);

    return "Your average grade is " + total / myGrades.length + ".";
  };

  var failing = function () {
    var failingGrades = myGrades.filter(function (item) {
      return item < 70;
    });

    return "You failed " + failingGrades.length + " times.";
  };

  // Explicitly reveal public pointers to the private functions
  // that we want to reveal publicly

  return {
    average: average,
    failing: failing,
  };
})();

myGradesCalculate.failing(); // 'You failed 2 times.'
myGradesCalculate.average(); // 'Your average grade is 70.33333333333333.'
```

That may seem like a lot to take in, but it’s just the tip of the iceberg when it comes to module patterns. Here are a few of the resources I found useful in my own explorations:

- [Learning JavaScript Design Patterns](https://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript) by Addy Osmani: a treasure trove of details in an impressively succinct read
- [Adequately Good by Ben Cherry](http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html): a useful overview with examples of advanced usage of the module pattern
- [Blog of Carl Danley](https://carldanley.com/js-module-pattern/): module pattern overview and resources for other JavaScript patterns.

# CommonJS and AMD

The approaches above all have one thing in common: the use of a single global variable to wrap its code in a function, thereby creating a private namespace for itself using a closure scope.

While each approach is effective in its own way, they have their downsides.

For one, as a developer, you need to know the right dependency order to load your files in. For instance, let’s say you’re using Backbone in your project, so you include the script tag for Backbone’s source code in your file.

However, since Backbone has a hard dependency on Underscore.js, the script tag for the Backbone file can’t be placed before the Underscore.js file.

As a developer, managing dependencies and getting these things right can sometimes be a headache.

Another downside is that they can still lead to namespace collisions. For example, what if two of your modules have the same name? Or what if you have two versions of a module, and you need both?

So you’re probably wondering: can we design a way to ask for a module’s interface without going through the global scope?

Fortunately, the answer is yes.

There are two popular and well-implemented approaches: CommonJS and AMD.

## CommonJS

CommonJS is a volunteer working group that designs and implements JavaScript APIs for declaring modules.

A CommonJS module is essentially a reusable piece of JavaScript which exports specific objects, making them available for other modules to _require_ in their programs. If you’ve programmed in Node.js, you’ll be very familiar with this format.

With CommonJS, each JavaScript file stores modules in its own unique module context (just like wrapping it in a closure). In this scope, we use the _module.exports_ object to expose modules, and _require_ to import them.

When you’re defining a CommonJS module, it might look something like this:

```js
function myModule() {
  this.hello = function () {
    return "hello!";
  };

  this.goodbye = function () {
    return "goodbye!";
  };
}

module.exports = myModule;
```

We use the special object module and place a reference of our function into _module.exports_. This lets the CommonJS module system know what we want to expose so that other files can consume it.

Then when someone wants to use _myModule_, they can require it in their file, like so:

```js
var myModule = require("myModule");

var myModuleInstance = new myModule();
myModuleInstance.hello(); // 'hello!'
myModuleInstance.goodbye(); // 'goodbye!'
```

There are two obvious benefits to this approach over the module patterns we discussed before:

1\. Avoiding global namespace pollution  
2\. Making our dependencies explicit

Moreover, the syntax is very compact, which I personally love.

Another thing to note is that CommonJS takes a server-first approach and synchronously loads modules. This matters because if we have three other modules we need to _require_, it’ll load them one by one.

Now, that works great on the server but, unfortunately, makes it harder to use when writing JavaScript for the browser. Suffice it to say that reading a module from the web takes a _lot_ longer than reading from disk. For as long as the script to load a module is running, it blocks the browser from running anything else until it finishes loading. It behaves this way because the JavaScript thread stops until the code has been loaded. (I’ll cover how we can work around this issue in Part 2 when we discuss module bundling. For now, that’s all we need to know).

## AMD

CommonJS is all well and good, but what if we want to load modules asynchronously? The answer is called Asynchronous Module Definition, or AMD for short.

Loading modules using AMD looks something like this:

```js
define(["myModule", "myOtherModule"], function (myModule, myOtherModule) {
  console.log(myModule.hello());
});
```

What’s happening here is that the **_define_** function takes as its first argument an array of each of the module’s dependencies. These dependencies are loaded in the background (in a non-blocking manner), and once loaded **_define_** calls the callback function it was given.

Next, the callback function takes, as arguments, the dependencies that were loaded — in our case, **_myModule_** and **_myOtherModule —_** allowing the function to use these dependencies. Finally, the dependencies themselves must also be defined using the **_define_** keyword.

For example, **_myModule_** might look like this:

```js
define([], function () {
  return {
    hello: function () {
      console.log("hello");
    },
    goodbye: function () {
      console.log("goodbye");
    },
  };
});
```

So again, unlike CommonJS, AMD takes a browser-first approach alongside asynchronous behavior to get the job done. (Note, there are a lot of people who strongly believe that dynamically loading files piecemeal as you start to run code isn’t favorable, which we’ll explore more when in the next section on module-building).

Aside from asynchronicity, another benefit of AMD is that your modules can be objects, functions, constructors, strings, JSON and many other types, while CommonJS only supports objects as modules.

That being said, AMD isn’t compatible with io, filesystem, and other server-oriented features available via CommonJS, and the function wrapping syntax is a bit more verbose compared to a simple _require_ statement.

## UMD

For projects that require you to support both AMD and CommonJS features, there’s yet another format: Universal Module Definition (UMD).

UMD essentially creates a way to use either of the two, while also supporting the global variable definition. As a result, UMD modules are capable of working on both client and server.

Here’s a quick taste of how UMD goes about its business:

```js
(function (root, factory) {
  if (typeof define === "function" && define.amd) {
    // AMD
    define(["myModule", "myOtherModule"], factory);
  } else if (typeof exports === "object") {
    // CommonJS
    module.exports = factory(require("myModule"), require("myOtherModule"));
  } else {
    // Browser globals (Note: root is window)
    root.returnExports = factory(root.myModule, root.myOtherModule);
  }
})(this, function (myModule, myOtherModule) {
  // Methods
  function notHelloOrGoodbye() {} // A private method
  function hello() {} // A public method because it's returned (see below)
  function goodbye() {} // A public method because it's returned (see below)

  // Exposed public methods
  return {
    hello: hello,
    goodbye: goodbye,
  };
});
```

For more examples of UMD formats, check out this [enlightening repo](https://github.com/umdjs/umd) on GitHub.

# Native JS

Phew! Are you still around? I haven’t lost you in the woods here? Good! Because we have \*one more\* type of module to define before we’re done.

As you probably noticed, none of the modules above were native to JavaScript. Instead, we’ve created ways to _emulate_ a modules system by using either the module pattern, CommonJS or AMD.

Fortunately, the smart folks at TC39 (the standards body that defines the syntax and semantics of ECMAScript) have introduced built-in modules with ECMAScript 6 (ES6).

ES6 offers up a variety of possibilities for importing and exporting modules which others have done a great job explaining — here are a few of those resources:

- [jsmodules.io](http://jsmodules.io/cjs.html)
- [exploringjs.com](http://exploringjs.com/es6/ch_modules.html)

What’s great about ES6 modules relative to CommonJS or AMD is how it manages to offer the best of both worlds: compact and declarative syntax _and_ asynchronous loading, plus added benefits like better support for cyclic dependencies.

Probably my favorite feature of ES6 modules is that imports are _live_ read-only views of the exports. (Compare this to CommonJS, where imports are copies of exports and consequently not alive).

Here’s an example of how that works:

```js
// lib/counter.js

var counter = 1;

function increment() {
  counter++;
}

function decrement() {
  counter--;
}

module.exports = {
  counter: counter,
  increment: increment,
  decrement: decrement,
};

// src/main.js

var counter = require("../../lib/counter");

counter.increment();
console.log(counter.counter); // 1
```

In this example, we basically make two copies of the module: one when we export it, and one when we require it.

Moreover, the copy in main.js is now disconnected from the original module. That’s why even when we increment our counter it still returns 1 — because the counter variable that we imported is a disconnected copy of the counter variable from the module.

So, incrementing the counter will increment it in the module, but won’t increment your copied version. The only way to modify the copied version of the counter variable is to do so manually:

```js
counter.counter++;
console.log(counter.counter); // 2
```

On the other hand, ES6 creates a live read-only view of the modules we import:

```js
// lib/counter.js
export let counter = 1;

export function increment() {
  counter++;
}

export function decrement() {
  counter--;
}

// src/main.js
import * as counter from '../../counter';

console.log(counter.counter); // 1
counter.increment();
console.log(counter.counter); // 2
```

Cool stuff, huh? What I find really compelling about live read-only views is how they allow you to split your modules into smaller pieces without losing functionality.

Then you can turn around and merge them again, no problem. It just “works.”

# Looking forward: bundling modules

Wow! Where does the time go? That was a wild ride, but I sincerely hope it gave you a better understanding of modules in JavaScript.

In the next section I’ll walk through module bundling, covering core topics including:

- Why we bundle modules
- Different approaches to bundling
- ECMAScript’s module loader API
- …and more. :)
]]></description>
            <link>https://hungvn.com/blog/giai-thich-chi-tiet-ve-javascript-modules</link>
            <guid isPermaLink="true">https://hungvn.com/blog/giai-thich-chi-tiet-ve-javascript-modules</guid>
            <pubDate>Wed, 04 Sep 2019 19:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[CSS in JS trong dự án thực tế]]></title>
            <description><![CDATA[
Recently I have stumbled across a lot of blog posts describing changes in [styling](/actualize-network/modern-css-explained-for-dinosaurs-5226febe3525) [approaches](https://medium.freecodecamp.org/css-in-javascript-the-future-of-component-based-styling-70b161a79a32). Clearly, we’re entering a new era of styling in JS, that simply can be called _CSS in JS_. But what all of those posts miss, in my opinion, is a deep comparison of the features provided by those solutions and how they perform in real-world project. Code examples always look fresh and reusable and sexy, but what happens when we pick such solution and use it in a live application? Are there any drawbacks that turn beautiful ideas into coding hell? Let’s find out.

> Side note: Recently I’ve been a React developer and when I did the research I was focusing mainly on how I could utilize the technology in my projects, so therefore I will mostly focus on the ease of use in React. Ability to read JSX will help you to understand what the heck is going on.

# CSS Modules

Putting [CSS Modules](https://github.com/css-modules/css-modules) here can be a bit of a stretch, depending on how you define CSS in JS, because you write basically in CSS (with some cool additions). What’s change is the way of loading the styles into components. But they were the first, so treat it like a honorable mention on the list. Chances are that you probably seen CSS Modules somewhere. But let’s take a look at them (or, you know, you can always scroll to the next section). Let’s start with this simple example:

```js
// styles.css
.heading {
  color: gray;
  font-size: 1.5em;
}
.paragraph {
  font-size: 1.1em;
}
// component.js
import React from 'react';
import styles from './styles.css';
const Article = () => {
  return (
    <div>
      <h1 className={styles.heading}>
        Heading
      </h1>
      <p className={styles.paragraph}>
        Article's text
      </p>
    </div>
  );
};

```

Okay, so as you can see, the CSS are still the same. You simply write them like you did for years. What changes is the way of loading them into your application. Now, while bundling, the CSS files are being parsed and turn into pure JS objects, that are easy to use inside code. Styles are imported explicitly and used like any other JS object, which is very cool from the semantic perspective. But that’s not where CSS Modules shine.

## Local Scope

Having classnames parsed, CSS Modules is able to change the names of the output classnames into totally unique strings. This gives us local scope inside CSS. That’s huge! The generated output will look like this:

```html
// output
<div>
  <h1 class="6b87a4">Heading</h1>
  <p class="7h3g1a">Article's text</p>
</div>
```

The unique classnames are awesome! Are the solution to everything! And are totally un-debuggable. But there’s a small fix for it:

```js
// fix (in webpack.config.js)
(...)&localIdentName=[path]_[name]_[local]_[hash:base64:5]
// output
<div>
  <h1 class="src-components_component_heading_6b87a4">
    Heading
  </h1>
  <p class="src-components_component_paragraph_7h3g1a">
    Article's text
  </p>
</div>
```

Ah, much better! Now it’s clearly visible what styles come from what files. You can adjust the naming convention according to what’s suits you the most.

Pros:

- Pure CSS (no learning curve)
- Some additional features
- Local scoping
- Nice semantics using JavaScript’s import statement
- Easy debugging (with the right Webpack setting)

Cons:

- No more global styles, which is generally a good thing, but you need to invest some time to adjust to this approach
- Additional Webpack (or other bundler) configuration

## SASS Modules / LESS Modules

CSS Modules on their own bring some additional functionalities, like _composition_ or _global pseudo class_. But if you’re missing some of the cool stuff like _mixins_ or _variables_ you can always add [SASS](https://sass-lang.com/) or [LESS](http://lesscss.org/). Just add the respective loader to your webpack config. Now, you have a very powerful duo, fully pack with features and possibilities.

Pros:

- All of the CSS Modules features
- All of the SASS/LESS features (!)

Cons:

- Similar as CSS Modules

> For a long time I thought that using SASS with CSS Modules was the ultimate solution. Then, the other solutions came along.

# Styled Components

Although one can argue, that CSS Modules were the first CSS in JS, [Styled Components](https://github.com/styled-components/styled-components) were the one that started the whole avalanche of such solutions recently.

Styled Components utilize tagged template strings and allow to put your CSS code inside JavaScript directly. You can still split it into 2 files, to get that feeling of logic and styles being separate. But it’s optional. So, how our example would look like in Styled Components? Let’s see:

```js
// component.js
import React from "react";

import styled from "styled-components";

const Heading = styled.h1`
  color: gray;
  font-size: 1.5em;
`;

const Paragraph = styled.p`
  font-size: 1.1em;
`;

const Article = () => {
  return (
    <div>
      <Heading>Heading</Heading>
      <Paragraph>Article's text</Paragraph>
    </div>
  );
};
```

It’s pretty straightforward. Just use tags provided by the library to render a component that you would like having styling added to inside the template string literal. As simple as that.

## Extending styles

Let’s say, we would like to extend the styling of existing component and add some more. That’s very simple:

```js
const SexyParagraph = styled(Paragraph)`
  text-decoration: underline;
  color: green;
`;
```

Things get a little bit complicated, when you would like to add additional handlers to styled components. Let’s take a simple button and add a onClickhandler to it. Sadly, we can’t do it in one step. What we need to do, is basically create 2 components — one with logic, and one that brings styles:

```js
// button.js
import React from "react";

import styled from "styled-components";

const Button = ({ children }) => <button onClick={() => console.log("click")}>{children}</button>;

const StyledButton = styled(Button)`
  border: solid 2px green;
`;

// usage:
<StyledButton>My fancy button</StyledButton>;
```

So this makes things a bit excessive. Every time you would like to add some logic to a component, you will end up with 2 components. While it is kinda in style of [HoC](https://reactjs.org/docs/higher-order-components.html), but it just doesn’t go well with other HoC, so it can’t be used with cool HoC helpers like [recompose](https://github.com/acdlite/recompose). I must admit, that I’m a big fan of HoC and not being able to use Styled Components in that fashion just misses the mark for me.

Creating a separate component every time that a styling is needed seems like a good idea, but when I used such approach I suddenly missed the ability to just write a bit more complicated markup. So, in theory this approach is very appealing, but practice shows that sometimes you need to produce much more small components. This can lead to less readable code. Because if I can do something in 20 lines of JSX, I would prefer that over creating 10 small components.

## Dynamic Styles

One of cool features of Styled Components, that was just not possible in CSS Modules, is the ability to read components’ props and generate the appropriate styling. Let’s assume that we have 2 props: important and width. They can be accessed inside the style in such manner:

```js
const CustomButton = styled.button`
  color: ${props => props.important ? 'red' : 'black'};
  width: ${props => props.width}px;
}

<CustomButton important={false} width={320}>My button</Button>
```

Dynamic styles are a pretty cool feature. Although my concern is that it can lead to more logic-heavy styles. Depending on the project, that can be a double edged sword.

## Theming

Another great feature is theme support. That’s right, you can simply define your theme or color palette (as a simple object) and access its properties whenever you like. But what if I could tell you, that you can change themes on the fly? Yup, it’s possible. Let’s see it in action:

```js
// button.js
const ThemableButton = styled.button`
  color: ${props => props.theme.textColor};
  border: ${props => props.theme.borderColor};
`;

// themes.js
const theme = {
  textColor: "red",
  borderColor: "gray",
};

const otherTheme = {
  ...theme,
  textColor: "green",
};

// in app.js
<ThemeProvider theme={theme}>
  <div>
    <SomeComponent>
      <ThemableButton>Red button</ThemableButton>
    </SomeComponent>
  </div>
  <ThemeProvider theme={otherTheme}>
    <ThemableButton>I'm green!</ThemableButton>
  </ThemeProvider>
</ThemeProvider>;
```

The usage of ThemeProvider allows to add a theme (via property) to all components inside. If you’re in need of adding another theme, just place your components inside another ThemeProvider and enter a new theme property. As simple as that. The question arises, how many times you were in need of a theming that can be changed? I didn’t see much of such projects recently, but if you need it, it’s there.

## Debugging

Now, from debugging perspective, the generated output is fairly good. The StyledButton from the example above will not render a component inside a component, which is good. At the very beginning only the class names are unreadable (such as in case of CSS Modules). But there’s a Babel [plugin for that](https://github.com/styled-components/babel-plugin-styled-components), and you’re good to go.

Pros:

- Easy to use, easy to understand.
- Local scope
- Dynamic styling based on props
- Theming
- Easy debugging (with babel plugin)
- Works with React Native (although I didn’t test that)

Cons:

- Excessive creation of components (2 components each time handler or lifecycle method needs to be used)
- Possible too much of too small components
- Syntax highlighting needs an external plugin

# Glamorous

[Glamorous](https://glamorous.rocks/) takes inspiration from Styled Components and aims to change a bit the way you can use it. Notably, the biggest difference is the departure from tagged template strings in favor of plain objects. You still would use it in a similar way, but replacing string with objects. Just take a look:

```js
import glamorous from 'glamorous';

const Heading = glamorous.h1({
  fontSize: '2.4em',
  marginTop: 10,
  color: '#CC3A4B'
})

// rendering
render() {
  return (<Heading>My Heading</Heading>);
}
```

To use media queries, pseudo classes and pseudo elements, simply create nested objects with selectors as their names, like so:

```js
import glamorous from 'glamorous';

const Heading = glamorous.h1({
  fontSize: '2.4em',
  marginTop: 10,
  color: '#CC3A4B',
  ':hover': {
    color: 'yellow'
  },
  '@media only screen and (max-width: 500px)': {
    marginTop: 5,
    fontSize: '1.8em'
  }
});

// rendering
render() {
  return (<Heading>My Heading</Heading>);
}
```

## Animations

Well, this is something that does not come with Styled Components. Glamorous has a build in helper for creating CSS animations. That’s something really cool. Nowadays fluid animations and transitions are important parts of good UX and everything that improves creation of those effects is more then welcome.

```js
const AnimatedDiv = glamorous.div(props => {
  const bounce = glamor.css.keyframes({
    "0%": { transform: `scale(1.01)` },
    "100%": { transform: `scale(0.99)` },
  });

  return {
    animation: `${bounce} 0.2s infinite alternate`,
  };
});
```

Okay, so it’s not a game changing functionality. But it allows to create unique keyframes animations in a simple manner.

## Dynamic Styling

Just like in Styled Components, Glamorous has the ability to use dynamic styling. In my opinion, it does it in much clearer way. Because we work with objects, not with string literals, conditional operations are much more natural. Simply, instead of object, pass a function that receives props and returns a valid object.

```js
const CustomButton = glamorous.button((props) => ({
  color: props.important ? 'red' : 'black',
  width: props.width
});

<CustomButton important={false} width={320}>My button</Button>
```

Obviously, having the ability to pass a function into the component factory gives you much more flexibility, but allows to create even more logic-heavy styles. Double edged sword once again.

## Theming and reusing styles

Theming for Glamorous looks like it was taken directly from Styled Components, just define a theme object and pass it to your components. They will have access to it via props.theme. Simple as that.

Glamorous allows also to reuse and extend existing styles. For that you can use the glamorous object as a function, pass the component and then styles to override the existing ones.

```js
const GreatButton = glamorous(CustomButton)({
  padding: 20,
});
```

Moreover, it allows you to copy existing styles to a different tag via withComponent method:

```js
const GreatLink = GreatButton.withComponent("a");
```

## Not HoC compliant

When it comes to overall usage, Glamorous suffers from the same drawback of not really being in compliant with HoC approach. So, once again, to build a more advanced component with styling, you will need to create 2 components. Let’s revisit the example from Styled Components:

```js
// button.js
import React from "react";

import glamorous from "glamorous";

const Button = ({ children }) => <button onClick={() => console.log("click")}>{children}</button>;

const StyledButton = glamorous(Button)({
  border: "solid 2px green",
});

// usage:
<StyledButton>My fancy button</StyledButton>;
```

So this comes with the same issue: too many small components.

## Debugging

When it comes to debugging, Glamorous on it’s own is not very readable in the DevTools. But, obviously, there’s a [plugin](https://github.com/bernard-lin/babel-plugin-glamorous-displayname) for that.

Pros:

- ...styledComponents.pros
- Object notation instead template literals
- Keyframes helper

Cons:

- (Potentially) excessive components creation

# Styletron

When it comes to [Styletron](https://github.com/rtsao/styletron), I’m probably quite biased. I have become involved in a project using it and it quickly pushed me to do research on other similar solutions to migrate away to. I felt so limited and distracted by it so I couldn’t just bare with styling anymore. I get the impression, that Styletron does a lot of things similar to Glamorous, but fails to deliver really usable in real-life solution. Let’s start with basics:

```js
import { styled } from 'styletron-react';

const Heading = styled('h1', {
  fontSize: '2.4em',
  marginTop: 10,
  color: '#CC3A4B'
});

// rendering
render() {
  return (<Heading>My Heading</Heading>);
}
```

When it comes to simple usage, it’s almost the same as in Glamorous.

## Themes, dynamic styles and extending styles

Styletron provides ways to extend existing styles, or to build dynamic styles. It also supports theming in a very similar fashion, as we have seen previously. Let’s see all of those features in action together:

```js
import { styled } from 'styletron-react';
import ThemeProvider from './ThemeProvider';
import Button from './GenericButton';

const FancyButton = styled(GenericButton, ({ theme, size }) => {
  return {
    color: theme.button.color,
    background: theme.button.background,
    height: (size === 'big') ? '30px', '20px',
    width: (size === 'big') ? '100px', '60px'
  };
});

const MyTheme = {
  button: {
    color: '#ee3ae4',
    background: '#323c4d'
  }
}

// rendering
<ThemeProvider theme={MyTheme}>
  <FancyButton size="big">Click me</FancyButton>
</ThemeProvider>
```

Similar to previous solutions, Styletron does not allow to create more lifecycle-heavy components with styles. Instead, you need to create 2 components, one with logic, and one with styles:

```js
class MyComponent extends React.Component {
  componendDidMount() {
    // some awesome logic here
  }
  render() {
    return <div>My Component</div>;
  }
}

const StyledComponent = styled(MyComponent, {
  /* styles */
});
```

So, let’s see, what Styletron renders in HTML…

## Generated output

The output for the example above will be something like:

```html
<div class="_c _d _g x1 x3 xm _a">
  <div>My Component</div>
</div>
```

And two issues can be seen here. Firstly, that the rendered code is totally not debuggable. You can’t really deduce from which component any of the styles really come. Or even what component you’re looking at. Switching to React DevTools doesn’t help either. All you gonna see is that it’s `<styled(div)>`. That’s really helpful.

Oh, and each style property gets it’s own, unique class name. Imagine having a well styled component with over 30 properties. Yeah…

```html
<div
  class="_a _b _c _d _e _f _m1 _m2 _m3 _m4 _m17 _m20 _m22 _m33 _m45 _m46 _la _lg _lz _lh _l5 _hm _hn _hi x1 x12 x13 x15 x16 x21 x22 x23 x24 x25 x26 x30 x32 x33 x34"
>
  Hi
</div>
```

And what’s even worse, there is **no debugging plugin** for it!

Moreover, imagine that the example would have 10 nested components, one inside another. Could you tell the number of generated divs? Yup, 20. Because every time you need to have more advanced component, Styletron will need to add additional wrapper for styling purposes. That’s something I like to call a _Wrapper-iada_. And it’s no good.

## Other issues

Styletron has a bug that’s basically prevents you from using dynamic tags (so the tags used depending on the props). Let me explain:

```js
const headers = {
  h1: 'h1',
  h2: 'h2',
  h3: 'h3
}

const DynamicHeader = ({ size, children }) => {
  const Element = headers[size];
  return (
    <Element>{children}</Element>
  );
};
```

Now, if I would like to add styling to my DynamicHeader, I would go with:

```js
const StyledHeader = styled(DynamicHeader, { /\* new styles \*/ });
```

None of the new styles won’t be applied. Why? I don’t have an idea, but it’s not good.

## No animations

That’s right, Styletron does not support css keyframes! Obviously, you can use animation like the following:

```js
const BouncyDiv = styled("div", {
  animation: "bounce 1s",
});
```

And it will work. But you can’t define the keyframes of bounce using Styletron. If you would really like to somehow define keyframes, you need to use good, ol’ CSS. That’s a terrible solution.

Let’s sum up:

Pros:

- Looks similar to Glamorous
- Local scope
- Theming, dynamic styles, extending styles

Cons:

- Undebuggable (!)
- Wrapper-iada
- No dynamic elements
- No keyframes support

# Styled JSX

Next CSS-in-JS solution that I researched was [Styled JSX](https://github.com/zeit/styled-jsx). At the very beginning it looks different to the solutions above, it kinda looks more inline with JSX approach and I find it a bit more appealing. The basic example looks like this:

```js
const MyComponent = () => {
  return (
    <div>
      <h1>Heading</h1>
      <p>Paragraph 1</p>
      <p className="p2">Paragraph 2</p>
      <style jsx>{`
        h1 {
          font-size: 1.6em;
        }
        p {
          line-height: 1.5em;
        }
        .p2 {
          color: gray;
        }
      `}</style>
    </div>
  );
};
```

Styled JSX uses template literals inside of a `<style jsx>` tag. What’s really neat, is that you can use the plain old CSS inside. It’s readable, it’s safe due to local scope. If you like, you can move the string to a separate file because everything is in a string. If you’re running React in versions 16.2 or higher, you can replace the div with React’s fragment.

## Same features and more freedom

Obviously, defining the styles inside component’s render method allows us to access all of the props and hence build dynamic styles. Or you can access the theme provided by ThemeProvider although you need to use additional module for that, as Styled JSX don’t have a built in ThemeProvider.

```js
const MyComponent = ({ theme, size }) => {
  return (
    <div>
      <h1>Heading</h1>
      <style jsx>{`
        h1 {
          font-size: ${size}px;
          color: ${theme.heading.color};
        }
      `}</style>
    </div>
  );
};
```

What I like here, is that I can write styles and apply them to components with lifecycle methods. Another thing to like is that Styled JSX integrates nicely with React’s idea of rendering components. That was not possible with any of the previous libraries. But here I can decide when I should split component into smaller ones. That kind of freedom is something I really appreciate. Artificial code splitting forced by previous solutions does not always end up in a very readable code.

## Drawbacks

I must say I really like this approach, but the drawbacks just kill it for me. The problems start when you want to extend existing styling. Or when you would like to alter the default styling of a child component. There is no easy way of doing such things. While in Glamorous all you needed was to call glamorous(DefaultButton)(newStyles), in Styled JSX you need to come up with your own approach to reusing existing styling. So as I said before, this kills the Styled JSX for me.

Pros:

- More inline with JSX approach
- Doesn’t force artificial code splitting
- Easy to understand
- Local scope
- Dynamic Styles, Themes support

Cons:

- Reusability of styles is hard if non-existent

# JSS

The last but not least — [JSS](http://cssinjs.org/). At first glance, JSS looks very similar to Glamorous. You create objects literals with styles, you apply them to components. But it also successfully adds the ability to write couple styles for multiple tags inside one component.

```js
import withStyles from 'react-jss';

const styles = {
  heading: {
    fontSize: '1.6em'
  },
  paragraph: {
    lineHeight: '1.4em'
  }
};

const MyComponent ({ classes }) => {
  return (
    <div>
      <h1 className={classes.heading}>
        Heading
      </h1>
      <p className={classes.paragraph}>
         Paragraph 1
      </p>
    </div>
  );
};

export default withStyles(styles)(MyComponent);
```

First what I have to admit, and what really got me excited about JSS is that finally, it’s a HoC! You pass a object with different class names to it, and the HoC will produce a wrapper that adds a classes property containing generated, unique class names. In a way, it brings the functionality of both Styled JSX and Glamorous neatly together. That’s off to a good start.

## Theming and dynamic styles

Just like abovementioned solutions, JSS supports both themes and dynamic styles. It comes with build in ThemeProvider which is always a neat solution.

```js
// component.js
import withStyles from "react-jss";
// app.js
import { ThemeProvider } from "react-jss";

const styles = theme => ({
  wrapper: {
    fontSize: "1.4em",
    color: theme.primaryColor,
    height: props => props.size,
  },
});

const Component = ({ classes }) => {
  return <div className={classes.wrapper}>My fancy component</div>;
};

export default withStyles(styles)(Component);

const theme = {
  primaryColor: "#51abff",
};

// rendering
<ThemeProvider theme={theme}>
  <Component size="32px" />
</ThemeProvider>;
```

The theme object is available when instead of styles object, you create a function that returns the styles object. Component’s props are available in a slightly more annoying way, as a argument for function returning value of each property.

## Reusing and overriding styles

When it comes to extending styles, well, JSS does not provide any simple way of doing so. But, then again, they are all JS object, so we can export styles and extend them on our own using the spread operator.

```js
// component.js
export const styles = {
  wrapper: {
    // original styles
  },
};

const Component = () => {
  // Component's logic
};

export default withStyles(styles)(Component);

// fancy-component.js
import { styles as defaultStyles } from './component';
export const styles = {
  wrapper: {
    ...defaultStyles.wrapper,
    color: 'red',
  },
};
```

A bit of work, but it’s very explicit. No under-the-hood magic. There is a [extend-plugin](http://cssinjs.org/jss-extend), however its usage is very similar to the spread operator.

JSS has a neat feature that is not available in other libraries, and that’s ability to override default styles of the component. You can call the withStyles HoC again and again on component, overriding it’s default styles, like so:

```js
// componentA.js
const styles = {
  wrapper: {
    color: 'red',
    fontSize: '1.4em'
  }
  paragraph: {
    fontSize: '1.2em',
    color: 'gray'
  }
};

const ComponentA = () => {
  // ...
};

export default withStyles(styles)(ComponentA);

// componentB.js
const stylesA = {
  wrapper: {
    color: 'blue'
  }
};

const StyledA = withStyles(stylesA)(ComponentA);

const ComponentB = () => {
  return (
    <div>
      <StyledA />
    </div>
  );
};
```

Because withStyles performs a shallow merge of the style objects, the StyledA component will contain the original styles for paragraph, but it will have only the newest styles for wrapper. This means that it will have only the color: blue property but it will lose the fontSize: 1.4em property.

You can obviously combine the two methods to override styles with extending the existing ones. However, since it is a HoC, you can write your own HoC that does just that.

## Other features

JSS comes with variety of [plugins](http://cssinjs.org/plugins). You can use them, for example, to write styles inside template literals, if that’s your thing, or to extend existing classes via class names or objects.

## Debugging

When it comes to debugging, JSS is very user-friendly. At the very beginning, it renders human-friendly class names, so you can quickly find your way around the generated HTML markup. It also does not change the generated components’ names, as it only works on the className property, which is quite nice.

Pros:

- Local Scope
- Theming, dynamic styles
- No artificial code splitting
- Overriding default styles (!)
- works as a HoC

Cons

- No native style extending solution (but you can work around this)

# Conclusion

It’s time to sum up. Is there a clear winner? In my opinion, yes. JSS takes the top spot. It gives me all of the features of other CSS-in-JS solutions and doesn’t forces me to create super-small components each time I need styling for a div. In addition to that, it works as a HoC, so if I don’t like the default behavior (like when overriding styles) I can always create my own HoC that wraps it and changes the behavior. It’s simple to use and flexible. And at the end of the day, it’s the solution that devs from the [Material UI](http://www.material-ui.com/#/) are [gonna use](https://material-ui-next.com/customization/css-in-js). For me, that’s a hell of a recommendation for JSS.

> As I already mentioned, I thought that SASS + CSS Modules were the future. But now I can clearly see, that CSS in JS is at least as good, with JSS being my favorite. It’s really usable and works great in the real-life development. My personal pick after doing the research: JSS.
]]></description>
            <link>https://hungvn.com/blog/css-in-js-trong-du-an-thuc-te</link>
            <guid isPermaLink="true">https://hungvn.com/blog/css-in-js-trong-du-an-thuc-te</guid>
            <pubDate>Sun, 01 Sep 2019 12:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[JavaScript naming conventions: nên và không nên]]></title>
            <description><![CDATA[
I find it amazing how many different meanings we can get from less than 30 characters. I’m talking about the alphabet with some well-placed punctuation, of course. From a love story to a computer program, writing has allowed us to create extraordinarily different worlds. And language, in general, provides a framework in which we can hang a stream of ideas.

Most programming languages seem to have very strict standards — certain terms have to be used in certain places. But one area where there is an enormous amount of freedom is how we name those terms.

Take this simple program which creates a sentence from an array of words, adds a punctuation mark, and logs it to the console:

![](1_Gt4VIOQZwk_tVVIrKpqMZg.png)

Nothing too special, right? But what you may not have considered is how many _terms_ you were responsible to name.

There are 23 words (not including hard-coded values) in the above program. We controlled the names of 14 of those words. That is more than 60% of what was typed, was our responsibility to name!

![](1_GJ3JQHA53Xhic0RCLfepSg.png)

Whether you are building an enterprise application or a simple _Hello, World,_ you want your program to read like a Times Bestseller, not a Mad Libs workbook.

This is _not_ a manifesto on how to structure an entire JavaScript application, but rather a chapter on how to choose names for those things in which you have the freedom to do so. I’ve included the various references at the bottom if you want to learn more. One last thing, the key takeaway of all of our conventions and standards is this:

> _Most of these conventions are not for you today, but instead, for you and the people reading your code tomorrow._

![](1_Xwatja8ddZXjumrmLFTjKw.png)

## References and continued learning

1.  [“Clean Code” by Robert C. Martin](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=brandonwoz-20&linkId=8af093cb2b8d9a87993f285341ff015a) — _A great read for all languages. It goes beyond naming conventions and proposes the entire structure of your program. The examples are in Java, but the principles apply to JavaScript._
2.  [“Clean Code JavaScript” by Ryan Mcdermott](https://github.com/ryanmcdermott/clean-code-javascript) — _The above book, but remade for JavaScript. It is available online and is free._
3.  [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) — _Possibly the most comprehensive style guide for JavaScript. It contains not only the what, but also the why. (If you’re on a small device, you may need to click on “view all readme” to see the entire document)._
4.  [W3Schools JavaScript Style Guide](https://www.w3schools.com/js/js_conventions.asp) — A s*hort and concise guide.*
5.  [Google’s ES6 Style Guide](https://google.github.io/styleguide/jsguide.html) — _Google’s style guide for JavaScript._

Thanks for reading!
]]></description>
            <link>https://hungvn.com/blog/javascript-naming-conventions-nen-va-khong-nen</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-naming-conventions-nen-va-khong-nen</guid>
            <pubDate>Fri, 30 Aug 2019 18:15:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Original DOM vs Shadow DOM vs Virtual DOM]]></title>
            <description><![CDATA[
## Mở đầu

Với các bạn tìm hiểu về Web Development, chắc hẳn không xa lạ gì với khái niệm DOM ? Hay cụ thể hơn như là Original DOM nhỉ

Ngoài các trang web nhỏ và vừa ra thì có bao giờ bạn tự hỏi, các trang web lớn như _Facebook, Twitter, GMail, etc_ thì có cả một _"rừng cây Amazon"_ trong source code HTML của mình thì họ quản lý DOM Tree như thế nào không?

Và đương nhiên chỉ với DOM thôi thì các nhà phát triển web khó lòng xử lý hàng núi việc như thế. Từ đó ra đời khái niệm Virtual DOM và Shadow DOM.

Đúng như tiêu đề thì ở bài viết này các bạn hãy cùng mình tìm hiểu sâu hơn về Original DOM, Shadow DOM và Virtual DOM để có được cái nhìn đầy đủ hơn về chúng nhé.

_Cùng bắt đầu thôi nào ^^_

## Original DOM

### Overview

Có thể bạn thừa biết 🤣🤣)) **DOM** là viết tắt của **Document Object Modal**.

DOM bao gồm:

- **Object-based representation of the HTML document**

_Các phần tử trong DOM có cấu trúc được định nghĩa thành các đối tượng, có các phương thức, thuộc tính để có thể truy xuất dễ dàng._

_Chúng được coi như các node và được biểu diễn dưới dạng DOM Tree_.

```js
<html>
  {' '}
  -> document node
  <head>
    {' '}
    -> element node - head
    <title>HTML DOM -> text node</title> -> element node - title
  </head>
  <body> -> element node - body</body>
</html>
```

- **DOM APIs**

_HTML DOM cung cấp các APIs để duyệt và chỉnh sửa các node._

_Ví dụ cụ thể về APIs có thể kể tới như getElementById() dùng để truy xuất một phần tử theo id cũng hay removeChild() dùng để loại bỏ một phần tử con dựa vào phần tử cha của nó._

## Shadow DOM

### Overview

Mozilla đã tóm tắt 3 đặc điểm cơ bản về **Shadow DOM**:

> Shadow DOM can be thought of as:
>
> - Isolated DOM
> - A “lite” version of the DOM
> - NOT of a full standalone document

Sở dĩ nói như vậy là do các stylesheet hay javascript từ bên ngoài **không-thể-tác-động** vào trong Shadow DOM được và ngược lại.

Ví dụ như ta có thẻ `<video>` như một _custom element_.

### Cấu trúc của một shadow DOM

Với Shadow DOM chúng ta sẽ có thêm Shadow Root. Nội dung Shadow Root sẽ không được trình duyệt render mà thay vào đó là Shadow Host. Shadow Host được xem như một element bình thường nhưng nội dung bên trong nó (cả stylesheet) sẽ được đóng gói và độc lập với thế giới bên ngoài:

![](https://haodev.files.wordpress.com/2019/06/dd.png)

### Tạo một shadow DOM

```js
<style> p { color: green } </style>

<p id="sd-root">I am Shadow Root</p>

<script>
  const host = document.querySelector('#sd-root');
  const root = host.createShadowRoot();
  root.innerHTML = `

    <style> p { color: gray }</style>

    <p>Hello <strong>Shadow DOM</strong></p>
  `;
</script>
```

_Bạn đoán xem, kết quả sẽ là gì nào_ 🤔🤔 . . .

![](https://images.viblo.asia/8f53d168-06c9-44d5-9324-eeef3fd67aa6.gif)

Ở đây khi trình duyệt render xong chúng ta sẽ nhận được:

![](https://images.viblo.asia/f64a3a5a-df1a-4410-b021-bc4ea06aa311.PNG)
thay vì là

![](https://images.viblo.asia/b058ffa5-0423-4ef4-aa8f-3c6197349f0e.PNG)

Khi Inspect phần tử lên ta sẽ thấy như thế này đây:

![](https://haodev.files.wordpress.com/2019/06/code-inspect.png?w=374&h=131)

Như vậy, chúng ta sẽ có vài nhận xét như sau:

- Style bên trong Shadow DOM dù conflict selector với bên ngoài nhưng không sao vì đặc tính của Shadow DOM (scoped style sheet)
- Khi chúng ta truy xuất .innerHTML() của element #sd-root thì ta CHỈ lấy được đoạn text khởi tạo: “_I am Shadow Root_” và cũng không-thể-tác-động được gì vào bên trong Shadow Root, cụ thể chính là Shadow Host.

> Okay, chúng ta đã rõ hơn về **DOM**:
>
> - Phần sáng của nó (hay thường được gọi là **Light DOM**) là cái chúng ta có thể tương tác được.
> - Phần tối của nó, cái bóng (**Shadow DOM**) chỉ phản ánh lên nó sẽ được render thế nào khi Light DOM thay đổi.  
>   Và theo lẽ đương nhiên, ta không-bao-giờ có thể chạm được vào cái bóng của một vật nào cả 😄😄

_Oohh, DOM ngon vậy thì sao lại có Virtual DOM làm gì nhỉ ?_ 🙄🙄

_Mình cùng tìm hiểu tiếp nhé_ 😛😛

## Virtual DOM

Mặc dù concept này đã xuất hiện từ khá lâu rồi nhưng nó chỉ mới trở nên phổ biến khi được sử dụng trong các thư viện nổi tiếng như ReactJS, VueJS...

### Overview

_Đúng như tên gọi của nó, DOM-ảo. Ảo, có nghĩa là không thật_

> Virtual-DOM là một Object chứa các thông tin cần thiết để tạo ra một DOM (Document Object Model).

Virtual DOM có khả năng tính toán, cập nhật các node mà không cần sử dụng DOM APIs. Sau khi cập nhật trên DOM ảo, các thay đổi sẽ được thực hiện với Original DOM.

Như một vài đặc điểm mình đã nêu ở trên, Virtual DOM được xem như một cách hiệu quả để giải quyết vấn đề cập nhật trên DOM, không cần render lại toàn bộ cả DOM Tree.

Dưới đây là đặc tả một DOM Tree:

![](https://haodev.files.wordpress.com/2019/06/html.png)

thành một Virtual DOM:

![](https://haodev.files.wordpress.com/2019/06/virtual.png)

_Trong thực tế, thay vì phải sử dụng toàn-bộ-object, chúng ta thường làm việc với các object-nhỏ-hơn tương ứng với các thành phần của Virtual DOM._

### Cơ chế hoạt động

Ban đầu, một đối tượng có nhiệm vụ như một snapshot từ virtual DOM sẽ được tạo ra:

![](https://haodev.files.wordpress.com/2019/06/virt-cop.png)

Bản copy này được sử dụng để tạo diff để so sánh với bản virtual DOM ban đầu, về cơ bản thì nó sẽ có dạng như thế này:

![](https://haodev.files.wordpress.com/2019/06/diff.png)

Từ đó, giúp Engine biết rằng phải update element nào trong original DOM, chúng chỉ thực hiện update khi có sự thay đổi.

Để thực hiện việc này chỉ cần sử dụng một vòng loop với diff cho dù là thêm một node mới hay update node cũ:

![](https://haodev.files.wordpress.com/2019/06/exam.png)

Sau đó, tiến hành cập nhật list, viết lại toàn bộ template, chạy lại hàm render(), hiển thị thay đổi ra ngoài view.

> Mặc dù nói là toàn bộ template, song, chỉ những phần thực sự thay đổi mới được cập nhật. Các thay đổi được thực hiện cho đối tượng này sau đó được đối chiếu và sửa đổi đối với original DOM .

### Why use Virtual DOM?

#### Speed

Trước đây mình nghĩ rằng lý do nói sử dụng Virtual DOM nhanh hơn Original DOM là do _việc set attribute cho object nó nhanh hơn việc update DOM_, nhưng **không phải** các bạn ạ 😂😂

_Thực tế là việc cập nhật DOM chẳng tốn nhiều thời gian là bao so với việc cập nhật attribute cho object._

Điều thật sự ảnh hưởng tới speed performance ở đây là khi DOM thay đổi, Browser buộc phải ngồi tính lại CSS, build layout, paint template...

Vì cấu trúc của DOM là tree structure , khi muốn thay đổi các element và các thẻ con của nó, ta phải thông qua các Reflow/Layout. Từ đó, các thay đổi được sẽ được re-painted. Càng nhiều các item phải reflow/repaint, web của bạn sẽ càng load chậm 😦

_Hmmm..._

_Để hiểu sâu hơn vấn đề này, chúng ta hãy tìm hiểu thêm một khái niệm nữa đó là về cơ chế binding._

#### Data-binding

Khái niệm data-binding có thể hiểu đơn giản là:

> Data-binding: Data in Model changes `<=>` View changes.

###### **Data-binding trong DOM thật**

Bây giờ ta lướt qua một chút các framework có cơ chế data-binding như BackboneJS, AngularJS, khi dữ liệu của Model Object thay đổi, nó sẽ:

1.  Xác nhận các event + các View Object liên quan
2.  Tác động vào các phần tử DOM trên View và phản ánh sự thay đổi dữ liệu đó.

###### **Data-binding trong DOM ảo**

> Các framework sử dụng Virtual-DOM, Virtual-DOM vừa đóng vai trò là Model, vừa đóng vai trò là View

_Như vậy, khi Virtual-DOM thay đổi, mọi sự thay đổi trên Model đã kéo theo sự thay đổi trên View và ngược lại._

Dù không tác-động-trực-tiếp vào các phần tử DOM ở View nhưng vẫn thực hiện được cơ chế data-binding. Điều này làm cho tốc độ ứng dụng tăng lên đáng kể.

### **BONUS: Virtual DOM trong ReactJS**

_Dù phần này có hơi mở rộng so với tiêu đề bài viết một chút , nhưng hôm rồi mình tình cờ đọc được một bài viết về cách ReactJS thao tác với DOM ảo khá thú vị nên bonus vào để chúng mình hiểu sâu hơn về Virtual DOM nhé ^^_

Với một thư viện sử dụng DOM ảo như ReactJS, sau khi **DOM thật được load lần đầu tiên**, DOM ảo cũng được React tạo ra tương ứng với DOM thật bên trên. Trong React, nó cũng được gọi là một Component với tree structure gồm các Component con bên trong.

_**Lưu ý:**_

_Khi có một state mới được set, React đánh dấu nó như là một dirty Component (nghĩa là mỗi khi chúng ta gọi tới setState() thì Component đó sẽ được đánh dấu là dirty)_

Các event khi ta thao tác với DOM được React event listener lắng nghe. Do đó, khi có event nào, event đó sẽ được gửi tới React event listener và sau đó sẽ chạy một anonymous function()

Trong anonymous function(), chúng ta gọi tới this.setState() với một new state value. _Sau khi this.setState() được chạy, Component đó được đánh dấu là dirty_.

Okay, điều gì xảy ra tiếp theo:

###### **Chạy qua Component lifecycle**

Quan trọng nhất trong quá trình update ở đây chính là render(), sau khi xây dựng lại Component, DOM ảo được tạo lại và update DOM ảo để tìm ra sự khác biệt\*(như phần Cơ chế hoạt động mình trình bày phía trên)\*, từ đó tìm ra cụ thể element thay đổi, và sau đó cập nhật chỉ những element đó ở DOM thật.

###### **Snapshots & Diffing**

React lấy một snapshot của Virtual DOM (bản ghi trạng thái ngay lúc đó) ngay trước khi áp dụng bất kỳ bản cập nhật nào. Sau đó, nó sử dụng snapshot này để so sánh với một Virtual DOM được cập nhật trước khi thực hiện các thay đổi.

Khi cập nhật được cấp cho Virtual DOM (**Virtual DOM sử dụng key, ref mà ở DOM không có và Virtual DOM được tạo mới sau mỗi lần render lại**), quá trình tiếp theo React sử dụng thuật toán Diffing để so sánh và đối chiếu để biết được sự cập nhật được diễn ra ở đâu sau đó cập nhật nó mà bỏ qua những elements không liên quan.

Do đó, work-flow của React thao tác với DOM ảo khi có change detection:

> 1.  Xây dựng lại component
> 2.  Update DOM ảo
> 3.  Tìm sự thay đổi
> 4.  Update DOM thật

Nhờ có DOM ảo, React có thể tìm ra các node bị thay đổi và update ở DOM thật chỉ ở những cái node đó, thật thuận tiện và nhanh gọn phải không nào ^^

## Kết

Như vậy là chúng ta đã điểm qua Original DOM, Shadow DOM hay Virtual DOM rồi. Hy vọng rằng bài viết này có thể giúp các bạn hiểu hơn về DOM và các vấn đề liên quan.

Nếu bài viết này có thể giúp ích cho bạn, tặng mình 1 upvote để có thêm động lực cho những bài viết sắp tới nha 😛😛

Chúc bạn tuần mới làm việc hiệu quả !

Thanks for reading ❤
]]></description>
            <link>https://hungvn.com/blog/original-dom-vs-shadow-dom-vs-virtual-dom</link>
            <guid isPermaLink="true">https://hungvn.com/blog/original-dom-vs-shadow-dom-vs-virtual-dom</guid>
            <pubDate>Tue, 20 Aug 2019 10:40:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về HTTP Status Code]]></title>
            <description><![CDATA[
Nếu bạn là một web developer hoặc thường xuyên làm việc với các API chắc chắn bạn đã quá quen thuộc với các con số 200, 404, 500... chúng là các Status Code của HTTP. Vậy có khi nào bạn tự hỏi ngoài các con số trên còn các số nào không, ý nghĩa của chúng là gì? Trong blog này tôi sẽ giải quyết điều này giúp bạn. Nào chúng ta bắt đầu thôi.

Trước tiên chúng ta sẽ tìm hiểu một chút về HTTP Response. Khi nhận và phiên dịch một HTTP Request, Server sẽ gửi tín hiệu phản hồi là một HTTP Response bao gồm các thành phần sau :

- Một dòng trạng thái (Status-Line)
- Không hoặc nhiều hơn các trường Header (General|Response|Entity) được theo sau CRLF
- Một dòng trống chỉ dòng kết thúc của các trường Header
- Một phần thân thông báo tùy ý

Dưới đây là một ví dụ về một HTTP Response

![http](2034885a-9b0e-477b-9568-86182f3637dd.png)

Bây giờ chúng ta sẽ tập trung chính vào dòng Status-Line: Một dòng Status Line bao gồm phiên bản giao thức (HTTP-Version) sau đó là mã hóa trạng thái số (Status-Code) và cụm từ thuần văn bản được liên kết của nó. Các thành phần được phân biệt bởi dấu cách

```
Status-Line = HTTP-Version <Space> Status-Code <Space> Reason-Phrase CRLF

Ví dụ :
HTTP/1.1 404 Not Found

HTTP-Version : HTTP/1.1
Status-Code : 404
Reason-Phrase : Not Found
```

Status code (Mã hóa trạng thái thường được gọi là mã trạng thái) là một số nguyên 3 ký tự, trong đó ký tự đầu tiên của Status-Code định nghĩa loại Response và hai ký tự cuối không có bất cứ vai trò phân loại nào. Có 5 giá trị của ký tự đầu tiên:

- 1xx: Information (Thông tin): Khi nhận được những mã như vậy tức là request đã được server tiếp nhận và quá trình xử lý request đang được tiếp tục.
- 2xx: Success (Thành công): Khi nhận được những mã như vậy tức là request đã được server tiếp nhận, hiểu và xử lý thành công
- 3xx: Redirection (Chuyển hướng): Mã trạng thái này cho biết client cần có thêm action để hoàn thành request
- 4xx: Client Error (Lỗi Client): Nó nghĩa là request chứa cú pháp không chính xác hoặc không được thực hiện.
- 5xx: Server Error (Lỗi Server): Nó nghĩa là Server thất bại với việc thực hiện một request nhìn như có vẻ khả thi.

Status-Code HTTP là có thể co giãn và ứng dụng HTTP không được yêu cầu để hiểu ý nghĩa của tất cả các mã trạng thái được đăng ký. Một danh sách của tất cả các mã trạng thái đã được cung cấp trong một chương riêng biệt cho bạn tham khảo.

### I. 1xx Infomation (Thông tin)

- 100 Continue: Chỉ một phần của Request được nhận bởi Server (có thể là header và Client cần gửi tiếp body), nhưng miễn là nó không bị loại bỏ, Client nên tiếp tục với Request.
- 101 Switching Protocols: Requester đã hỏi Server về việc thanh đổi Protocol và Server đã chấp nhận điều đó

### II. 2xx Success (Thành công)

- 200 OK: Request đã được tiếp nhận và xử lý thành công. Các Response thực tế trả về sẽ phụ thuộc vào phương thức HTTP của Request. Trong một GET Request, Response sẽ chứa một thực thể tương ứng với các tài nguyên yêu cầu, trong một POST Request, Response sẽ chứa một thực thể mô tả hoặc chứa các kết quả của các action.
- 201 Created: Request được chấp nhận cho xử lý, nhưng việc xử lý chưa hoàn thành.
- 203 Non-authoritative Information (Xuất hiện từ HTTP/1.1): Server là nơi chuyển đổi proxy (ví dụ một Web accelerator) đã nhận được 200 OK nhưng nó trả về một phiên bản thay đổi (có thể là header) của Response nguyên gốc.
- 204 No Content: Server đã xử lý thành công request nhưng không trả về bất cứ content nào.
- 205 Reset Content: Server đã xử lý thành công request nhưng không trả về bất cứ content nào. Không giống với 204 No Content Response này yêu cầu phía Client phải thiết lập lại document view.
- 206 Partial Content: Server chỉ trả về một phần của resouce(dạng byte) do một range header được gửi bởi phía Client. Các Range Header được sửa dụng bởi Client để cho phép nối lại các phần của file download bị dán đoạn hoặc chia thành nhiều luồng download.

### III. 3xx Redirection (Sự chuyển hướng lại)

- 300 Multiple Choices: Một danh sách các link. Người sử dụng có thể chọn một link và tới vị trí đó. Tối đa 5 địa chỉ. Ví dụ: List các file video với format khác nhau
- 301 Moved Permanently: Request hiện tại và các request sau được yêu cầu di chuyển tới một URI mới.
- 302 Found: Đây là một ví dụ cho thấy sự mâu thuẫn giữa thực tiễn và quy chuẩn. Ở phiên bản HTTP/1.0 nó có nghĩa là yêu cầu Client chuyển hướng đến một URL tạm thời (tương tự như là 301 Moved Permanently) nhưng phần lớn các browser lại thực hiện nó với ý nghĩa của 303 See Other(sẽ nói sau đây). Do đó từ phiên bản HTTP/1.1 có thêm hai mã 303 và 307 để phân biệt rõ hành vi, nhưng một số ứng dụng web và framework vẫn sử dụng 302 như thể là 303.
- 303 See Other (Xuất hiện từ HTTP/1.1): Response trả về của Request có thể tìm thấy ở một URL khác bằng cách sử dụng phương thức GET.
- 304 Not Modified: Đây là Status-Code tới một If-Modified-Since hoặc If-None-Match header, nơi mà URL không được chỉnh sửa từ ngày cụ thể.
- 305 Use Proxy: Tài nguyên yêu cầu chỉ có sẵn thông qua một proxy, địa chỉ mà được cung cấp trong các Response. Nhiều HTTP Client (như Mozilla và Internet Explorer) không xử lý một cách chính xác phản ứng với mã trạng thái này, chủ yếu là vì các lý do an ninh.
- 306 Switch Proxy: Mã này hiện không còn được sử dụng, ý nghĩa ban đầu của nó là "Các Request tiếp theo nên sử dụng các proxy được chỉ định".
- 307 Temporary Redirect (xuất hiện từ HTTP/1.1): Trong trường hợp này, Request hiện tại cần được lặp lại một URI khác nhưng các Request trong tương lai vẫn sử dụng URI gốc.

### IV. 4xx: Client Error (Lỗi Client)

![](https://miro.medium.com/max/2400/1*8xtbzaB2Elv3AQx4GkV4oA.gif)

- 400 Bad Request: Server không thể xử lý hoặc sẽ không xử lý các Request lỗi của phía client (ví dụ Request có cú pháp sai hoặc Request lừa đảo định tuyến ...)
- 401 Unauthorized: Tương tự như 403 Forbidden nhưng được sử dụng khi yêu cầu xác thực là bắt buộc và đã không thành công. Các Response bắt buộc phải có thành phần WWW-Authenticate chứa các thách thức với tài nguyên được yêu cầu. Một số trang web vấn đề HTTP 401 khi một địa chỉ IP bị cấm từ các trang web (thường là các tên miền trang web) và địa chỉ cụ thể là từ chối quyền truy cập một trang web.
- 402 Payment Required: Hiện tại mã này chưa được sử dụng và nó được dự trữ cho tương lai. Mục đích ban đầu là mã này có thể được sử dụng như là một phần của đề án tiền mặt hoặc micropayment kỹ thuật số, nhưng điều đó đã không xảy ra, và mã này thường không được sử dụng. Google API sử dụng Status-Code này nếu một nhà phát triển đặc biệt đã vượt quá giới hạn số lần yêu cầu.
- 403 Forbidden: Request là hợp lệ nhưng server từ chối đáp ứng nó. Nó có nghĩa là trái phép, người dùng không có quyền cần thiết để tiếp cận với các tài nguyên.
- 404 Not Found: Các tài nguyên hiện tại không được tìm thấy nhưng có thể có trong tương lai. Các request tiếp theo của Client được chấp nhận.
- 405 Method Not Allowed: Request method không được hỗ trợ cho các tài nguyên được yêu cầu. Ví dụ Một GET request đến một POST resource, PUT Request gọi đến một tài nguyên chỉ đọc.
- 406 Not Acceptable: Server chỉ có thể tạo một Response mà không được chấp nhận bởi Client.
- 407 Proxy Authentication Required: Bạn phải xác nhận với một Server ủy quền trước khi Request này được phục vụ.
- 408 Request Timeout: Request tốn thời gian dài hơn thời gian Server được chuẩn bị để đợi.
- 409 Conflict: Request không thể được hoàn thành bởi vì sự xung đột, ví dụ như là xung đột giữa nhiều chỉnh sửa đồng thời.
- 410 Gone: Các resource được yêu cầu không còn nữa và sẽ không có sẵn một lần nữa, khi gặp mã lỗi này Client không nên có gắng tìm kiếm các tài nguyên này ở những lần sau.
- 411 Length Required: Content-Length không được xác định rõ. Server sẽ không chấp nhận Request nào không có nó.
- 412 Precondition Failed: Server sẽ không đáp ứng một trong những điều kiện tiên quyết của Client trong Request.
- 413 Payload Too Large: Server sẽ không chấp nhận yêu cầu, bởi vì đối tượng yêu cầu là quá rộng. Trước đây nó gọi là "Request Entity Too Large".
- 414 URI Too Long: URI được cung cấp là quá dài để Server xử lý, thường là kết quả của quá nhiều dữ liệu được mã hóa như là một truy vấn chuỗi của một GET Request, trong trường hợp đó nó phải được chuyển đổi sang một POST Request. Trước đây được gọi là "Request-URI Too Long"
- 415 Unsupported Media Type: Server sẽ không chấp nhận Request, bởi vì kiểu phương tiện không được hỗ trợ. Ví dụ khi Client upload một ảnh có định dạng image/svg+xml, nhưng server yêu cầu một định dạng khác.
- 416 Range Not Satisfiable: Client yêu cầu một phần của tập tin nhưng server không thể cung cấp nó. Trước đây được gọi là "Requested Range Not Satisfiable"
- 417 Expectation Failed: Máy chủ không thể đáp ứng các yêu cầu của trường Expect trong header.

### V. 5xx: Server Error (Lỗi Server)

![](https://miro.medium.com/max/1440/1*Y-BHUzdE1AhGNfuM-5-W6Q.png)

- 500 Internal Server Error: Một thông báo chung chung, được đưa ra khi Server gặp phải một trường hợp bất ngờ, Message cụ thể là không phù hợp.
- 501 Not Implemented: Server không công nhận các Request method hoặc không có khả năng xử lý nó.
- 502 Bad Gateway: Server đã hoạt động như một gateway hoặc proxy và nhận được một Response không hợp lệ từ máy chủ nguồn.
- 503 Service Unavailable: Server hiện tại không có sẵn (Quá tải hoặc được down để bảo trì). Nói chung đây chỉ là trạng thái tạm thời.
- 504 Gateway Timeout: Server đã hoạt động như một gateway hoặc proxy và không nhận được một Response từ máy chủ nguồn.
- 505 HTTP Version Not Supported: Server không hỗ trợ phiên bản “giao thức HTTP”.

Trên đây là danh sách các Status-Code phổ biến nhất, ngoài ra còn nhiều các Status-Code tiêu chuẩn đã được nhưng nghĩa như : 418, 421, 506, 507, 508, 511 ... Cám ơn các bạn đã theo dõi.

VI. Tài liệu tham khảo List of HTTP status codes (Wiki): [https://en.wikipedia.org/wiki/List_of_HTTP_status_codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-ve-http-status-code</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-ve-http-status-code</guid>
            <pubDate>Mon, 12 Aug 2019 18:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React Hooks: Memoization]]></title>
            <description><![CDATA[When and how to memoize React Hooks for performance, and how to avoid solving imaginary performance problems before they exist.]]></description>
            <link>https://hungvn.com/blog/react-hooks-memoization</link>
            <guid isPermaLink="true">https://hungvn.com/blog/react-hooks-memoization</guid>
            <pubDate>Mon, 05 Aug 2019 12:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Bí Kíp Bạn Có Thể Dùng Khi Phạm Sai Lầm Với Git]]></title>
            <description><![CDATA[
Những nội dung sau rất nguy hiểm, nếu bạn làm theo, xin hãy chịu trách nhiệm về bản thân mình.
Nếu có gì sai sót, mong bạn hãy chỉ ra để tôi được biết

# Ở trên local

Có hiệu quả khi làm việc trên môi truờng phát triển của bản thân, không làm ảnh hưởng đến người khác. Khi làm việc trên remote sẽ phát sinh ảnh hưởng đến người khác nên rất nguy hiểm.

## Sự cố 1: Khi trong commit message lỡ có những từ cấm kị khiến bạn chỉ muốn chết đi cho xong

Để sửa lại nội dung commit thì rất đơn giản. Cũng có thể thêm được cả file vào trong commit

```git
$ git commit --amend
# Sau lệnh này ta có thể thay đổi nội dung commit message một cách tuỳ ý
```

## Sự cố 2: Khi lỡ tay commit dưới tên của môt user khác

Khi làm việc ở nhà và khi làm việc trên công ty thì hẳn sẽ có lúc sử dung git config khác nhau và cũng có lúc bị nhầm thiết lập.

Ở đây chúng ta đang nói về việc thay đổi tác giả (Author) Hãy đổi Commiter ở .gitconfig hoặc .git/config

### Khi muốn đổi tên user hoặc email của HEAD

```git
# Hãy sửa lại user.name và user.email
$ git commit --amend -m "nội dung commit message" --author="user.name <user.email>"
```

### Trường hợp muốn sửa lại commit từ lâu rồi

```git
$ git rebase -i <commit>

====
# Sau lệnh này sẽ mở ra editor nên hãy sửa lại như sau rồi lưu lại

# (trước khi sửa) các commit cũ từ trên xuống dưới
pick aa11bbc commit message 1
pick b2c3c4d commit message 2
pick 4e56fgh commit message 3
・・・

# (Sau khi sửa) Đổi commit cần sửa sang edit
edit aa11bbc commit message 1
pick b2c3c4d commit message 2
pick 4e56fgh commit message 3
・・・
====

# Sau đó thì sửa tương tự
$ git commit --amend -m "commit message" --author="user.name <user.email>"

# Trở lại như cũ
$ git rebase --continue
```

### (NGUY HIỂM) Viết lại toàn bộ lịch sử commit

Khi muốn sửa các commit của người dùng (committer) nhất định thì có thể dùng cách sau để sửa

Lịch sử commit sẽ bị thay đổi hoàn toàn

```git
git filter-branch --commit-filter '
        if [ "$GIT_COMMITTER_NAME" = "<Old Name>" ];
        then
                GIT_COMMITTER_NAME="<New Name>";
                GIT_AUTHOR_NAME="<New Name>";
                GIT_COMMITTER_EMAIL="<New Email>";
                GIT_AUTHOR_EMAIL="<New Email>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD
```

## Sự cố ３: Khi đã lỡ tay commit một số file thừa nhưng sau khi nghĩ lại thì nên ignore thì hơn

### Trường hợp commit xoá

Nếu có những phần thừa thì ta xoá đi rồi thêm vào ignore

```git
# Đầu tiên là xoá các file đã commit khỏi repository
$ git rm --cached <tên file>

# Sau đó là thêm vào gitignore
$ echo '<tên file>' >> .gitignore
```

### Trường hợp muốn coi như là chưa từng có file đó

Khi mà bạn muốn: "Hả, file nào cơ, là gì có file nào như thế ?"

```git
# Trường hợp chỉ xoá khỏi lịch sử commit （để lại ở working tree）
$ git filter-branch -f --index-filter 'git rm --cached -rf --ignore-unmatch <tên file>' HEAD

# Trường hợp xoá khỏi lịch sử commit và cả ở working tree
$ git filter-branch -f --index-filter 'git rm -rf --ignore-unmatch <tên file>' HEAD
```

## Sự cố 4: Khi mà tên branh bạn đặt quá là "chuối"

Nếu không ai nhìn thấy thì ta "bí mật" sửa lại tên branch thôi nào !

```git
$ git branch -m <tên branch sau khi đổi>
```

## Sự cố 5: Khi trong phút nông nổi bạn lỡ commit và giờ muốn commit đó biến mất

### Không để cho ai biết （＝ người khác vẫn chưa pull về）

Sửa lại phần lịch sử commit ngay trước đó

```git
# Tuỳ vào từng trường hợp mà ta có 3 cách sau để đưa lịch sử commit về như cũ

# 1. Chỉ đưa HEAD về như cũ
$ git reset --soft HEAD~

# 2. Đưa HEAD và index về như cũ
$ git reset HEAD~

# 3. Đưa cả index, working tree về 1 commit trước đó
$ git reset --hard HEAD~
```

### Trường hợp đã bị ai đó phát hiện（＝ người khác đã pull về）

Nếu thay đổi lịch sử commit sẽ dẫn đến tình trạng lộn xộn nên ta cầm dùng commit xoá để giải quyết

```git
$ git revert <commit>
```

## Sự cố 6: Khi muốn tổng hợp những commit vụn vặt trước đây thành một commit

Sử dụng rebase + squash (or fixup) để tổng hợp lại các commit cũ

```git
# Rebase về n commit trước (có bao gồm cả HEAD)
# Ví dụ) git rebase -i HEAD~3
$ git rebase -i HEAD~<số lượng commit>

====
# Sau lệnh này sẽ mở ra editor nên hãy sửa lại như sau rồi lưu lại

# (trước khi sửa) các commit cũ từ trên xuống dưới
pick aa11bbc commit message 1
pick b2c3c4d commit message 2
pick 4e56fgh commit message 3
・・・

# (sau khi sửa) các commit trước là squash sẽ được tổng hợp vào 1 commit ở đằng trước
pick aa11bbc commit message 1
squash b2c3c4d commit message 2
squash 4e56fgh commit message 3
・・・
====
```

Thay vì dùng squash có thể dùng fixup nhưng khi đó commit message của những commit được fixup sẽ bị mất

## Sự cố ７: Khi bạn muốn chia commit to thành những commit nhỏ hơn một cách thông minh

Ở mục 6, tuy tổng hợp lại là tốt nhưng khi tổng hợp quá nhiều cũng sẽ trở thành vấn đề Rất tiện khi mà những commit chức năng bị lẫn vào những commit sửa bug

```git
# Đây là việc không làm sau khi đã push code lên remote

# Đầu tiên là đưa HEAD và index về 1 commit trước đó
# Nói cách khác là ta coi như là chưa từng có commit to đùng kia và chỉ giữ lại trạng thái của working tree
$ git reset HEAD~

# Dùng lệnh sau đây để thêm (y) hoặc không thêm (n) các phần nhỏ (=hunk) vào index
# Nếu các phần nhỏ đó vẫn chưa đủ nhỏ thì dùng (s) để tiếp tục chia nhỏ hơn （Chi tiết của git add -p thì hãy hỏi anh Google nhé）
$ git add -p

# Khi các phần cần thay đổi đã có thì ta commit
$ git commit -m "commit message"

# Sau đó ta lặp đi lặp lại các bước như trên cho phần còn lại
```

## Sự cố ８: Khi lỡ tay commit nhầm sang một branch khác

Có những lúc ta sơ suất lỡ tay commit thẳng vào master trong khi thực ra là muốn commit vào một branch khác

```git
# Đầu tiên là tạo một branch khác chứa trạng thái mà ta đã commit
$ git branch other-branch

# Đưa HEAD, index của master về 1 commit trước đó
$ git reset --hard HEAD~

# Check out sang branch có commit trước đó
$ git checkout other-branch
```

## Sự cố ９: Khi muốn xoá hoàn toàn các file không cần thiết

Có những lúc ta muốn 1 phát xoá tất tần tật những file tự động sinh ra hoặc những file tự động back up. Nếu không phải là những file cần git quản lý hoặc những file sẽ commit thì xoá đi thôi. Ơ mà cái này cũng ko phải là sự cố nhỉ...

```git
# Đầu tiên là add＆commit tất cả những thứ cần thiết lại
# Nếu không làm như thế này thì những file này cũng bị xoá mất đó
$ git add <file cần commit>
$ git commit -m "commit message"

# Dùng git stash để sơ tán cả những file untracked
$ git stash -u

# drop các thứ đã stash để xoá đi
$ git stash drop
```

Tiện đây thì trong trường hợp chỉ là những file mà git không quản lý thì chỉ như sau là OK

```git
# Kiểm tra lại các file sẽ xoá cho chắc
$ git clean -n

# Tiến hành xoá bỏ
$ git clean -f
```

## Sự cố 10: Khi tạm thời cần tạm dừng công việc hiện tại và chuyển sang một branch khác

Tuy mình không xấu nhưng có những lúc cần phải tạm dừng công việc để làm việc khác

```git
# Tạm thời lưu lại các phần công việc còn đang làm dở
$ git stash -u

# Chuyển sang một branch khác và làm việc
$ git checkout -b other-branch
~làm việc, làm việc, làm việc~
$ git add <các file cần thiết>
$ git commit -m "commit message"

# Trở về branch cũ
$ git checkout origin-branch

# Lấy lại các nội dung công việc đang làm dở trước đó
$ git stash pop
```

## Sự cố 11：Khi lỡ tay xoá mất một commit cực kì cực kì quan trọng

Đây hẳn là sự cố khủng khiếp nhất. Có thể xảy ra khi lỡ tay git reset --hard Tuy nhiên, commit nào cũng có thể hồi phục được

```git
# Đầu tiên là xem lại toàn bộ lịch sử commit
$ git reflog

# Từ đó chọn commit muốn phục hồi và khôi phục lại
# ví dụ）git reset --hard HEAD@{2}
$ git reset --hard <commit>
```

## Sự cố 12: Khi lỡ tay xoá mất branch và muốn lấy lại

Nếu vẫn còn reflog thì không có sao. Vẫn có thể hồi phục lại được Nếu commit lên một branch không tên, sau đó check out sang một branch khác bị xoá mất thì cũng tương tự

Tương tự giống như sự cố 13 dưới đây

```git
# Đầu tiên là xem lại toàn bộ lịch sử commit
$ git reflog

# Từ các commit này, chọn rồi tạo branch mới
# ví dụ）git branch new-branch HEAD@{2}
$ git branch <tên branch> <commit>
```

## Sự cố 13: Khi muốn thay đổi một phần nội dung commit

Khi có những typo nhỏ và muốn chỉnh sửa thì ko cần thiết phải tạo commit mới để sửa mà hãy tiến hành sửa lại luôn

```git
# Chỉ định commit muốn sửa lại
$ git rebase -i <commit>

====
# Sau lệnh này sẽ mở ra editor nên hãy sửa lại như sau rồi lưu lại

# (trước khi sửa) các commit cũ từ trên xuống dưới
pick aa11bbc commit message 1
pick b2c3c4d commit message 2
pick 4e56fgh commit message 3
・・・

# (Sau khi sửa) Đổi commit cần sửa sang edit
edit aa11bbc commit message 1
pick b2c3c4d commit message 2
pick 4e56fgh commit message 3
・・・
====

# Commit cần sửa sẽ được khai triển working tree nên ta chỉ cần sửa rồi sau đó add lại
$ git add <tên file>

# Sửa lại commit
$ git commit --amend

# Hoàn tất rebase để trở lại như cũ
$ git rebase --continue

# Khi muốn huỷ bỏ rebase
$ git rebase --abort
```

## Sự cố 14: Khi có conflict trong quá trình rebase

Khi không merge mà tiến hành rebase thì nếu có conflict, chắc hẳn là hoảng loạn rồi

```git
# Khi đang ở branch1 rồi rebase từ branch2 vào
$ git rebase branch2

~~ Phát sinh conflict ~~

# Sẽ trở thành branch không tên nền cần phải chú ý
$ git branch

* (no branch, rebasing branch2)
  branch1
  branch2
  master

# Hãy cố gắng giải quyết các conflict

# Sau khi hoàn thành, ta add rồi tiến hành rebase
$ git add <tên file>

# Thay đổi commit
$ git commit --amend

$ git rebase --continue
```

### Sự cố 15: Khi đã merge nhưng lại muốn trở lại như lúc trước

Chỉ cho trường hợp mà người khác vẫn chưa pull code về

```git
# tiến hành merge
$ git checkout <tên brach nguồn>
$ git merge <tên branch muốn merge>

# Sau khi merge, nhưng lại muốn trở lại như trước thì làm như sau
# Nếu chỉ định là ORIG_HEAD thì có thể trở lại trạng thái trước khi merge
$ git reset --hard ORIG_HEAD
```

# Ở trên Remote

## Sự cố 16: Khi pull từ remote về thì có quá nhiều conflict nên tạm thời muốn trở lại như cũ

Sau khi pull code về cập nhật nhưng thấy conflict nhiều như núi thì quả là muốn trở lại như cũ Gần giống như sự cố 15

```git
# Lấy từ code mới remote
$ git pull origin master

# Phát sinh conflict

# Suy nghĩ lại thì trong pull(fetch + merge) muốn bỏ phần merge đi
$ git reset --hard ORIG_HEAD
```

## Sự cố 17: Lỡ tay push force lên master trên remote

Việc push -f lên origin/master là việc bị cấm Tuy nhiên thì thỉnh thoảng vẫn có một số người làm...

Ta sẽ sửa lại như sau

### Trường hợp chỉ cần push về 1 commit trước đó

```git
# Cái này ko được làm đâu nhé, push force
$ git commit -m "commit message"
$ git push -f origin master

# Nếu là một công ty nghiêm túc thì đến đây chắc chắn sẽ nổi giận đấy

# Nếu muốn đưa về 1 commit tước đó thì làm như sau
$ git push -f origin HEAD~:master
```

Nếu trên local cũng muốn như vậy thì tiến hành reset cũng tốt

```git
$ git reset HEAD~
$ git push -f origin master
```

### Nếu muốn xoá đi vài commit trước đó

```git
# Cái này ko được làm đâu nhé, push force
$ git commit -m "commit message"
$ git push -f origin master

# Khi bị mắng và muốn trở về như cũ thì
$ git rebase -i <commit muốn rebase về>

====
# Sau lệnh này sẽ mở ra editor nên hãy sửa lại như sau rồi lưu lại

# (trước khi sửa) các commit cũ từ trên xuống dưới
pick aa11bbc commit message 1
pick b2c3c4d commit message 2
・・・

# (Sau khi sửa) Xoá các commit không cần thiết đi
pick b2c3c4d commit message 2

・・・
====

# push force lại một lần nữa
$ git push -f origin master
```

## Sự cố 18: Sau khi release phát hiện thấy có bug và muốn trở về như cũ

Do phát sinh thiệt hại nên những thứ đã merge và maste cần phải chuyển tạm thời về như cũ Tuy nhiên không thể revert từng commit 1 nếu có nhiều commit

```git
# Kiểm tra commit log
$ git log --oneline --graph

====
*   1x3y5z7 - Merge pull request #4 from develop
|\
| * a2b45c7 - (develop) commit 3
* | dbc65f4 - commit 2
* | f0b0a91 - commit 1
# Chỉ định điểm muốn revert về (Cơ bản 1 là OK)
====

# Nếu merge develop vào master thì chỉ định master sẽ là １、develop là ２ rồi revert
# Ví dụ）git revert -m 1 1x3y5z7
$ git revert -m 1 commit merge>
```

Nếu vẫn chưa có ai kéo phần code này về thì có thể làm đươc cả những việc sau nữa（Cái này nguy hiểm）

```git
# Trở về trạng thái trước khi merge
$ git reset ORIG_HEAD

# PUSH FORCE
$ git push -f origin master
```

## Sự cố 19：Khi sau khi chuyển lại và đã commit thêm một số commit mới nhưng không thể merge lại được

Ở sự cố 18, khi đã xoá bỏ merge, tiến hành chỉnh sửa nhưng merge lại không được
commit revert không có nghĩa là sẽ ko còn commit merge nữa mà là làm ngược lại những việc mà commit merge làm
Thế nên, khi merge lại thì cần phải revert lại commit revert

```git
# Tiếp tục của sự cố 18

# Thêm commit vào develop branch
$ git checkout develop
$ git commit -m "commit message"

# Checkout sang master
$ git checkout master

# revert lại commit revert
$ git revert <commit revert>

# merge develop
$ git merge develop
```

# Khi muốn thử những điều trên ở một môi trường an toàn thì

Đúng là nếu chưa quen mà tự nhiên lại thực hành luôn thì rất vất vả.
Những ai đã có sản phầm thì có thể clone về và dùng cái đó để test thử
Nếu thế thì cho dù có bị thất bại thì cũng không gây ảnh hưởng gì đến môi trường làm việc chính.
Những ai chưa có sản phẩm có thể lên Github, tìm hiếm 1 repo nào đó nổi tiếng, clone về rồi thực hành
Tuy nhiên cần chú ý 1 điều là những cái này chỉ được thử ở trên môi trường local thôi nhé
Nếu muốn thử cả ở trên remote nữa thì có thể chuẩn bị sẵn môi trường test trên Github, clone về rồi thử
Hình dung cơ bản như sau

```git
# git clone về
$ git clone <URL của repository>

# Thử nghiệm trên local

# Kiểm tra remote hiện tại
$ git remote -v

# Xoá remote đã đăng ký
$ git remote rm origin

# Tạo remote đã được chuẩn bị sẵn cho test ở Github và thay đổi lại remote
$ git remote add origin <URL của repository mới>

# Sau đó là thử nghiệm trêm remote
```
]]></description>
            <link>https://hungvn.com/blog/bi-kip-ban-co-the-dung-khi-pham-sai-lam-voi-git</link>
            <guid isPermaLink="true">https://hungvn.com/blog/bi-kip-ban-co-the-dung-khi-pham-sai-lam-voi-git</guid>
            <pubDate>Sat, 03 Aug 2019 15:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách xử lý các lỗi thường gặp trong Git]]></title>
            <description><![CDATA[
Đầu tiên muốn sửa được lỗi trong git ta phải thực hiện tạo ra nó trước đã. Vậy phần 1 mình sẽ nói 1 số lệnh cơ bản trong git theo follow tạo và sử dụng 1 project.

## Các lệnh cơ bản

**1\. Khởi tạo git**

- Chắc ai cũng biết rồi muốn khởi tạo 1 repo ta dùng lệnh

```git
git init
```

**2\. Thêm mới remote vào project**

```git
# hiển thị danh sách remote trong git của project
git remote -v

# Thêm mới một remote vào git
git remote add origin <url>
```

**3\. Clone project**

- Bạn phát hiện ra là bạn đã có url của project sẵn rồi thì tội gì phải khởi tạo git mới nữa. Thay vào đó hãy dùng clone

```git
git clone
```

**4\. Làm việc cùng branch**

- Git là một hệ thống quản lý phiên bản phân tán, vì thế mô hình của nó giống như một cái cây. Vậy bạn có thể nhận ra luôn là mỗi cái cây luôn có một thân cây chính, và các cành, nhánh nhỏ. Tương tự trong git ta có branch thể hiện mỗi nhánh nhỏ của một cái cây và nhánh chính tương đương với thân cây thường được gọi là master. Nếu từng làm việc thực tế trong các dự án bạn thường thấy nhánh master sẽ là nhánh rỗng, thay vào đó những developer sử dụng các nhánh có tên như development, product, test,.... Điều này giúp cho các lập trình viên phân biện và thao tác trên những môi trường tương ứng quan quá trình phát triển phần mềm một cách dễ dàng và minh bạch hơn.

![](https://images.viblo.asia/3b171116-23fb-4bd2-a8ac-65b63fe65372.png)

- Một số lệnh cơ bản

```git
# Danh sách branch
git branch

# tạo mới branch
git branch (<name>)

# Di chuyển từ branch hiện tại đến một branch khác bằng tên branch đó
git checkout <name>

# Tạo và di chuyển từ branch hiện tại đến một branch mới
git checkout -b <name>
```

**5\. Hợp nhất branch**

- Đây là một trong những câu lệnh cơ bản thường dùng của quy trình. Nhưng với việc các tool hỗ trợ như github, gitlab,... thì việc sử dụng câu lệnh này chỉ còn nằm ở dưới local mà thôi.

```git
# để hợp nhất nhánh branch-name vào nhánh master
git merge <branch-name>
```

**6\. Cập nhật code mới nhất về**

Khi làm việc một mình thực tế bạn sẽ không cần đến git nhưng khi làm việc nhóm và muốn lấy code mới nhất từ một nhánh nào đó trên repo online về thì bạn sẽ dùng lệnh sau:

```git
git pull origin <branch>
```

**7\. xem status và một vài thứ nữa**

```git
git status

git diff –-stat
```

## Những sự cố thường gặp trong Git

### 1\. Viết sai message commit

- Để thay đổi nộ dung commit, thêm, sửa file vào commit rất đơn giản bạn chỉ cần sử dụng

```git
git commit --amend
```

### 2\. Đặt sai tên branch

- Việc gõ nhầm hay thiết thành phần theo convention khi đặt tên branch là không hiếm. Lúc mới tiếp cận bạn thường lựa chọn giải pháp là tạo một branch mới. Có một cách nhanh hơn rất nhiều giống như rename trong các phần làm việc với file đó là dùng câu lệnh:

```git
git branch -m <tên branch sau khi đổi>
```

### 3\. Commit chơi chơi và giờ muốn nó bay màu

- Việc làm ngốc ngếch này diễn ra thường xuyên trong quá trình làm việc, vậy làm thế nào để code dữ nguyên và xóa commit đó đi, đầu tiên bạn phải tìm hiểu một số lý thuyết sau:

**Note: HEAD, Working tree, Index trong git là gì?**

- Git giữ một con trỏ đặc biệt có tên HEAD. Trong Git, đây là một con trỏ tới nhánh nội bộ mà bạn đang làm việc
- Trên Git, những thư mục được đặt trong sự quản lý của Git mà mọi người đang thực hiện công việc trong thực tế được gọi là working tree.
- Giữa repository và working tree tồn tại một nơi gọi là index. Index là nơi để chuẩn bị cho việc commit lên repository

#### Cách 1: Sử dụng reset (khi chưa có ai pull về)

- `git reset HEAD~`

  Di chuyển HEAD về vị trí commit reset và vẫn giữ nguyên tất cả các thay đổi của file, nhưng loại bỏ các thay đổi khỏi stage (Đưa HEAD và index về như cũ)

```git
git reset {commit_id}
```

- `git reset --hard HEAD~`
  - Di chuyển con trỏ HEAD về vị trí commit reset và loại bỏ tất cả sự thay đổi của file sau thời điểm commit reset
  - HEAD~ có ý nghĩa giống với HEAD^ hay @^, nghĩa là quay về trước 1 commit
  - Muốn quay về trước n commit, VD 5 commit thì có thể thay bằng HEAD~5.
  - --hard có nghĩa là bỏ commit đi và bỏ cả những thay đổi chưa được commit trong working space. Khi này môi trường sẽ hoàn toàn "sạch sẽ" như thời điểm trước khi commit

- `git reset --soft HEAD~`
  - Lệnh này chỉ di chuyển HEAD về vị trí commit reset. Trạng thái của stage và tất cả sự thay đổi của file sẽ được giữ nguyên
  - --soft có nghĩa là bỏ commit đi nhưng giữ nguyên những thay đổi chưa được commit trong working space.
  - --soft hữu dụng khi bạn muốn giữ lại những thay đổi chưa commit cho lần commit tiếp theo

#### Cách 2: Sử dụng revert (người khác đã pull về)

```git
# commit_hash là mã commit
git revert <commit_hash>
```

#### Cách 3: Sử dụng --amend

```git
git commit --amend
# Bạn có thể sử dụng lệnh này để viết lại commit message
# Option --no-edit sử dụng khi bạn chỉ muốn thêm file mà không muốn sửa commit message
git commit --amend --no-edit
```

### 4\. Khi lỡ tay commit nhầm sang một branch khác

- Có những lúc ta sơ suất lỡ tay commit thẳng vào master trong khi thực ra là muốn commit vào một branch khác

```git
#Đầu tiên là tạo một branch khác chứa trạng thái mà ta đã commit
$ git branch other-branch
#Đưa HEAD, index của master về 1 commit trước đó
$ git reset --hard HEAD~
#Check out sang branch có commit trước đó
$ git checkout other-branch
```

### 5\. Gộp nhiều commit thành một commit

Sử dụng rebase + squash (or fixup) để tổng hợp lại các commit cũ

- Squash: giữa nguyên commit message của những commit trước
- Fixup: xoá commit message của những commit trước

```git
Rebase về n commit trước (có bao gồm cả HEAD)
# Ví dụ) git rebase -i HEAD~3
$ git rebase -i HEAD~<số lượng commit>
# Sau lệnh này sẽ mở ra editor nên hãy sửa lại như sau rồi lưu lại
# Note: Với vim bấm “a” để bắt đầu edit → Bấm ECS để dừng thao tác edit → Bấm “shift + z + z” để save
# (trước khi sửa) các commit cũ từ trên xuống dưới
pick aa11bbc commit message 1
pick b2c3c4d commit message 2
pick 4e56fgh commit message 3
・・・
# (sau khi sửa) các commit trước là squash sẽ được tổng hợp vào 1 commit ở đằng trước
pick aa11bbc commit message 1
squash b2c3c4d commit message 2
squash 4e56fgh commit message 3
```

### 6\. Chia commit to thành nhiều commit nhỏ

```git
# Đầu tiên là đưa HEAD và index về 1 commit trước đó.
# Nói cách khác là ta coi như là chưa từng có commit to đùng kia và chỉ giữ lại trạng thái của working tree
$ git reset HEAD~
# Dùng lệnh sau đây để thêm các phần nhỏ vào index
$ git add -p
# Khi các phần cần thay đổi đã có thì ta commit
$ git commit -m "commit message"
# Sau đó ta lặp đi lặp lại các bước như trên cho phần còn lại
```

### 7\. Chuyển xang nhánh khác khi đang làm việc giở

```git
# Tạm thời lưu lại các phần công việc còn đang làm dở
$ git stash -u
# Chuyển sang một branch khác và làm việc
$ git checkout -b other-branch
$ git add <các file cần thiết>
$ git commit -m "commit message"
# Trở về branch cũ
$ git checkout origin-branch
# Lấy lại các nội dung công việc đang làm dở trước đó
$ git stash pop
```

### 8\. Hồi phục commit quan trọng khi lỡ tay xóa nó đi

- Đây hẳn là sự cố khủng khiếp nhất. Có thể xảy ra khi lỡ tay git reset --hard .Tuy nhiên, commit nào cũng có thể hồi phục được

```git
# Đầu tiên là xem lại toàn bộ lịch sử commit
$ git reflog
# Từ đó chọn commit muốn phục hồi và khôi phục lại
# ví dụ: git reset --hard HEAD@{2}
$ git reset --hard <commit>
```

### 9\. Khôi phục branch đã xóa

```git
# Đầu tiên là xem lại toàn bộ lịch sử commit
$ git reflog
# Từ các commit này, chọn rồi tạo branch mới
# ví dụ: git branch new-branch HEAD@{2}
$ git branch <tên branch> <commit_id>
```

### 10\. Khôi phục về trạng thái trước khi merge

- Note: Chỉ cho trường hợp mà người khác vẫn chưa pull code về

```git
git reset --hard ORIG_HEAD
# Commit trước khi reset được tham chiếu bằng ORIG_HEAD
```

### 11\. Khôi phục về trạng thái trước khi pull từ remote

- Sau khi pull code về cập nhật nhưng thấy conflict nhiều như núi thì quả là muốn trở lại như cũ

```git
# Lấy từ code mới remote
$ git pull origin master
# Phát sinh conflict
# Suy nghĩ lại thì trong pull(fetch + merge) muốn bỏ phần merge đi:
$ git reset --hard ORIG_HEAD
```

### 12\. Khi bạn muốn rename 1 nhánh cả ở local và trên remote (github)

```git
git branch -m new-name
git push remote-name :old-name new-name
```

### 13\. Khi bạn muốn xoá 1 branch trên remote từ xa

```git
git push origin --delete remote-branch-name
```

Đó là các thao tác cơ bản và cách sửa một số lỗi thường gặp khi làm việc với git của mình. Rất mong các bạn góp ý để mình cải thiện bài viết này và các bài sau hơn nữa.
]]></description>
            <link>https://hungvn.com/blog/cach-xu-ly-cac-loi-thuong-gap-trong-git</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-xu-ly-cac-loi-thuong-gap-trong-git</guid>
            <pubDate>Fri, 02 Aug 2019 10:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Clean Up Redux Code with React-Redux Hooks]]></title>
            <description><![CDATA[
If you search “Redux hooks” on Google, you won’t find a lot of resources about the cool new [React-Redux hooks API](https://react-redux.js.org/api/hooks). What you _will_ find are bunch of articles about how to use React hooks as a replacement for Redux and other state management libraries.

But this was never the point of hooks. [React hooks](https://reactjs.org/docs/hooks-intro.html) were made to allow developers to write functional components that can do all the things we once needed class components for, like using state or lifecycle methods. React hooks improve the developer experience by optimizing the organization, maintainability, and readability of React code. They allow us to share logic between components without using complicated design patterns like [render props](https://reactjs.org/docs/render-props.html) or [higher-order components](https://reactjs.org/docs/higher-order-components.html), and they cut down on the dense boilerplate required by JavaScript classes. They don’t really add any new functionality to React; functional components using hooks can’t do anything that class components can’t. But they _do_ allow us to write much cleaner code.

If these improvements make you feel comfortable with using React to manage your application state without an external library, go for it! But React hooks are by no means the death of state management libraries like Redux. In fact, [React-Redux version 7.1.0](https://github.com/reduxjs/react-redux/releases/tag/v7.1.0), released in June 2019, provides developers with its own set of hooks, with methods like [useSelector()](https://react-redux.js.org/next/api/hooks#useselector) and [useDispatch()](https://react-redux.js.org/next/api/hooks#usedispatch). Like React’s hooks API, these hooks let us cleanly organize our logic within the body of a functional component. They also eliminate the need to wrap our components in a higher-order [connect()](https://react-redux.js.org/api/connect) component to connect to our store.

Let’s look at a ridiculously simple example to see how this works. (This assumes basic knowledge of how React and Redux applications work.)

![](https://miro.medium.com/max/626/1*z1BSgaeufKhRDYVCAk2TjQ.png)

Here we have a web page that lets you increment and decrement a counter. Super exciting, right? Behind the scenes, we have a whole React and Redux app setup to manage the state of the counter. (Fork this [GitHub repo](https://github.com/maximiliangonzalez/counter) and play around with the code!)

```javascript
export const increment = count => ({
  type: "CHANGE_COUNT",
  payload: count + 1,
});

export const decrement = count => ({
  type: "CHANGE_COUNT",
  payload: count - 1,
});
```

Here are some action creators to increment and decrement the counter in our store. I could have declared a CHANGE_COUNT constant to protect against misspellings, but the store is small enough to skip that step.

```javascript
import { createStore } from "redux";

const initialState = {
  count: 0,
};

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case "CHANGE_COUNT":
      return {
        ...state,
        count: action.payload,
      };
    default:
      return state;
  }
};
```

This is business as usual for Redux. The new hooks API doesn’t reduce this part of the boilerplate. Now let’s look at how we connect our store to the React app with the counter:

```javascript
import React from "react";

import { render } from "react-dom";
import { Provider } from "react-redux";

import App from "./components/App.jsx";
import store from "./reducers/counterReducer";

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
```

Now let’s look at how our App component would get access to data from the Redux store without using the React-Redux hooks API:

```javascript
import React from "react";

import { connect } from "react-redux";

import * as actions from "../actions/actions";

class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { count, increment, decrement } = this.props;

    return (
      <div>
        <h1>The count is {count}</h1>
        <button onClick={() => increment(count)}>+</button>
        <button onClick={() => decrement(count)}>-</button>
      </div>
    );
  }
}

const mapStateToProps = store => ({
  count: store.count,
});

const mapDispatchToProps = dispatch => ({
  increment: count => dispatch(actions.increment(count)),
  decrement: count => dispatch(actions.decrement(count)),
});

export default connect(mapStateToProps, mapDispatchToProps)(App);
```

This is how we get our simple counter app to work with React and Redux. But that’s a lot of boilerplate for something so simple. Let’s take a look at what’s going on here. First of all, we have a constructor that does nothing but give our class component access to the props being passed down to it. This component doesn’t actually need to be a class component since it’s not using local state or any lifecycle methods, so let’s quickly refactor it to a functional component so we can bring in the hooks:

```javascript
import React from "react";

import { connect } from "react-redux";

import * as actions from "../actions/actions";

const App = props => {
  const { count, increment, decrement } = props;

  return (
    <div>
      <h1>The count is {count}</h1>
      <button onClick={() => increment(count)}>+</button>
      <button onClick={() => decrement(count)}>-</button>
    </div>
  );
};

const mapStateToProps = store => ({
  count: store.count,
});

const mapDispatchToProps = dispatch => ({
  increment: count => dispatch(actions.increment(count)),
  decrement: count => dispatch(actions.decrement(count)),
});

export default connect(mapStateToProps, mapDispatchToProps)(App);
```

Okay, that’s a bit nicer, but it’s still more complicated than it needs to be. We still need to definemapStateToProps() and mapDispatchToProps()functions to connect to the Redux store, and wrap our App component in the connect()higher-order component so we can pass these pieces of the store and dispatching functions down to our App component as props. We also have to write this.props over and over again (or, to avoid that, we can use [object destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) assignment like I did to assign our props to variables) in order to access these pieces of the store and dispatching functions. It’s all a bit messy, isn’t it? Let’s clean this up a bit.

First, let’s look at [useSelector()](https://react-redux.js.org/next/api/hooks#useselector). This new React-Redux hook takes the place of mapStateToProps() and allows you to directly hook into your Redux store without needing to pass state as props from a higher-order component. This function takes a callback as an argument. That callback takes the entire Redux store as its argument, but you don’t have to worry about grabbing the store yourself, because useSelector() gets it from the Provider that we wrapped our App component in. In the body of the callback, you can return whichever piece of the store you want to have access to and save it as a variable in your component.

Since our Redux store’s initial state has a countproperty with the initial value of 0, we can write _const count = useSelector(store => store.count)\_which \_selects_ the countproperty from our store and assigns it to the countconstant we just declared. Before we press any buttons, that variable will have the value of0. Let’s refactor our component to use the useSelector() hook.

```javascript
import React from "react";

import { useSelector, connect } from "react-redux";

import * as actions from "../actions/actions";

const App = props => {
  const { increment, decrement } = props;
  const count = useSelector(store => store.count);

  return (
    <div>
      <h1>The count is {count}</h1>
      <button onClick={() => increment(count)}>+</button>
      <button onClick={() => decrement(count)}>-</button>
    </div>
  );
};

const mapDispatchToProps = dispatch => ({
  increment: count => dispatch(actions.increment(count)),
  decrement: count => dispatch(actions.decrement(count)),
});

export default connect(null, mapDispatchToProps)(App);
```

This is a lot nicer already. We can get direct access to values from our Redux store now, and not rely on some higher-order component we didn’t write to pass it to our component as props. We can reference our count constant anywhere in the body of our component and it will have the current value from our Redux store. If any actions are dispatched that update the countproperty in our store, our countconstant will be updated as well. We can simply call useSelector()again with a different selector and assign it to another variable if we need to make another selection from the store.

But, speaking of dispatching actions, our mapDispatchToProps() function still forces us to use connect() to get functions as props that we’d rather directly access in our component. Let’s do something about this.

The other main React-Redux hook, [useDispatch()](https://react-redux.js.org/next/api/hooks#usedispatch), takes care of this for us. This one is super simple. Just call useDispatch() in your component, and it will return a function you can use to dispatch actions to your Redux store. Pass a call to an action creator to this returned function, and it will work just like a function from mapDispatchToProps().

Let’s refactor our component one last time to implement the useDispatch() hook:

```javascript
import React from "react";

import { useSelector, useDispatch } from "react-redux";

import * as actions from "../actions/actions";

const App = () => {
  const dispatch = useDispatch();
  const count = useSelector(store => store.count);

  return (
    <div>
      <h1>The count is {count}</h1>
      <button onClick={() => dispatch(actions.increment(count))}>+</button>
      <button onClick={() => dispatch(actions.decrement(count))}>-</button>
    </div>
  );
};

export default App;
```

Now that we can access our store and the dispatch function directly in our component, there’s no longer any need to wrap App in a higher-order component to pass anything to it as props. This results in much cleaner code where everything is defined where it’s relevant. If you need to change any logic pertaining to Redux, you won’t have to look outside of the body your component anymore. Now, everything is nicely contained.

Obviously, this example is so simple that it hardly makes sense to use Redux here (or even React, really). But these hooks can be used the exact same way they are here, even if they’re in a more complex component that also uses React hooks like [useState()](https://reactjs.org/docs/hooks-state.html) or [useEffect()](https://reactjs.org/docs/hooks-effect.html).

Admittedly, there still is a lot of time-consuming boilerplate writing you need to do to set up a React-Redux app, even if you’re using the hooks APIs. Prototyping apps such as [preducks](https://www.preducks.com/) (pictured at the top of the article) can help you eliminate a lot of the mindless setup and truly optimize your developer experience. (There’s even a [node module](https://www.npmjs.com/package/preducks?activeTab=readme) for extremely quick setup: think [_create-react-app_](https://www.npmjs.com/package/create-react-app) but with Redux boilerplate too). preducks also uses [TypeScript](https://www.typescriptlang.org/). Much like hooks, TypeScript also improves your developer experience by bringing strict, static type checking into JavaScript, letting you eliminate bugs and keep better track of the shape you expect your data to be. This gets useful when your React-Redux apps get large and your data gets complex. Give preducks a try if you’re interested in seeing React Redux hooks in action (along with React hooks and TypeScript).

(For a more complex example of how to use React-Redux hooks along with TypeScript, check out this [GitHub repo](https://github.com/palgorhythm/todoTShooks) showing how to build a to-do app with these technologies.)
]]></description>
            <link>https://hungvn.com/blog/clean-up-redux-code-with-react-redux-hooks</link>
            <guid isPermaLink="true">https://hungvn.com/blog/clean-up-redux-code-with-react-redux-hooks</guid>
            <pubDate>Tue, 23 Jul 2019 08:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[3 Cách thực thi Child method từ Parent Component]]></title>
            <description><![CDATA[
First off, let me express that this is generally _not_ the way to go about things in React land. Usually what you want to do is pass down functionality to children in props, and pass up notifications from children in events (or better yet: [`dispatch`](https://reactjs.org/docs/hooks-reference.html#usereducer)).

But if you _must_ expose an imperative method on a child component, you can use [refs](https://reactjs.org/docs/refs-and-the-dom.html). Remember this is an escape hatch and usually indicates a better design is available.

> Previously, refs were only supported for Class-based components. With the advent of [React Hooks](https://reactjs.org/docs/hooks-intro.html), that's no longer the case

## Using Hooks and Function Components (`>= react@16.8`)

```javascript
import React, { forwardRef, useRef, useImperativeHandle } from "react";

// We need to wrap component in `forwardRef` in order to gain
// access to the ref object that is assigned using the `ref` prop.
// This ref is passed as the second parameter to the function component.
const Child = forwardRef((props, ref) => {
  // The component instance will be extended
  // with whatever you return from the callback passed
  // as the second argument
  useImperativeHandle(ref, () => ({
    getAlert() {
      alert("getAlert from Child");
    },
  }));

  return <h1>Hi</h1>;
});

const Parent = () => {
  // In order to gain access to the child component instance,
  // you need to assign it to a `ref`, so we call `useRef()` to get one
  const childRef = useRef();

  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.getAlert()}>Click</button>
    </div>
  );
};
```

[Functioning example](https://codesandbox.io/s/8lxr0pq179)

Documentation for `useImperativeHandle()` is [here](https://reactjs.org/docs/hooks-reference.html#useimperativehandle):

> `useImperativeHandle` customizes the instance value that is exposed to parent components when using `ref`.

## Using Class Components (`>= react@16.4`)

```javascript
class Parent extends Component {
  constructor(props) {
    super(props);
    this.child = React.createRef();
  }

  onClick = () => {
    this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert("getAlert from Child");
  }

  render() {
    return <h1>Hello</h1>;
  }
}

ReactDOM.render(<Parent />, document.getElementById("root"));
```

[Functioning Example](https://codesandbox.io/embed/kw5mn93wmr)

## Legacy API (`<= react@16.3`)

For historical purposes, here's the callback-based style you'd use with React versions before 16.3:

```javascript
const { Component } = React;
const { render } = ReactDOM;

class Parent extends Component {
  render() {
    return (
      <div>
        <Child
          ref={instance => {
            this.child = instance;
          }}
        />
        <button
          onClick={() => {
            this.child.getAlert();
          }}
        >
          Click
        </button>
      </div>
    );
  }
}

class Child extends Component {
  getAlert() {
    alert("clicked");
  }

  render() {
    return <h1>Hello</h1>;
  }
}

render(<Parent />, document.getElementById("app"));
```
]]></description>
            <link>https://hungvn.com/blog/3-cach-thuc-thi-child-method-tu-parent-component</link>
            <guid isPermaLink="true">https://hungvn.com/blog/3-cach-thuc-thi-child-method-tu-parent-component</guid>
            <pubDate>Fri, 12 Jul 2019 11:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tại sao các React developer nên modularize các ứng dụng của mình]]></title>
            <description><![CDATA[Why breaking a React application into small, single-purpose modules is the most reliable path to a maintainable, comprehensible codebase.]]></description>
            <link>https://hungvn.com/blog/tai-sao-cac-react-developer-nen-modularize-cac-ung-dung-cua-minh</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tai-sao-cac-react-developer-nen-modularize-cac-ung-dung-cua-minh</guid>
            <pubDate>Tue, 25 Jun 2019 19:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách tổ chức các ứng dụng React tốt hơn]]></title>
            <description><![CDATA[A practical strategy for structuring large React and Redux codebases so they stay organised and maintainable as teams and features grow.]]></description>
            <link>https://hungvn.com/blog/cach-to-chuc-cac-ung-dung-react-tot-hon</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-to-chuc-cac-ung-dung-react-tot-hon</guid>
            <pubDate>Wed, 12 Jun 2019 12:15:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tại sao nên sử dụng object cho một danh sách trong Redux]]></title>
            <description><![CDATA[
If you are working on an application, chances are that you are using a list of items: users, comments, posts, todos, movies etc.

The most common data structure to choose for lists in Javascript is an array.

I would like to explain why that might not be the best choice when storing those lists in a state management tool like Redux or React Context.

### C[RUD] operations on a single item

If you want to make one of the RUD (read, update or delete) operations to a single item, you always need to iterate.

Except for the create, where you just need to add the item to the list.

#### Read

If you use an array, you need to find that item by filtering. When you have an object, you only need the identifier you used as key.

#### Update

When using an array the fastest way is to map and change the one you want to change. With an object, just set the property pointing to the updated item.

#### Delete

Filter for an array. Just delete that key for an object.

### Fetching from an API

This is where using an object shines over using an array.

When your items come from the backend, you need to fetch them. What happens when you fetch the same item twice? Or the same list twice? Or a list with some duplicated and some new items?

If you use an array you need to make sure to not duplicate the items. You need to handle that scenario. It means adding more complexity.

How about adding to an object the same item twice?

Nothing to do. The items are stored by key. In an object you can’t have the same key twice. You will only substitute the fetched item by the one already in the state.

### When NOT to use an object

If you don’t have a unique identifier for each item. Or you want to keep an order without using an extra property.

### Code Examples

Let’s take a look at some code examples. The following code examples represent only the operations described above. They are NOT redux reducers or other kind of state creator. They are just some snippets to better understand the point I am making above.

We have a list of comments.

```javascript
// array
const comments = [
  { id: '1', text: 'add code examples' },
  { id: '2', text: 'examples would be great for this article' },
  { id: '3', text: 'hi there' },
];
// object
const comments = {
  1: { id: '1', text: 'please add code examples' },
  2: { id: '2', text: 'examples would be great for this article' },
  3: { id: '3', text: 'hi there' },
};
```

#### Read comment id 2

```javascript
const commentId = "2";
// array
comments.find(comment => comment.id === commentId);
// object
comments[commentId];
```

#### Update comment id 1

```javascript
const updatedComment = { id: "1", text: "add code examples, please" };
// array
comments.map(comment => {
  if (comment.id === updatedComment.id) {
    return updatedComment;
  }
  return comment;
});
// object
comments[updatedComment.id] = updatedComment;
```

#### Delete comment id 3

```javascript
const commentId = "3";
// array
comments.filter(comment => comment.id !== commentId);
// object
delete comments[commentId];
```

#### Adding a new comment

We have to assume that we don’t know whether it already exists or not

```javascript
const newComment = { id: '4', text: 'thanks for the code examples!' };
// array
if (comments.find((comment) => comment.id === newComment.id) {
  comments = comments.map((comment) => {
    if (comment.id === newComment.id) {
      return newComment;
    }
    return comment;
  });
} else {
  comments = comments.concat([newComment]);
}
// object
comments[newComment.id] = newComment;
```

### What if you need an array somewhere in your code?

Sometimes, you might find that it’s easier to use an array for your list of items. For example, when you are rendering a list. It’s easier to have an array, use a map and create the element in each iteration.

This has an easy solution. Instead of accessing directly the state, use a function. What is also known as a **selector**.

A selector is a function that takes some state and returns the data you need. Usually in the schema or structure you want.

```javascript
// object
const comments = {
  1: { id: "1", text: "please add code examples" },
  2: { id: "2", text: "examples would be great for this article" },
  3: { id: "3", text: "hi there" },
};
// transform to array
const commentsSelector = commentsObj => {
  return Object.keys(commentsObj).map(commentKey => commentsObj[commentKey]);
};
// usage of the selector
const commentsArray = commentsSelector(comments);
```

### Conclusion

Using an object will save your future self some time and bugs. Do her/him a favor and use an object to store a list of items.

Even as a beginner, I recommend you to to use objects instead of arrays to store lists of items. The struggle pays off at the end. As most struggles do :)

More on best practices in state shapes in [Redux Docs on Normalization](https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape).

Thank you for reading. I would love to hear your thought in the comments.
]]></description>
            <link>https://hungvn.com/blog/tai-sao-nen-su-dung-object-cho-mot-danh-sach-trong-redux</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tai-sao-nen-su-dung-object-cho-mot-danh-sach-trong-redux</guid>
            <pubDate>Mon, 27 May 2019 19:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Xây dựng hệ thống Component có thể tái sử dụng với React và Styled-components]]></title>
            <description><![CDATA[
Coding and Design. A love / hate relationship. Some developers dread the tedious task of implementing design guidelines provided by UX / UI Designers, others love to make things beautiful. I identify with the latter, but at the same time, why not build a smart system that will reduce the time and confusion in adopting design guidelines. We will have a look at how to create a Component System that makes your development process stupidly fast and still follows and enforces design guidelines.

I will first introduce the styled-components library and then show you how to build a design system with it.

### Prerequisite: Design System

To enable this workflow, we will need some design guidelines that we can follow. In the last years, many big companies rebuilt their design systems, such as [Microsoft](https://www.microsoft.com/design/fluent/), [Airbnb](https://airbnb.design/building-a-visual-language/), [IBM](https://www.ibm.com/design/language/) and many more. These design systems can range from color palettes, defining border-radii, margins, paddings and so on to fully fledged UI components, such as cards and containers and even UX-focused components that include workflows, animations, and some logic.

If you do not have an explicit design system, don’t worry. We will start very simple and you can extend it over time. I started out with a couple of components and for many of my projects I can reuse some or all and just adapt to the new project.

We will have a look at building layout components, buttons, text components, and some more feature-packed components, including animations.

### A quick introduction to styled-components

Let’s first talk about what [styled-components](https://www.styled-components.com/) does and how to use it. I will also describe why I prefer it over other possibilities to style a web application.

Styled-components is a kind of CSS in JS solution, meaning that you do not have external CSS files to fiddle with. Everything is in one place — logic, styling, and markup. At first sight, this might seem confusing and if you don’t know how to handle it, your JS files will blow up in no time. This article is here to provide you a guide to prevent that and efficiently write components.

The basic usage of styled-components is as follows:

```javascript
import React from "react";

import styled from "styled-components";

const StyledButton = styled.button`
  border-radius: 5px;
  background-color: #a1cdf1;
  color: #fff;
  padding: 10px 15px;
  outline: none;
  border: none;
  cursor: pointer;
`;

const Application = () => {
  return <StyledButton onClick={() => console.log("clicked")}>Click me</StyledButton>;
};
```

As you can see, you can basically put any kind of CSS in the style declaration. Styled-components exports all of the common HTML elements, so you can use them from the imported package, for example styled.div`or styled.a or anything else. Maybe you have noticed the backticks` around the styles, this is plain JavaScript (ES6) and is called template literals. I assume you have seen something like this before console.log(`Bob is ${age} years old.`) , enabling you to put JavaScript within a string. Styled-components behaves no different and you can use **any kind of JavaScript** inside your style declaration.

But wait, there’s more. Since we’re using React.js to build our application, we highly depend on state and props. Wouldn’t it be useful to have styles based on our Application state? Yes it would, and styled-components provides a simple solution for that. You can pass a function to your style declarations, with one parameter, being the component’s props. You can then use props to adjust your styling. Here is an example:

```javascript
import React from "react";

import ReactDOM from "react-dom";
import styled from "styled-components";

const StyledButton = styled.button`
  border-radius: 5px;
  background-color: ${props => (props.secondary ? "#F7A072" : "#a1cdf1")};
  color: #fff;
  padding: 10px 15px;
  outline: none;
  border: none;
  cursor: pointer;
  margin: 15px;
`;

const Application = () => {
  return (
    <div>
      <StyledButton>Click me</StyledButton>
      <StyledButton secondary>Click for secondary Action</StyledButton>
    </div>
  );
};
```

There is some more functionality provided by styled-components, for example extending styles, the ability to style any component, theming or the css -helper (which we’re going to use later). For now, this should be a good starting point to build our component system, but feel free to have a look at the [docs](https://www.styled-components.com/docs).

#### Summary: Advantages of styled-components over css files

Traditional CSS is hard to keep clean. To prevent selector collisions, you would have to use specific class-naming terminology to ensure isolation (i.e. BEM). Conditional styling would be implemented by passing ternary / logical statements to the className prop, for example:

```javascript
<Button className={`btn ${this.props.isActive ? 'btn--active' : 'btn--primary' }'}
```

This not only makes the actual class names hard to read (and to write), but you don’t really know what visual effect it will have. To find out you would have to search for the CSS file and find the matching classes. For me, using CSS files feels like a ‘horizontal’ approach, where CSS is on the same level as your markup and logic. For me — and more so in React.js — the structure should be more “vertical”. Underlying everything is the logic, which in turn puts markup on the page and styles it accordingly.

With styled-components, we use that approach. Everything depends on logic and lives in one place, being isolated. When you want to change a Button, you know exactly where to look. When instantiating these components, the syntax is very declarative, since you’re using very basic props (mostly you will use booleans). There is no need trying to demystify conditional classNames and the styles behind them.

```javascript
<Button primary active={this.props.isActive} big />
```

Another great advantage is that you can very easily create an implicit documentation for your app, using props-destructuring. When you forgot what possible options there are for styling a specific component, just look at the function parameters and you’re good to go. Here’s a more in-depth example of the Button component:

```javascript
import React from "react";

import Button from "./Button.jsx";

const Application = () => {
  return (
    <div>
      <Button>Click me</Button>
      <Button secondary>Click me</Button>
      <Button inverse big>
        Click me
      </Button>
    </div>
  );
};
```

```javascript
import React from "react";

import styled, { css } from "styled-components";

const StyledButton = styled.button`
  border-radius: 5px;
  background-color: ${props => (props.secondary ? "#F7A072" : "#a1cdf1")};
  color: #fff;
  padding: 10px 15px;
  font-size: ${props => {
    if (props.big) return "20px";
    return "16px";
  }};
  outline: none;
  border: none;
  cursor: pointer;
  margin: 15px;
  border: 2px solid ${props => (props.secondary ? "#F7A072" : "#a1cdf1")};
  ${props => {
    return (
      props.inverse &&
      css`
        background-color: #fff;
        color: #a1cdf1;
      `
    );
  }}
`;

const Button = ({ secondary, big, inverse, ...props }) => {
  return <StyledButton secondary={secondary} big={big} inverse={inverse} {...props} />;
};

export default Button;
```

As you can see, it is very easy to recognize what props you can pass to the Button component.

Lastly, it is still possible to override and extend any styles with inline styles.

![Photo by David Pisnoy on Unsplash](https://cdn-images-1.medium.com/max/1600/1*Sa1xgXyCno2Gyhb6ZQiwxA.jpeg)

#### Multiple types: css`` vs each property individually

Hopefully you spotted that I used the `css` helper in the extended Button example. There are different ways to apply styles based on props, either with inline ternary / conditional operators (Button.jsx:6) for one style property, full JavaScript block (Button.jsx:9–12) for one style property or the css helper (Button.jsx:19–27) for multiple style properties. Obviously, you may use what fits your coding style best. However, I tend to use the `css` helper for mostly separated chunks of styling, that are not mixed with other props and usually use separate conditionals for one style property, just to keep my code clean.

---

Here is the Button example on codesandbox.io:

`codesandbox: l27mlxk449`

---

### Building the component system

Let’s get to the real work. We saw how the basic principles work, now let’s build a more sophisticated system.

> A full working example with all components is available on [Github](https://github.com/gisderdube/react-component-system).

#### Container

![Default container, 25px — <Container />](https://cdn-images-1.medium.com/max/2400/1*Kcyyq-E_LhAp6m3ukb-l7Q.jpeg)

One component I very often use is a container component. Usually, you don’t want your content to overflow a certain width on your page. I would aim for 900–1000px, depending on application content. You could have a component with the desired width and position it with flex, but what if you want to have a full width background(-color)? There is an easy trick for that, using padding and calc() it, depending on your viewport width. This is will create a nice container, has full width, centers the content and can easily be nested and reused.

Here’s the code for that Container component:

```javascript
import React from "react";

import styled from "styled-components";

const Container = styled.div`
  padding-left: ${props => {
    if (props.full) return 0;
    return "calc((100vw - 960px) / 2)";
  }};
  padding-right: ${props => {
    if (props.full) return 0;
    return "calc((100vw - 960px) / 2)";
  }};
  padding-top: ${props => {
    if (props.fullVertical) return 0;
    if (props.small) return "15px";
    return "25px";
  }};
  padding-bottom: ${props => {
    if (props.fullVertical) return 0;
    if (props.small) return "15px";
    return "25px";
  }};
`;

export default Container;
```

I added a couple of other props to the Container, being small , full and fullVertical. Sometimes you want a full-width image or similar. Feel free to extend or change the component as you wish, I just found these rules useful.

Here’s some visual examples:

![<Container fullVertical />](https://cdn-images-1.medium.com/max/2400/1*99Y_P7Z07QrpYG2vDLS8kQ.jpeg)

---

![<Container full small />](https://cdn-images-1.medium.com/max/2400/1*6kaf52ZydJTzemF0wqQnwQ.jpeg)

---

> You can set global styles for your application, such as font-family or base font-size, with styled-component’s [`createGlobalStyle`](https://www.styled-components.com/docs/api#createglobalstyle) helper.

---

#### Flexbox

With the Container in place, let’s have a look at our second component, which we will also use for layout: a flex wrapper and child components. This component simply saves us time to type display: flex, flex-direction: …, justify-content: ..., and all of the other flex properties over and over again.

![<Flex justifyAround>…</Flex>](https://cdn-images-1.medium.com/max/2400/1*dPIao5k5EgoVR1A5WtylAA.jpeg)

Way easier than thinking of a class, assigning it and giving the styling properties manually, isn’t it?

Let’s even add another sub-component, declared in the same file / module, that gives us a nice column, either half, a third or a quarter of our parent element.

![<Flex noWrap><Column three />(x3)</Flex>](https://cdn-images-1.medium.com/max/2400/1*9WP-l7ZEonOCgm5r_OgstQ.jpeg)

We can also use a smaller Column, use it fewer times and spread it over the Flex parent:

![<Flex justifyAround><Column four />(x3)</Flex>](https://cdn-images-1.medium.com/max/2400/1*YS3MxZD1yiNAX3pxfXZzHA.jpeg)

Here is the code:

```javascript
import React from "react";

import styled from "styled-components";

const Flex = styled.div`
  display: flex;
  flex-wrap: ${props => {
    if (props.wrapReverse) return "wrap-reverse";
    else if (props.noWrap) return "nowrap";
    return "wrap";
  }};
  justify-content: ${props => {
    if (props.justifyContent) return props.justifyContent;
    if (props.justifyCenter) return "center";
    else if (props.justifyAround) return "space-around";
    else if (props.justifyBetween) return "space-between";
    else if (props.justifyEnd) return "flex-end";
    return "flex-start";
  }};
  align-items: ${props => {
    if (props.alignItems) return props.alignItems;
    else if (props.alignStretch) return "stretch";
    else if (props.alignEnd) return "flex-end";
    if (props.alignCenter) return "center";
    else if (props.alignBaseline) return "baseline";
    return "flex-start";
  }};
  align-content: ${props => {
    if (props.alignContent) return props.content;
    else if (props.contentStart) return "flex-start";
    else if (props.contentEnd) return "flex-end";
    else if (props.contentCenter) return "center";
    else if (props.contentBetween) return "space-between";
    else if (props.contentAround) return "contentAround";
    return "stretch";
  }};
  flex-direction: ${props => (props.column ? "column" : "row")};
`;

export const Column = styled.div`
  width: ${props => {
    if (props.three) return "33.33%";
    if (props.four) return "25%";
    return "50%";
  }};
  padding: ${props => (props.noPadding ? 0 : "15px")}};
`;

export default Flex;
```

#### Button

Having implemented basic layout components, we can now proceed to a bit more approachable stuff. Let’s try to improve our Button that we saw in the introduction. What if we could have a loading sign being displayed, based on props. Remember, we want to have one entry point for the component, the component itself should take care of the rest, logic, styling and markup. For the loading sign to be displayed, we don’t want our caption, meaning React children, to be visible. Our component instance could look somewhat like this:

```javascript
<Button loading={this.state.loading} />
```

![](https://cdn-images-1.medium.com/max/2400/1*gTOL15dNWSzXIhvKM86GpA.gif)

When we look at the code, we see that the children are dynamically rendered, depending on the prop loading :

```javascript
import React from "react";

import styled, { css } from "styled-components";

import Loader from "./Loader";

const StyledButton = styled.button`
  border-radius: 5px;
  background-color: ${props => (props.secondary ? "#F7A072" : "#a1cdf1")};
  color: #fff;
  padding: 10px 15px;
  font-size: ${props => {
    if (props.big) return "20px";
    return "16px";
  }};
  outline: none;
  border: none;
  cursor: pointer;
  margin: 15px;
  border: 2px solid ${props => (props.secondary ? "#F7A072" : "#a1cdf1")};
  ${props => {
    return (
      props.inverse &&
      css`
        background-color: #fff;
        color: #a1cdf1;
      `
    );
  }}
`;

const Button = ({ secondary, big, inverse, loading, children, ...props }) => {
  return (
    <StyledButton secondary={secondary} big={big} inverse={inverse} {...props}>
      {loading ? <Loader small white /> : children}
    </StyledButton>
  );
};

export default Button;
```

> Note that I also added a Loader component. Have a look at the repo on Github to see what it does, I use it to display any loading state throughout the app, it can also be displayed top level, outside of the Button component.

#### Animated Card Component

Let’s tackle one more complex example, a card component with animations. We’re going to have a card that fades on page load and then displays its content. You can actually tweak any kind of behavior or animation and publish it through props. Another really nice trick is to have a scroll listener that will trigger the animation when our card comes on the screen and reverses the animation when we scroll to the top again (you can find an example for that on [our website](https://dube.io)). For now, we’ll just have a fade-in animation.

```javascript
<Card>...</Card>
<Card big>...</Card>
<Card primary delay={1500}>...</Card>
```

![](https://cdn-images-1.medium.com/max/1600/1*A-pWLeDUcd64kbM5PaemOg.gif)

As you can see, with predefined components like that, you can really easily implement more complex behavior and appearance in your application, with just one line of code. As a bonus, your designer will be very happy because the app looks exactly like he has imagined. When there are design changes, it is incredibly easy to implement them. Simply change the base component and the changes will apply throughout the whole application. Here’s the code for the card component:

```javascript
import React from "react";

import styled, { css, keyframes } from "styled-components";

const animatedCss = css`
  opacity: 1;
  transform: translateY(0);
`;

const primaryCss = css`
  background-color: #008bf8;
  color: #fff;
`;

const StyledCard = styled.div`
  width: ${props => (props.big ? "450px" : "300px")};
  padding: 15px;
  opacity: 0;
  transform: translateY(50px);
  transition: 500ms all ease-in-out;
  margin: ${props => (props.noMargin ? 0 : "15px")};
  box-shadow: 0 5px 15px -5px rgba(0, 0, 0, 1);
  border-radius: 5px;
  ${props => props.animated && animatedCss}
  ${props => props.primary && primaryCss}
`;

class Card extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      animated: false,
    };
  }

  componentDidMount() {
    setTimeout(() => {
      this.setState(() => {
        return { animated: true };
      });
    }, this.props.delay);
  }

  render() {
    const { delay = 0, noAnimation, primary, noMargin, big, ...props } = this.props;
    return (
      <StyledCard
        animated={this.state.animated}
        delay={delay}
        primary={primary}
        noAnimation={noAnimation}
        big={big}
        noMargin={noMargin}
        {...props}
      />
    );
  }
}

export default Card;
```

Now you might wonder why I have the delay prop. This seems a bit odd in the example above, but comes in extremely handy when having a whole list of cards:

![](https://cdn-images-1.medium.com/max/1600/1*KsUl-rWXG0OD1lP0oU4Vtw.gif)

---

#### Heading

Before we finish up, I just want to show the code of the Heading component, it should be clear by now how to use it:

```javascript
import React from "react";

import styled, { css } from "styled-components";

const baseStyle = css`
  margin-bottom: ${props => props.noMargin && "0"};
  color: #202020;
  font-family: "Poppins", sans-serif;
  font-weight: 600;
  margin-top: 0;
  text-align: ${props => {
    if (props.center) return "center";
    if (props.right) return "right";
    return "left";
  }};

  max-width: 100%;
`;

const HeadingOne = styled.h1`
  font-size: 42px;
  font-weight: bold;
  margin-bottom: 25px;
  ${baseStyle};
  @media (max-width: 480px) {
    font-size: 40px;
  }
`;

const HeadingTwo = styled.h2`
  font-size: 36px;
  font-weight: bold;
  margin-bottom: 20px;
  ${baseStyle};
`;

const HeadingThree = styled.h3`
  font-size: 28px;
  font-weight: bold;
  margin-bottom: 15px;
  ${baseStyle};
`;

const HeadingFour = styled.h4`
  font-size: 22px;
  font-weight: bold;
  margin-bottom: 10px;
  ${baseStyle};
`;

const HeadingFive = styled.h5`
  font-size: 18px;
  font-weight: bold;
  margin-bottom: 5px;
  ${baseStyle};
`;

const Heading = ({ h2, h3, h4, h5, noMargin, right, center, ...props }) => {
  if (h2) return <HeadingTwo noMargin={noMargin} right={right} center={center} {...props} />;
  if (h3) return <HeadingThree noMargin={noMargin} right={right} center={center} {...props} />;
  if (h4) return <HeadingFour noMargin={noMargin} right={right} center={center} {...props} />;
  if (h5) return <HeadingFive noMargin={noMargin} right={right} center={center} {...props} />;
  return <HeadingOne noMargin={noMargin} right={right} center={center} {...props} />;
};

export default Heading;
```

![Photo by Kevin Crosby on Unsplash](https://cdn-images-1.medium.com/max/1600/1*xar2PozlmWQqFc-HanTBhw.jpeg)

### Wrapping up

We covered a whole lot by now. Building a component system can be fun and does **save you a lot of time** in the long run. By enforcing a design system through reusable components, you ensure that your whole application looks according to the guidelines and changes can easily be implemented. Components should be built vertically, having one entry point and the possibility to return different elements, visual features or behaviors. The Heading component for example returns different html elements based on what props you pass. You can think of it as a “connector” between your explicit components and the behavior below the reusable entry point.

![](https://cdn-images-1.medium.com/max/1600/1*rH3xKEHsWDsI8ecO3IG4IQ.png)

To keep track of your components and remember what possible options there are, you can have a look at the destructured props or simply by checking the styled-components style declaration. To have a common ground for designers, developers and even product owners or stakeholders, you can build a sample page with all possible components. When you clone the [repository](https://github.com/gisderdube/react-component-system), you will see that I did the same. Be creative and try to build your own reusable components, what I often build are: Input (also including more logic), List, Table, Separator, Text and more!
]]></description>
            <link>https://hungvn.com/blog/xay-dung-he-thong-component-co-the-tai-su-dung-voi-react-va-styled-components</link>
            <guid isPermaLink="true">https://hungvn.com/blog/xay-dung-he-thong-component-co-the-tai-su-dung-voi-react-va-styled-components</guid>
            <pubDate>Mon, 20 May 2019 12:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React Hooks: Dễ dàng sáng tạo, tái sử dụng và chia sẻ code]]></title>
            <description><![CDATA[
Hooks are an upcoming feature in React that enable you to use state and many other React features without writing a class. This has some important ramifications for the future of React code, especially with regard to how components will be composed.

The motivation for hooks, as provided by the [official documentation](https://reactjs.org/docs/hooks-intro.html) from the Facebook React team, is that hooks solve some problems that they have encountered over five years of writing and maintaining React components. These problems are:

1.  It’s hard to reuse stateful logic between components
2.  Complex components become hard to understand
3.  Classes confuse both people and machines

In this short article, we will focus on how React hooks solve the first problem — the difficulty of reusing stateful logic between components — because it has the most wide-ranging consequences.

### Reusing Stateful Logic

For the past few years, the preferred ways of sharing stateful logic in React are higher-order components (HOCs) and render props. Both HOCs and render props require an additional component in the application component tree, and arguably they also make it somewhat more difficult to reason about the shared logic within the code. Now we can add React hooks as a way of sharing logic.

Let’s compare the options for dealing with cross-cutting concerns in React using a very simple example to highlight the differences between them.

### Higher-Order Component

A [higher-order component](https://reactjs.org/docs/higher-order-components.html) (HOC) is a widely-used pattern in React to reuse component logic, by wrapping the component around a target component and passing data to it via its props. In other words, a higher-order component is a function that takes your target component as an argument, and returns a the target component with additional data and functionality.

The following simple example shows a higher-order component that tracks the mouse position in a web app.

![](https://cdn-images-1.medium.com/max/1600/1*Oc9dlXJ9kTNrTyBVYQdLbg.png)

In the wrapped class component above, the mouse position is obtained via the [_mousemove_ event API](https://developer.mozilla.org/en-US/docs/Web/Events/mousemove) provided by browser windows. We set up an event listener and update the state which holds the mouse position coordinates. The class encapsulates the functionality, and now we can share it with other components.

So, using the higher-order component pattern, the function withMousePositiontakes any target component as an argument, and returns it with all its existing props plus one additional prop: the mousePosition coordinates.

![](https://cdn-images-1.medium.com/max/1600/1*txKyOwTtnTav8U_arBSJoA.png)

In this example we have shared the mousePosition coordinate data with a presentational App component. The dynamic mouse position is displayed in an orange paragraph:

![](https://cdn-images-1.medium.com/max/1600/1*l2-smXC3uGEqglE5PrZIHQ.png)

The wrapped AppWithMousePosition component can then be rendered to the DOM:

![](https://cdn-images-1.medium.com/max/1600/1*OcGPrQ_Chqv5xONR7UiVuQ.png)

Try the **HOC approach** for yourself in the following [CodeSandbox](https://codesandbox.io/s/43z216n6y9).

---

### Render Props

A [render prop](https://reactjs.org/docs/render-props.html) is a way of sharing code between React components using a prop whose value is a function. The prop is often called _render_, thus the terminology “render prop”.

Let’s see how our mouse position example introduced earlier looks when implemented using a render prop:

![](https://cdn-images-1.medium.com/max/1600/1*iLTz4A8jkUBxG4tk9RvJAA.png)

The stateful logic for the mouse position is the same as we used in the higher-order component earlier.

The difference between the HOC method and this render props method is that we now specify a function prop called render within the render method of the class component, which takes the state of the component as an argument, and renders it as a child of the class component:

![](https://cdn-images-1.medium.com/max/1600/1*4-GeK4NjlO4LNpZ_BjaVSw.png)

Note that the terminology “function as child” is also used when referring to this pattern.

Now, we can wrap any target component with this MousePosition component, and dynamically render the mouse position by passing it in via the render prop. This is a dynamic way of sharing stateful logic, compared with the statically defined higher-order component.

> As an aside, for more details regarding the pros and cons of higher-order components and render props, please see [this excellent article](https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce) by Michael Jackson, the co-author of React Router.

Returning to our example, we can now render a presentational App component by composing the MousePosition component within it. We render the dynamic mouse position within a sky-blue `<p>` element, which is passed via a function in the render prop:

![](https://cdn-images-1.medium.com/max/1600/1*vGhEf1Ml-i5u8PwyGBLPGA.png)

To summarize, the behavior associated with listening for mousemove events and storing the mouse position coordinates has been encapsulated in the MousePosition component, and can be used flexibly in any other component, via this “render props” pattern. This is an example of a composable component that has reusable, shareable state logic.

Try the **render props approach** for yourself in the following [CodeSandbox](https://codesandbox.io/s/rjprzkj29p).

---

### React Hooks

Now, let’s look at how “hooks” could be used to achieve the goal of reusing stateful logic within your apps, using the very same mouse position example:

![](https://cdn-images-1.medium.com/max/1600/1*7jTUgx_w2rWLIvpSo50g0g.png)

Note that we have created a “[custom hook](https://reactjs.org/docs/hooks-custom.html)” called useMousePosition. It is a function component, not a class component, but it does encapsulate state!

For our mouse position example, we are using two different React hooks within the body of our custom hook function:

- [State hook](https://reactjs.org/docs/hooks-state.html): useState
- [Effect hook](https://reactjs.org/docs/hooks-effect.html): useEffect

The useState hook lets us add React state to function components, without having to convert them into class components. The useState function hook takes the initial value of state as an argument, and returns a two-element array containing the state value (mousePosition), and a function to update that value (setMousePosition). You can see at the bottom of the function that we are returning the mousePosition state value from the function.

The useEffect hook lets you perform side effects in function components. Examples of side effects are getting data from an API, listening for browser events, and manually changing the DOM. The useEffect hook carries out the same tasks as the lifecycle methods componentDidMount, componentDidUpdate, and componentWillUnmount combined do in class components.

useEffect takes a callback function (called the “effect”) as its first argument, and runs it after each render of the component. In our example, the effect is to set up the mousemove event listener after the first render when the component is mounted. The returned callback from the effect, if specified, serves to “clean up” before the component is unmounted. In our example, we are removing the event listener when we unmount.

![](https://cdn-images-1.medium.com/max/1600/1*fwmjuTzC5ObwmdU2UmUQpg.png)

Within the effect callback, we are setting up a mousemove event listener called handleMouseMove, which itself calls setMousePosition with the updated mouse coordinates whenever the user moves the mouse.

The second argument to the useEffect function hook, if specified, is an **array of specific state values** that the effect will run on whenever the value updates. That is, the effect will run on each re-render of the component triggered by updates to those specific state values. If **no array** is specified, then the default behavior is to re-render the component and fire the effect whenever any of the state values updates.

In our example, we are passing an **empty array** [], which means that the effect does not depend on any state value updating in our component, i.e. our effect only runs on mount and it will clean up on unmount, but it won’t run on any mousePosition updates. The event listener already updates the mousePosition, so it is unnecessary to re-render the component when that happens.

Our useMousePosition custom hook completely replicates the behavior of the class components used in the HOC and render-props patterns earlier. It fully encapsulates the behavior we need in a **very compact**, **easy-to-understand**, and **reusable** way.

Now, we can share this dynamic mouse position functionality in any other component. Let’s call our custom hook useMousePosition in our presentational App component:

![](https://cdn-images-1.medium.com/max/1600/1*zf6AO_cN38s8W5j7W-XnQA.png)

Here, we are rendering the dynamic mouse coordinates in a pale green `<p>` tag.

Try the **hooks approach** for yourself in a [CodeSandbox](https://codesandbox.io/s/548z479m0n).

---

### Summary

Now you’ve seen the same mouse position example implemented in three different ways: **higher-order components**, **render props**, and **hooks**.

It is clear that by far and away **the most elegant** and **easy to follow** code is found in the React hook approach. In addition, **less code** is needed to achieve **the same results**.

Hooks make it easier than ever to separate out stateful component logic, data, and functionality into an encapsulated structure, making it convenient to reuse and share. The implications of this should not be underestimated. This is a **huge and exciting** development for React and everyone who uses it!
]]></description>
            <link>https://hungvn.com/blog/react-hooks-de-dang-sang-tao-tai-su-dung-va-chia-se-code</link>
            <guid isPermaLink="true">https://hungvn.com/blog/react-hooks-de-dang-sang-tao-tai-su-dung-va-chia-se-code</guid>
            <pubDate>Sun, 12 May 2019 17:10:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu chi tiết về React Hooks]]></title>
            <description><![CDATA[
React Hooks, unlike Class Components, provide **low-level** building blocks for optimizing and composing applications with minimal boilerplate.

Without in-depth knowledge, performance problems can arise and **code complexity** can increase due to **subtle bugs** and **leaky abstractions**.

I’ve created **12 part case study** to demonstrate common problems and ways to fix them. I’ve also compiled **React Hooks Radar** and **React Hooks Checklist** for small recommendations and quick reference.

---

### Case Study: Implementing Interval

The goal is to implement counter that starts from 0 and increases every 500ms. Three control buttons should be provided: start, stop and clear.

![](https://cdn-images-1.medium.com/max/1600/1*6UeqZz8r6rS9Gdl9fcLSow.gif)

#### Level 0: Hello World

```javascript
export default function Level00() {
  console.log('renderLevel00');
  const [count, setCount] = useState(0);
  return (
    <div>
      count => {count}
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
    </div>
  );
}
```

This is a simple, **correctly implemented** counter, which increments or decrements on user click.

#### Level 1: setInterval

```javascript
export default function Level01() {
  console.log('renderLevel01');
  const [count, setCount] = useState(0);
  setInterval(() => {
    setCount(count + 1);
  }, 500);
  return <div>count => {count}</div>;
}
```

Intention of this code is to increase counter every 500ms. This code has a huge **resource leak** and is **implemented incorrectly.** It will easily crash browser tab. Since Level01 function is called every time render happens, this component creates new interval every time render is triggered.

> Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s _render phase_). Doing so will lead to confusing bugs and inconsistencies in the UI.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect)

#### Level 2: useEffect

```javascript
export default function Level02() {
  console.log('renderLevel02');
  const [count, setCount] = useState(0);
  useEffect(() => {
    setInterval(() => {
      setCount(count + 1);
    }, 500);
  });
  return <div>Level 2: count => {count}</div>;
}
```

Most side-effects happen inside [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect). This code also has a huge **resource leak** and is **implemented incorrectly**. Default behavior of useEffect is to run after every render, so new interval will be created every time count changes.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect), [Timing of Effects](https://reactjs.org/docs/hooks-reference.html#timing-of-effects).

#### Level 3: run only once

```javascript
export default function Level03() {
  console.log('renderLevel03');
  const [count, setCount] = useState(0);
  useEffect(() => {
    setInterval(() => {
      setCount(count + 1);
    }, 300);
  }, []);
  return <div>count => {count}</div>;
}
```

Giving [] as second argument to useEffect will call function once, after mount. Even though setInterval is called only once, this code is **implemented incorrectly.**

count will increase from 0 to 1 and stay that way**.** Arrow functionwill be created once and when that happens, count will be 0.

This code has **subtle resource leak**. Even after component unmounts, setCount will still be called.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect), [Conditionally firing an effect](https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect).

#### Level 4: cleanup

```javascript
useEffect(() => {
  const interval = setInterval(() => {
    setCount(count + 1);
  }, 300);
  return () => clearInterval(interval);
}, []);
```

To prevent **resource leaks**, everything must be disposed when lifecycle of a hook ends. In this case returned function will be called after component unmounts.

This code **does not have resource leaks**, but is **implemented incorrectly**, just like previous one.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [Cleaning up an effect](https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect).

#### Level 5: use count as dependency

```javascript
useEffect(() => {
  const interval = setInterval(() => {
    setCount(count + 1);
  }, 500);
  return () => clearInterval(interval);
}, [count]);
```

Giving array of dependencies to useEffect will change its lifecycle. In this example useEffect will be called once after mount and every time count changes. Cleanup function will be called every time count changes to dispose previous resource.

This code **works correctly**, without any bugs, but it’s slightly **misleading**. setInterval is created and disposed every 500ms. Each setInterval is always called once.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect), [Conditionally firing an effect](https://reactjs.org/docs/hooks-reference.html#conditionally-firing-an-effect).

#### Level 6: setTimeout

```javascript
useEffect(() => {
  const timeout = setTimeout(() => {
    setCount(count + 1);
  }, 500);
  return () => clearTimeout(timeout);
}, [count]);
```

This code and the code above **work correctly**. Since useEffect is called every time count changes, using setTimeout has same effect as calling setInterval .

This example is inefficient, new setTimeout is created every time render happens. React has a better way for fixing the problem.

#### Level 7: functional updates for useState

```javascript
useEffect(() => {
  const interval = setInterval(() => {
    setCount(c => c + 1);
  }, 500);
  return () => clearInterval(interval);
}, []);
```

In previous example we ran useEffect on each count change. The was necessary because we needed to have always up-to-date current value.

useState provides API to update previous state without capturing the current value. To do that, all we need to do is provide lambda to setState .

This code **works correctly** and more efficiently. We are using a single setInterval during the lifecycle of a component. clearInterval will only be called once after component is **unmounted**.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useState](https://reactjs.org/docs/hooks-reference.html#usestate), [Functional updates](https://reactjs.org/docs/hooks-reference.html#functional-updates).

#### Level 8: local variable

```javascript
export default function Level08() {
  console.log('renderLevel08');
  const [count, setCount] = useState(0);
  let interval = null;
  const start = () => {
    interval = setInterval(() => {
      setCount((c) => c + 1);
    }, 500);
  };
  const stop = () => {
    clearInterval(interval);
  };
  return (
    <div>
      count => {count}
      <button onClick={start}>start</button>
      <button onClick={stop}>stop</button>
    </div>
  );
}
```

We’ve added start and stop buttons. This code is **implemented incorrectly,** stop button does not work. New reference is created during each render, so stop will have reference to null.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [Is there something like instance variables?](https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables)

#### Level 9: useRef

```javascript
export default function Level09() {
  console.log('renderLevel09');
  const [count, setCount] = useState(0);
  const intervalRef = useRef(null);
  const start = () => {
    intervalRef.current = setInterval(() => {
      setCount((c) => c + 1);
    }, 500);
  };
  const stop = () => {
    clearInterval(intervalRef.current);
  };
  return (
    <div>
      count => {count}
      <button onClick={start}>start</button>
      <button onClick={stop}>stop</button>
    </div>
  );
}
```

useRef is the go-to hook if mutable variable is needed. Unlike local variables, React makes sure same reference is returned during each render.

This code seems correct, but has a **subtle bug**. If start is called multiple times, setInterval will be called multiple times triggering **resource leak**.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useRef](https://reactjs.org/docs/hooks-reference.html#useref)

#### Level 10: useCallback

```javascript
export default function Level10() {
  console.log('renderLevel10');
  const [count, setCount] = useState(0);
  const intervalRef = useRef(null);
  const start = () => {
    if (intervalRef.current !== null) {
      return;
    }
    intervalRef.current = setInterval(() => {
      setCount((c) => c + 1);
    }, 500);
  };
  const stop = () => {
    if (intervalRef.current === null) {
      return;
    }
    clearInterval(intervalRef.current);
    intervalRef.current = null;
  };
  return (
    <div>
      count => {count}
      <button onClick={start}>start</button>
      <button onClick={stop}>stop</button>
    </div>
  );
}
```

To avoid resource leak, we simply ignore calls if interval is already started. Although calling clearInterval(null) does not trigger any errors, it’s still good practice to dispose resource only once.

This code has **no resource leaks**, is **implemented correctly**, but might have a **performance problem**.

memoization is main performance optimization tool in React. React.memo does shallow comparison and if references are same, render is skipped.

If start and stop were passed to a memoized component, the whole optimization would fail, because new reference is returned after each render.

🔗 [**React Hooks: Memoization**](https://medium.com/@sdolidze/react-hooks-memoization-99a9a91c8853)

#### Level 11: useCallback

```javascript
export default function Level11() {
  console.log('renderLevel11');
  const [count, setCount] = useState(0);
  const intervalRef = useRef(null);
  const start = useCallback(() => {
    if (intervalRef.current !== null) {
      return;
    }
    intervalRef.current = setInterval(() => {
      setCount((c) => c + 1);
    }, 500);
  }, []);
  const stop = useCallback(() => {
    if (intervalRef.current === null) {
      return;
    }
    clearInterval(intervalRef.current);
    intervalRef.current = null;
  }, []);

  return (
    <div>
      count => {count}
      <button onClick={start}>start</button>
      <button onClick={stop}>stop</button>
    </div>
  );
}
```

To enable React.memo to do its job properly, all we need to do it to memoize functions, using useCallback hook. This way, same reference will be provided after each render.

This code has **no resource leaks**, is **implemented correctly**, has **no performance problem**, but code is **quite complex,** even for a simple counter.

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)

#### Level 12: custom hook

```javascript
function useCounter(initialValue, ms) {
  const [count, setCount] = useState(initialValue);
  const intervalRef = useRef(null);
  const start = useCallback(() => {
    if (intervalRef.current !== null) {
      return;
    }
    intervalRef.current = setInterval(() => {
      setCount(c => c + 1);
    }, ms);
  }, []);
  const stop = useCallback(() => {
    if (intervalRef.current === null) {
      return;
    }
    clearInterval(intervalRef.current);
    intervalRef.current = null;
  }, []);
  const reset = useCallback(() => {
    setCount(0);
  }, []);

  return { count, start, stop, reset };
}
```

To **simplify code**, we need to encapsulate all complexity inside useCounter custom hook and expose clean api: `{ count, start, stop, reset }` .

```javascript
export default function Level12() {
  console.log('renderLevel12');
  const { count, start, stop, reset } = useCounter(0, 500);
  return (
    <div>
      count => {count}
      <button onClick={start}>start</button>
      <button onClick={stop}>stop</button>
      <button onClick={reset}>reset</button>
    </div>
  );
}
```

🔗 [Hooks API Reference](https://reactjs.org/docs/hooks-reference.html): [Using a Custom Hook](https://reactjs.org/docs/hooks-custom.html#using-a-custom-hook)

---

### React Hooks Radar

![](https://cdn-images-1.medium.com/max/1600/0*Px-sg5tvCOOlPcJb.jpeg)

All React Hooks are equal, but some hooks are **more equal** than others.

#### ✅ Green

Green hooks are main building blocks of modern React applications. They are safe to use almost everywhere without much thinking.

1.  [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer)
2.  [useState](https://reactjs.org/docs/hooks-reference.html#usestate)
3.  [useContext](https://reactjs.org/docs/hooks-reference.html#usecontext)

#### 🌕 Yellow

Yellow hooks provide useful performance optimizations by using memoization. Managing lifecycle and inputs should be done with caution.

1.  [useCallback](https://reactjs.org/docs/hooks-reference.html#usecallback)
2.  [useMemo](https://reactjs.org/docs/hooks-reference.html#usememo)

#### 🔴 Red

Red hooks interact with mutable world using side effects. They are most powerful and should be used with extreme caution. Customs hooks are recommended for all non-trivial use-cases.

1.  [useRef](https://reactjs.org/docs/hooks-reference.html#useref)
2.  [useEffect](https://reactjs.org/docs/hooks-reference.html#useeffect)
3.  [useLayoutEffect](https://reactjs.org/docs/hooks-reference.html#uselayouteffect)

---

### React Hooks Checklist

![](https://cdn-images-1.medium.com/max/1600/0*yDzaJvKh8gKFHiGH.jpg)

1.  Obey [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html).
2.  Don’t do any side-effects in main render function.
3.  Unsubscribe/dispose/destroy all used resources.
4.  Prefer useReducer or functional updates for useState to prevent reading and writing same value in a hook.
5.  Don’t use mutable variables inside render function, use useRef instead.
6.  If what you save in useRef has smaller lifecycle than the component itself, don’t forget to unset the value when disposing the resource.
7.  Be cautions with infinite recursion and resource starvation.
8.  Memoize functions and objects when needed to improve performance.
9.  Correctly capture input dependencies (undefined => every render, [a, b] => when a or b change, [] => only once).
10. Use customs hooks for non-trivial use-cases.

### GitHub Repo

[**sdolidze/react-hooks-interval**](https://github.com/sdolidze/react-hooks-interval)
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-chi-tiet-ve-react-hooks</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-chi-tiet-ve-react-hooks</guid>
            <pubDate>Wed, 01 May 2019 14:35:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Mẫu thiết kế React nâng cao P3: Render Props]]></title>
            <description><![CDATA[
In this Part, we will discuss a design pattern that can address all of the problems that we have identified up to this point. It is called: render props.

This design pattern can be a bit of a head scratcher at first (remember the function we had to place inside the context consumer in Part 2?) and in order to truly grasp how it exactly works, we need a in-depth understanding of the top level React API and how the JSX code we write is converted to javascript. So let’s use a very simple example and walk through what is going on under the hood.

### JSX

JSX is a syntax extension to JavaScript designed by Facebook’s engineers. We use it with React to describe what the UI should look like (a bit like a template language), but it comes with the full power of JavaScript. Whenever you write any components in JSX, Babel compiles it down to a React.createElement() call.

![](https://cdn-images-1.medium.com/max/1600/1*o0vuU7Dzb5aaz7m3p9-Y5A.png)

Let’s look at a very simple example:

![](https://cdn-images-1.medium.com/max/1600/1*1KwKntECiGRJU5sxnL7LYA.png)

The two examples above yield identical results, the parent component is simply converted to a React.createElement() call, the type is our ‘Parent’ component, there are no props and there are no children.

![](https://cdn-images-1.medium.com/max/1600/1*MZqaPGcEykaEhvp8X1TrlA.png)

When we add a child component, notice how it is itself converted to a React.createElement() call and it is this format that creates our React component tree.

![](https://cdn-images-1.medium.com/max/1600/1*ZuKIoHa_UECNwLVdSVgYMA.png)

The key thing to understand here is that Babel compiles down any props added as a single props javascript object; because it is pure javascript we can pass anything we want, such as functions.

![](https://cdn-images-1.medium.com/max/1600/1*pxbMxCmpRYI-pN0Xul3JjQ.png)

In the above example, instead of passing down the ‘string’, we’ve passed down a function that returns the ‘string’. So, when that function is called we can get the exact same result.

![](https://cdn-images-1.medium.com/max/1600/1*PQgX1RJVXBUHWPYqbAMAXg.png)

So what exactly is going on in the above examples? In the initial example, we just pass down the string, place it in a ‘div’ and it is rendered. In the next example however, we are passing it as a function and placing it in a ‘div’ but this time calling the function allowing us to achieve the exact same result.

### Render Props

Why is this important? Well, traditionally we have **rendered the children components** that we place inside of our parent component.

![](https://cdn-images-1.medium.com/max/1600/1*W4X307RXCRX-M92h2XFeyA.png)

This is the key thing to understand, instead of designing our components to render a child, there is nothing stopping us from **rendering the props** instead while achieving the exact same result:

![](https://cdn-images-1.medium.com/max/1600/1*mugiWhmq3woQb4oYMp509A.png)

So, in this design pattern we **render props** not the children. We can take this a step further too. What else can we do with functions? We can pass arguments when we call them:

![](https://cdn-images-1.medium.com/max/1600/1*yhv4JdMJMlGdenfchcYe2A.png)

Let’s take a moment to digest what’s just happened here. We’ve passed in a function like before but instead of always returning ‘string’ it returns the argument we pass in when it is called!

Wait a second, wasn’t this a problem we encountered in Part 1? To resolve it we had to clone the element, loop through each one and then pass down any desired props.

Using this design pattern we are able to pass props down to child components, Boom!

We can name the props anything we want. So instead of using ‘example’, let’s use something more appropriate:

![](https://cdn-images-1.medium.com/max/1600/1*Dm4kxErU2ytof6UYUMIL7A.png)

If you have used react router before, this may look very familiar. When you need to pass down props to a route you need to use a render function.

![](https://cdn-images-1.medium.com/max/1600/1*He7Q_dBroJoyZJykddFUIw.png)

This is **render props.** Instead of rendering the component directly, we are able to call `render` and pass in any arguments we want.

Let’s swing back to our Stepper component and see how we can utilize this design pattern (I’ve removed all the context boilerplate and added state back to the stepper component).

![](https://cdn-images-1.medium.com/max/1600/1*l2Aca-G6z5SVExCUc5ThRA.png)

This time instead of adding `{this.props.children}` we instead add `{this.props.render(stage,HandleClick)}`. We no longer need to add any children to the stepper component, all we need to do is return the same markup in the render prop.

![](https://cdn-images-1.medium.com/max/1600/1*4e8wL_DEKLswiKya4st1Rw.png)

What does this achieve? Well, every component in the tree now has access to all the props. It essentially gives us the same exposure to the props as the context API, we don’t have to manually pass the props down to each child and we have the flexibility to move things around. This simple adjustment to component design addresses all of the problems we’ve previously mentioned.

![](https://cdn-images-1.medium.com/max/1600/1*ji5DgEliT0219-opdiE5dw.png)

There is one small tradeoff using this design pattern though. The code is slightly less readable than before. Remember that strange function we saw earlier in this series, we needed to add a function inside the Context.consumer component.

![](https://cdn-images-1.medium.com/max/1600/1*vl1h9TNE5VRFo_q3NrM_zQ.png)

This looks very readable to me; let’s think about what is going on. Instead of adding a render function, we are simply adding the same function as a child instead.

Let’s try doing this with our example component we used earlier:

![](https://cdn-images-1.medium.com/max/1600/1*Qg0GYaUlIrS5Zs6k__DHgw.png)

On the left hand side, we are adding the function to the render prop like before. When this is compiled by Babel, the function is added into the the second argument: the props. On the right hand side, we added it as a child and when that is compiled it is added to the third argument: children.

![](https://cdn-images-1.medium.com/max/1600/1*o0vuU7Dzb5aaz7m3p9-Y5A.png)

How do we access the children when creating our components?

**_props.children_**

![](https://cdn-images-1.medium.com/max/1600/1*WWg_57uJXAc5ImvgoY_idw.png)

In a similar fashion to calling the render prop, as the child is a function we can call `props.children` instead and pass in our required arguments, giving us the same outcome as before with an enhanced level of readability.

![](https://cdn-images-1.medium.com/max/1600/1*Wafoqv6u2sdiGmpkOy4FhQ.png)

So there you have it, we have designed a component that is highly flexible and extremely readable. Users can have the autonomy to rearrange the child components without worrying if it will have access to the props they need. Ultimately, it is reusable. We can place this directly in any other application without any prior setup and it will work perfectly.
]]></description>
            <link>https://hungvn.com/blog/mau-thiet-ke-react-nang-cao-p3-render-props</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mau-thiet-ke-react-nang-cao-p3-render-props</guid>
            <pubDate>Thu, 25 Apr 2019 13:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Mẫu thiết kế React nâng cao P2: Context API]]></title>
            <description><![CDATA[
In the last part of the series, we discussed how to use compound components and static class methods to produce reusable and flexible components. Using the API we created, we are able to dynamically recreate different variations of the component in a very declarative fashion.

`codesandbox: lp6mn91557`

We can easily add as many steps as we want and we can decide if we want the progress panel on the left or the right.

```javascript
class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress>
          <Stepper.Stage num={1} />
        </Stepper.Progress>
        <Stepper.Steps>
          <Stepper.Step num={1} text={"Stage 1"} />
        </Stepper.Steps>
      </Stepper>
    );
  }
}
export default App;
```

The reason we are able to this is because we used some React API helper functions to pass the desired props to each child in the tree ; the ‘stage’ and ‘handleClick’ props are accessible to the components that need them.

![](https://cdn-images-1.medium.com/max/1600/1*14Xc1evO1VUe7ZbtaswMWA.png)

There is one major flaw with this technique though. Props are only able to be passed down to their direct children. This makes the API very rigid and the ‘Stepper.Steps’ component has to be a direct child of the ‘Stepper’ component otherwise it will break. This has massive implications in terms of flexibility.

What if we wanted to go a bit crazy and use a bit of flexbox magic to add a title?

```javascript
class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress>
          <Stepper.Stage num={1} />
        </Stepper.Progress>
        <div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
          <Stepper.Header title="Stepper Heading" />
          <Stepper.Steps>
            <Stepper.Step num={1} text={"Stage 1"} />
          </Stepper.Steps>
        </div>
      </Stepper>
    );
  }
}
```

![](https://cdn-images-1.medium.com/max/1600/1*Qd-eBIPrVF9yUx2SlHMb6g.png)

By adding a simple div we completely break the component. The ‘Stepper.Steps’ component is no longer a direct child of the ‘Stepper’ component and is therefore unable to receive its props. Wouldn’t it be great to have the flexibility to add small adjustments when ever we wanted?

Context to the Rescue!!

### React Context API

React Context has been around a while but React’s engineers made it very clear it was experimental and would likely break in the near future. The great news is that as of React 16.3, this is now stable and can be used throughout your React applications.

So what is this Context we keep hearing about?

I couldn’t come up with a clearer definition than the one in React’s official documentation:

> Context provides a way to pass data through the component tree without having to pass props down manually at every level.

This is exactly what we need to solve our problem! Using Context, we no longer need to loop through and clone each child to pass down required props. Context is designed so that we can share ‘global’ state that can be shared anywhere in the React tree.

![Using Context, all of our components have access to the ‘stage’ and ‘handleClick’ props.](https://cdn-images-1.medium.com/max/1600/1*ceym3XmxMn8phkR5yk5HCg.png)

So, let me guide you through the Context API, and the steps you need to take to get it up and running.

### 1: Create a new context

React now comes with a method called ‘createContext’. All we need to do is simply call this method and assign it to a variable.

```javascript
export const StepperContext = React.createContext();
```

The new context we created provides us access to a Provider and Consumer pair. The Provider, believe it or not, provides the ability for us to share state changes throughout our React Tree. The Consumer allows us to subscribe to these state changes anywhere in the tree.

### 2\. Create Context Provider

Our Context we just created has a Static Class method called ‘Provider’ that creates a React component. This component accepts a value property. This is extremely important as it is this property that will represent our global state that we need to pass to components further down in the tree. In our case all we want to share globally is the ‘stage’ prop and ‘handleClick’ method.

By using the props.children technique that we used in the first part of this series, we can dynamically expose any child components to the Provider, regardless of how deep it is in the tree.

```javascript
class StepperProvider extends Component {
  state = {
    stage: 1,
  };
  render() {
    return (
      <StepperContext.Provider
        value={{
          stage: this.state.stage,
          handleClick: () =>
            this.setState({
              stage: this.state.stage + 1,
            }),
        }}
      >
        {this.props.children}
      </StepperContext.Provider>
    );
  }
}
```

### 3\. Wrap our Provider around our Stepper Component

By simply wrapping the ‘StepperProvider’ component around our original ‘Stepper’ component, any child components further down the tree now have exposure to our context.

```javascript
class App extends Component {
  render() {
    return (
      <StepperProvider>
        <Stepper stage={1}>
          <Stepper.Progress>
            <Stepper.Stage num={1} />
          </Stepper.Progress>
          <Stepper.Steps>
            <Stepper.Step num={1} text={"Stage 1"} />
          </Stepper.Steps>
        </Stepper>
      </StepperProvider>
    );
  }
}
```

As it stands our Stepper code looks almost identical, however by simply wrapping it in the StepperProvider component all of our child Components will have access to ‘stage’ and ‘handleClick’ without manually drilling them down to each component.

### 4\. Refactor our components

Originally, our state was managed by the Stepper component and we cloned each child element to be able to receive the props required.

```javascript
class Stepper extends Component {
  state = {
    stage: this.props.stage,
  };
  static defaultProps = {
    stage: 1,
  };
  static Progress = Progress;
  static Steps = Steps;
  static Stage = Stage;
  static Step = Step;
  handleClick = () => {
    this.setState({ stage: this.state.stage + 1 });
  };
  render() {
    const { stage } = this.state;
    const children = React.Children.map(this.props.children, child => {
      return React.cloneElement(child, {
        stage,
        handleClick: this.handleClick,
      });
    });
    return <div style={styles.container}>{children}</div>;
  }
}
```

Almost all of this code is no longer required. We no longer need to create state, and we no longer need to pass down any props. We could do away with this code altogether but it’s a good place to declare our static methods to create a clean, readable API.

```javascript
class Stepper extends Component {
  static Progress = Progress;
  static Steps = Steps;
  static Stage = Stage;
  static Step = Step;
  render() {
    return <div style={styles.container}>{children}</div>;
  }
}

export default Stepper;
```

### 5\. Subscribe to state changes using a Consumer

I will use the the Stepper.Step component to demonstrate how to wire up the Consumer component. Previously, the Stepper.Step component required its parent to directly pass down the stage prop in order for it to function properly:

```javascript
export const Step = ({num, text,stage}) => (
	return stage === num ? <div key={num} style={styles.stageContent}>{text}</div> : null
)
```

With our application wired up with Context we no longer need this as a prop. We can use the Consumer to subscribe to it instead:

```javascript
<Consumer>  {value => /* render something based on the context value */}</Consumer>
```

The Consumer requires a function as a child and provides this function with our global context value. When the function is complete, it returns a react node.

What on earth does that mean?

It’s a bit of a head scratcher at first but lets take a look at the ‘consumed’ Step component.

```javascript
export const Step = ({ num, text }) => (
  <StepperContext.Consumer>
    {value => {
      const { stage } = value;
      return stage === num ? (
        <div key={num} style={styles.stageContent}>
          {text}
        </div>
      ) : null;
    }}
  </StepperContext.Consumer>
);
```

Instead of adding the ‘Step’ markup directly as a child to the Consumer, we instead add a function. This function provides the values we created from our Provider earlier and we can then use ES6 destructuring to pull off the stage prop. The ‘Step’ component now has access to the stage prop like before but this time it is pulled from the context. from here we are free to do with it as we wish; in this case we use it to determine what React node is returned.

The technique being used here may seem a little strange. It is called _render props_ and the [official react docs explain it here](https://reactjs.org/docs/render-props.html). This is an extremely powerful technique that I’ll be talking about in part 3 of this series.

### 6\. Repeat Stages 4 & 5 for all components that either require props or pass down props

I wont go into step by step detail here but by repeating stages 4 & 5 for the Stepper.Steps, Stepper.Progress and Stepper.Stage components you should end up with your component looking and functioning exactly the same as before.

`codesandbox: yjm2563jz9`

None of our components are now reliant on being direct descendants of others. Boom! We now have much more flexible code and should be able to add the heading we were unable to do earlier!

```javascript
class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress>
          <Stepper.Stage num={1} />
        </Stepper.Progress>
        <div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
          <Stepper.Header title="Stepper Heading" />
          <Stepper.Steps>
            <Stepper.Step num={1} text={"Stage 1"} />
          </Stepper.Steps>
        </div>
      </Stepper>
    );
  }
}
```

The Stepper.Steps and Stepper.Step are no longer pulling the ‘stage’ prop directly from their parents. They are subscribing to it from context so the extra div in place is not blocking props being passed further down the tree. The App still works!

![](https://cdn-images-1.medium.com/max/1600/1*ceym3XmxMn8phkR5yk5HCg.png)

This now gives us a huge amount of flexibility. We can reuse our component to dynamically create complex variations of our Stepper component without worrying if our Application will break

`codesandbox: lp6mn91557`

Although we can use this component anywhere in our application, it’s still not truly reusable.We still need the boilerplate of context in order for it to work.

In the next part of this series I will discuss how we can use render props to achieve the same goals without having to rely on wiring up context to share state between components in our application.
]]></description>
            <link>https://hungvn.com/blog/mau-thiet-ke-react-nang-cao-p2-context-api</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mau-thiet-ke-react-nang-cao-p2-context-api</guid>
            <pubDate>Wed, 24 Apr 2019 10:15:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Mẫu thiết kế React nâng cao P1: Compound Components]]></title>
            <description><![CDATA[
To celebrate the official release of React 16.3, I have decided to share some techniques I have been using recently which have completely changed my approach to creating React components. Using these techniques I am able to design components that are completely reusable, and have the flexibility to use these components in a number of different contexts.

`codesandbox: 5x22900pnl`

The sandbox above represents the initial code of a neat and tidy stepper component I will use to showcase some of these techniques. As it stands, this component is working completely fine, and does exactly what it was designed to do, however, there is no flexibility.

```javascript
import React, { Component } from "react";

import Stepper from "./Stepper";

class App extends Component {
  render() {
    return <Stepper stage={1} />;
  }
}

export default App;
```

As you can see, the ‘Stepper’ component’s flexibility ends at the stage prop; we are only able to change the stage to where it starts.

What if I need to position the progress block on the right hand side?

What if I need a similar Stepper with extra stages?

What if I need to change the content of the stages?

What if I wanted to change the order of the stages?

As it stands, the only way I could I achieve these changes is by completely re-writing the component. Re-writing it in the same fashion would yield a similar outcome. However, if more changes are needed again in the future, the component would need to be re-written again. So, let’s try a different approach and rewire the component so it has flexibility and reusability to be used in any future configurations.

In the first part of this series we will discuss a design pattern called “Compound Components”

### Using the Compound Component design pattern

To start, let’s take a look at the ‘Stepper’ component.

```javascript
class Stepper extends Component {
  state = {
    stage: this.props.stage,
  };
  static defaultProps = {
    stage: 1,
  };
  handleClick = () => {
    this.setState({ stage: this.state.stage + 1 });
  };
  render() {
    const { stage } = this.state;
    return (
      <div style={styles.container}>
        <Progress stage={stage} />
        <Steps handleClick={this.handleClick} stage={stage} />
      </div>
    );
  }
}

export default Stepper;
```

The ‘Stepper’ component is basically a component that contains a state object which stores the current stage, a method that increases value of the stage property, and a render method that returns a div with 2 child components.

Currently, we are explicitly placing the ‘Progress’ and ‘Steps’ components directly inside the ‘Stepper’ component. To alleviate this static approach we can use the props object to dynamically inject the child components.

![](https://cdn-images-1.medium.com/max/1600/1*m9qWcyCa_j9DRnITVN5Uwg.png)

Using this alternative approach, we can instead use the props.children object inside the Stepper.js file and place the ‘Progress’ and ‘Steps’ components inside the ‘Stepper’ component.

Just this simple change gives us instant benefits. We can now choose which component in the tree is rendered first; we can choose if the progress block is on the left or the right hand side.

There is one major problem with this approach, however. The ‘Progress’ and ‘Steps’ components no longer have access to the ‘stage’ and ‘handleClick’ props. In order for each child component to receive the props they need, we need to manually loop through the each child and inject the props inside them. We can do that using a number of helper methods provided by the react API. Two options include:- Children.map() and cloneElement().

```javascript
const children = React.Children.map(this.props.children, child => {
  return React.cloneElement(child, { stage, handleClick: this.handleClick });
});
```

The Children.map() is similar to the Array.map() method. It is needed because the children.props has an opaque data structure making the Array.map() method unsuitable for this use case.

The cloneElement does as the name suggests and clones the child component passed into it. Crucially, it also comes with the added ability of injecting extra props. Boom!

```javascript
// Render method of Stepper.js
const { stage } = this.state;
const children = React.Children.map(this.props.children, child => {
  return React.cloneElement(child, { stage, handleClick: this.handleClick });
});
return <div style={styles.container}>{children}</div>;
```

Now we can add the ‘Progress’ and ‘Stage’ as children to the ‘Stepper’ component and everything works the same as before. This time we can decide the position of each component, or if we want to be really crazy, we could have a progress block on both sides.

```javascript
import React, { Component } from "react";

import Stepper from "./Stepper";
import Progress from "./components/Progress";
import Steps from "./components/Steps";

class App extends Component {
  render() {
    return (
      <div>
        <Stepper stage={1}>
          <Progress />
          <Steps />
        </Stepper>
      </div>
    );
  }
}
export default App;
```

### Static Properties

Another cool technique to improve readability and ease of use is using static properties of classes. This allows us to call methods directly on the class.

What on earth does this mean? Lets take a look….

First, we need to create static methods inside the Stepper component and assign them to the ‘Progress’ and ‘Steps’ components:

```javascript
static Progress = Progress
static Steps = Steps
```

So now, instead of us importing the Progress and Steps components in numerous places we can instead call them directly from the Stepper component:

```javascript
import React, { Component } from "react";

import Stepper from "./Stepper";

class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress />
        <Stepper.Steps />
      </Stepper>
    );
  }
}
export default App;
```

We have started to generate a simple, readable API that is somewhat flexible. Why not use some of the same techniques for the ‘Progress’ component? Lets take a look at it…

```javascript
export default class Progress extends Component {
  render() {
    const { stage } = this.props;
    return (
      <div style={styles.progressContainer}>
        <Stage stage={stage} num={1} />
        <Stage stage={stage} num={2} />
        <Stage stage={stage} num={3} />
        <Stage stage={stage} num={4} />
      </div>
    );
  }
}
```

You may notice that its rigidity is very similar to the Stepper component we looked at before. Let’s replace the 4 Stage components with the more dynamic children.props object, loop through the children adding the required props and then add a static method so it can called directly from the Stepper class.

```javascript
export default class Progress extends Component {
  render() {
    const { stage } = this.props;
    const children = React.Children.map(this.props.children, child => {
      return React.cloneElement(child, { stage });
    });
    return <div style={styles.progressContainer}>{children}</div>;
  }
}
```

Once that is done we can dynamically add as many Stage components as we want in whatever position we want:

```javascript
import React, { Component } from "react";

import Stepper from "./Stepper";

class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress>
          <Stepper.Stage num={1} />
          <Stepper.Stage num={2} />
          <Stepper.Stage num={3} />
          <Stepper.Stage num={4} />
        </Stepper.Progress>
        <Stepper.Steps />
      </Stepper>
    );
  }
}
export default App;
```

We can do the same thing with the Steps component although this one is a little trickier as each child needs to be wrapped in a [React’s Transition Group](https://reactcommunity.org/react-transition-group/) Transition component. The same loop technique will need to be applied, but the component will only be visible if the stage prop matches the component’s num prop. If there is a match, its wrapped in a Transition component (the ReactTransitionGroup docs explain the purpose of this) and is rendered on screen.

```javascript
class Steps extends Component {
  render() {
    const { stage, handleClick } = this.props;
    const children = React.Children.map(this.props.children, child => {
      console.log(child.props);
      return (
        stage === child.props.num && (
          <Transition appear={true} timeout={300} onEntering={entering} onExiting={exiting}>
            {child}
          </Transition>
        )
      );
    });
    return (
      <div style={styles.stagesContainer}>
        <div style={styles.stages}>
          <TransitionGroup>{children}</TransitionGroup>
        </div>
        <div style={styles.stageButton}>
          <Button disabled={stage === 4} click={handleClick}>
            Continue
          </Button>
        </div>
      </div>
    );
  }
}

export default Steps;
```

By adding the relevant static methods on the Stepper.js component we can add as many Step components as we want, in what ever order we want.

```javascript
import React, { Component } from "react";

import Stepper from "./Stepper";

class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress>
          <Stepper.Stage num={1} />
          <Stepper.Stage num={2} />
          <Stepper.Stage num={3} />
        </Stepper.Progress>
        <Stepper.Steps>
          <Stepper.Step num={1} text={"Stage 1"} />
          <Stepper.Step num={2} text={"Stage 2"} />
          <Stepper.Step num={3} text={"Stage 3"} />
          <Stepper.Step num={4} text={"Stage 4"} />
        </Stepper.Steps>
      </Stepper>
    );
  }
}
export default App;
```

We have created a way more flexible and reusable component. We can now choose how many stages, what text will go in each stage, the order of each stage, and whether we would like the progress bar on the left or the right.

`codesandbox: 5x22900pnl`

We are still constrained in terms of flexibility though! What if we wanted to add a title block just above the Steps block?

```javascript
class App extends Component {
  render() {
    return (
      <Stepper stage={1}>
        <Stepper.Progress>
          <Stepper.Stage num={1} />
          <Stepper.Stage num={2} />
          <Stepper.Stage num={3} />
        </Stepper.Progress>
        <div>
          <div>Title</div>
          <Stepper.Steps>
            <Stepper.Step num={1} text={"Stage 1"} />
            <Stepper.Step num={2} text={"Stage 2"} />
            <Stepper.Step num={3} text={"Stage 3"} />
            <Stepper.Step num={4} text={"Complete!"} />
          </Stepper.Steps>
        </div>
      </Stepper>
    );
  }
}
export default App;
```

This would break our application as the ‘Stepper.Steps’ component is no longer a direct child of the ‘Stepper’ component and does not have access to the stage prop.

This is why the release of React 16.3 is quite a big deal! Up until now, React’s context API was in an experimental phase but now it’s been made official!

In Part 2 of this series I will discuss how we can implement the context API to be able to pass down props anywhere in the tree, so regardless of where the ‘Stepper.Steps’ component is positioned it will always be able to access the stage prop.
]]></description>
            <link>https://hungvn.com/blog/mau-thiet-ke-react-nang-cao-p1-compound-components</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mau-thiet-ke-react-nang-cao-p1-compound-components</guid>
            <pubDate>Sat, 20 Apr 2019 12:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Các mẫu thiết kế trong phát triển JavaScript hiện đại]]></title>
            <description><![CDATA[
### Mẫu là gì? Thiết kế là gì? Chúng ta vẫn đang nói về phát triển phần mềm phải không?

**Chắc chắn là vậy.**

As is the case with object-oriented programming, we, the developers, are trying to model the world surrounding us. As such, it makes sense to also try and use the world surrounding us as a tool to describe our craft.

In this case, we take a page from architecture (the one with buildings and bridges) and the seminal architecture book called **A Pattern Language: Towns, Buildings, Construction**by*Christopher Alexander, Sara Ishikawa, Murray Silverstein* where patterns are described as follows:

> Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.

In software development, architecture is the process of constructing an application in a healthy, robust and maintainable way and patterns provide a way of giving names to solutions for common problems. These solutions can range from abstract/conceptual to very precise and technical and allow developers to effectively communicate with each other.

![Efficient.](https://cdn-images-1.medium.com/max/2400/1*pdCoxUhmMHI5tBnGVdnNJQ.jpeg)

If two or more developers on a team are knowledgeable about patterns, talking about solutions to problems becomes very efficient. If only one developer knows about patterns, explaining them to the rest of the team is usually easy.

**The goal of this article is to whet your appetite for a somewhat formal representation of knowledge in software development by introducing you to the idea of software design patterns and presenting a couple of patterns which are interesting because they get used considerably in modern JavaScript projects.**

### Singleton pattern

#### The what

The singleton pattern isn’t one of the most widely used ones, but we’re starting here because it’s relatively easy to grasp.

The singleton pattern stems from the mathematical concept of a singleton which is:

> In mathematics, a **singleton**, also known as a **unit set**, is a set with exactly one element. For example, the set {null} is a singleton.

In software, it simply means that we limit the instantiation of a class to a single object. The first time an object of a class implementing the singleton pattern should be instantiated, it is actually going to get instantiated. Any subsequent try is just going to return that first instance.

![Who needs two superheroes when there is Batman?](https://cdn-images-1.medium.com/max/2400/1*JsnR25Uewd4wZLzZ-a9frg.png)

#### The why

Apart from allowing us to only have one superhero ever (which would obviously be Batman), why would we ever use the singleton pattern?

Although the singleton pattern isn’t without its problems (it’s been called evil before with singletons being [called pathological liars](http://misko.hevery.com/2008/08/17/singletons-are-pathological-liars/)), it still has its uses. The most notable one would be for instantiating configuration objects. You probably only want one configuration instance for your application, unless a feature of your application is providing multiple configurations.

#### The where

Angular’s services are a prime example of the singleton pattern being used in a big popular framework. There is a [dedicated page in Angular’s documentation](https://angular.io/guide/singleton-services) explaining how to make sure that a service is always provided as a singleton.

Services being singletons makes a lot of sense, since services are used as a place to store state, configuration and allow communication between components and you want to make sure that there aren’t multiple instances messing up these concepts.

As an example, let’s say that you have a trivial application which is used for counting how many times buttons have been clicked.

![](https://cdn-images-1.medium.com/max/2400/1*PZpt4afyPY10CnuRADJx5w.png)

You should keep track of the number of button presses in one object which provides:

- the functionality of counting
- and providing the current number of clicks.

If that object wasn’t a singleton (and the buttons would each get their own instance) the click count wouldn’t be correct. Also, which of the counting instances would you provide to the component showing the current count?

### Observer pattern

#### The what

The observer pattern is defined as follows:

> The **observer pattern** is a software design pattern in which an object, called the **subject**, maintains a list of its dependents, called **observers**, and notifies them automatically of any state changes, usually by calling one of their methods.

It’s really easy to understand the observer pattern if we try comparing it to an example in the real world — newspaper subscriptions.

The usual scenario when buying a newspaper is that you walk to the newsstand and ask if the new issue of your favourite newspaper is out. If it isn’t, it’s a sad affair of inefficiency where you have to walk home and try again later. In JavaScript terms, this would be the same as looping until you get the desired result.
When you finally get your hands on the newspaper, you can do what you meant to do the whole time — sit down with a cup of coffee and enjoy your newspaper (or, in JavaScript terms, execute the callback function that you wanted to do the whole time).

![Finally.](https://cdn-images-1.medium.com/max/2400/1*arrsn5kxG1GRbVpn7tlZkw.jpeg)

The smart thing to do (and get your beloved newspaper each day) would be to subscribe to the newspaper.
That way, the publishing company would let you know when a new issue of the newspaper is out and deliver it to you. No more running to the newsstand. No more disappointment. Bliss.
In JavaScript terms, you wouldn’t be looping and asking for the result until you run a function any more. You would, instead, let a subject know that you are interested in events (messages) and would provide a callback function which should be called when new data is ready. You are, then, the observer.

![Never miss your morning paper again.](https://cdn-images-1.medium.com/max/2400/1*Umz-GYQk5skILT07e0Kr4A.png)

The nice thing is — you don’t have to be the only subscriber. As you would be disappointed by missing your newspaper, so would other people, too. That’s why multiple observers can subscribe to the subject.

#### The why

The observer pattern has many use cases but generally, it should be used when you want to create a one-to-many dependency between objects which isn’t tightly coupled and have the possibility to let an open-ended number of objects know when a state has changed.

JavaScript is a great place for the observable pattern because everything is event-driven and, rather than always asking if an event happened, you should let the event inform you (like the old adage _“Don’t call us we’ll call you”_). Chances are you already did something which looks like the observer pattern — addEventListener. Adding an event listener to an element has all the markings of the observer pattern:

- you can subscribe to the object,
- you can unsubscribe from the object,
- and the object can broadcast an event to all its subscribers.

The big payoff from learning about the observer pattern is that you can implement your own subject or grasp an already existing solution much faster.

#### The where

Implementing a basic observable shouldn’t be too hard, but there is a great library being used by many projects and that’s [ReactiveX](http://reactivex.io/) of which [RxJS](https://github.com/ReactiveX/rxjs) is its JavaScript counterpart.

RxJS allows you not only to subscribe to subjects, but also gives you the possibility of transforming the data in any way you can imagine, combining multiple subscriptions, making asynchronous work more manageable and much much more. If you ever wanted to bring your data processing and transformation level to a higher level, RxJS would be a great library to learn.

Apart from the observer pattern, ReactiveX also prides itself with implementing the iterator pattern which gives subjects the possibility of letting its subscribers know when a subscription ended, effectively ending the subscription from the subject’s side. I am not going to be explaining the iterator pattern in this article, but it would be a great exercise for you to learn more about it and see how it fits in with the observable pattern.

### Facade pattern

#### The what

The facade pattern is a pattern which takes its name from architecture. In architecture:

> A **facade** is generally one exterior side of a building, usually the front. It is a foreign loan word from the French _façade_, which means “frontage” or “face”.

As the facade in architecture is an exterior of the building, hiding its inner workings, the facade pattern in software development tries to hide the underlying complexity behind a front, effectively allowing you to work with an API which is easier to grasp while providing the possibility to change the underlying code however you want.

#### The why

You can use the facade pattern in a myriad of situations but the most notable ones would be to make your code easier to understand (hide complexity) and to make dependencies as loosely coupled as possible.

![Fus Ro Dah!](https://cdn-images-1.medium.com/max/2400/1*Unh3rSLKfaMzs3gweZF7UQ.png)

It is easy to see why a facade object (or layer with multiple objects) would be a great thing. You don’t want to be dealing with dragons if it can be avoided. The facade object is going to provide you a nice API and deal with all the dragon shenanigans itself.

Another great thing that we can do here is change out the dragon from the background without ever touching the rest of the application. Let’s say that you want to change that dragon out with a kitten. It still has claws, but is much easier kept fed. Changing it out is a matter of rewriting the code in the facade without changing any of the dependent objects.

#### The where

A place where you will see facades often is Angular using its services as a means of simplifying background logic. But it doesn’t have to only be Angular, as you will see in the next example.

Let’s say that you want to add state management to your application. You could take Redux, NgRx, Akita, MobX, Apollo or any of the new kids on the block that have been popping up left and right. Well, why not choose them all and take them for a spin?

What are the basic functionalities a state management library is going to provide you?

Probably:

- a way of letting the state management know that you want a state change
- and a way of getting the current (slice of) state.

That doesn’t sound too bad.

Now, with the power of the facade pattern under your belt, you can write facades for each part of the state which are going to provide a nice API for you to work with — something like facade.startSpinner(), facade.stopSpinner() and facade.getSpinnerState(). These methods are really easy to understand and reason about.

After that, you can tackle the facade and write the code which is going to transform your code so that it works with Apollo (managing state with GraphQL — so hot right now). You may notice that it doesn’t suit your coding style at all or that the way unit tests have to be written really isn’t your cup of tea. No problem, write a new facade which is going to support MobX.

![Might as well be dragons…](https://cdn-images-1.medium.com/max/2400/1*O3pSZ9xOfBkk7lO0CtGCPA.png)

### Where to go from here

You’ve probably noticed that there was no code or implementation of the design patterns I’ve talked about. That’s because each of these design patterns could be at least a chapter in a book for itself.

Now that we’re talking about books, it wouldn’t hurt to take a look at one or two dealing with design patterns in depth.

The first and biggest recommendation has to be [**Design Patterns: Elements of Reusable Object-Oriented Software**](http://wiki.c2.com/?DesignPatternsBook)by _Erich Gamma_, _Richard Helm_, _Ralph Johnson_, and _John Vlisside_ also known as the _Gang of Four_. The book is a gold mine and the _de facto_ bible of software design patterns.

If you are looking for something that’s a bit easier to digest, there is [**Head First Design Patterns**](https://www.goodreads.com/book/show/58128.Head_First_Design_Patterns) by _Bert Bates_, _Kathy Sierra_, _Eric Freeman_ and _Elisabeth Robson_. It’s a very nice book which tries to convey the message of design patterns through a visual perspective.

**Last but not least, nothing beats just Googling, reading and trying out different approaches. Even if you end up never using a pattern or technique, you’ll learn something and grow in ways you never expected.**
]]></description>
            <link>https://hungvn.com/blog/cac-mau-thiet-ke-trong-phat-trien-javascript-hien-dai</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cac-mau-thiet-ke-trong-phat-trien-javascript-hien-dai</guid>
            <pubDate>Fri, 12 Apr 2019 20:35:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Băm và lưu password đúng cách]]></title>
            <description><![CDATA[
Sau khi đọc bài viết [băm mật khẩu đúng cách](https://vnhacker.blogspot.com/2018/05/bam-mat-khau-ung-cach.html) của anh thaidn, mình nhớ lại lúc mình mới ra trường, cũng đã từng nghĩ về vấn đề này (lúc đó mình khá thích môn Bảo Mật Thông Tin ở trường) nhưng chưa bao giờ hiểu tường tận. Chỉ biết là không nên:

- Lưu password ở dạng plain-text.
- Hash với một thuật toán hash mạnh, không nên xài MD5, SHA-1 …
- Hash với salt.

Chỉ hiểu rằng phải nên làm thế, nhưng không hiểu tại sao lại như vậy và một số câu hỏi khác cũng chưa trả lời được như:

- Password user gửi lên, nên hash ở client hay ở server.
- Salt nên lưu ở đâu.
- Salt có cần giữ bí mật hay không?
- Salt chung cho tất cả, hay salt riêng cho từng user?

Hôm nay, mình quyết định đi tìm câu trả lời cho những vấn đề mình thắc mắc, thay vì mặc định nó đúng.

## 1\. Tại sao không nên lưu plain-text, encrypt hoặc dùng MD5, SHA-1

Nếu lưu plain-text, database bị hack, SQL-injection, password user chìa ra theo một cách không thể dễ dàng hơn để đánh cắp.

Nếu mã hóa 2 chiều, sẽ luôn có một cách để giải mã bằng một chìa-khóa nào đó, sẽ phải tìm cách lưu chìa-khóa một cách an toàn.

MD5 và SHA-1 được chứng minh có đụng độ, nghĩa là 2 password khác nhau, khi hash bằng MD5 hoặc SHA-1 có thể ra cùng một chuỗi.

- [MD5 collision](https://en.wikipedia.org/wiki/MD5#Collision_vulnerabilities)
- [SHA1 collision](https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html)

## 2\. Tại sao phải salt

Ta đã biết, hash algorithm là one-way-function, tức là không thể suy ngược trực tiếp ra password nếu có hash_value (khác với mã hóa, có thể giải mã thông qua chìa-khóa).

Tuy nhiên vẫn có cách để từ hash_value có thể suy gián tiếp ra được password ví dụ brute-force attach, dictionary attach -> điểm chung là ta cần **thử** và **đoán** password nhiều lần cho tới khi đúng cái cần tìm.

Một cách khác đó là ta có thể **tính toán trước** giá trị hash của tất cả các trường hợp và của tất cả các thuật toán -> cách này khó, tốn thời gian, nhưng bây giờ với tốc độ tính toán của máy tính, ta vẫn có thể làm được. Bảng lưu trữ password + hash_value của password gọi là **[Rainbow Table](http://project-rainbowcrack.com/table.htm)**, có thể tự tạo hoặc tải một số bản miễn phí hoặc trả tiền để mua. Từ bây giờ nếu ta có hash_value ta có thể mapping để suy ra được password.

Tuy nhiên nếu ta chỉ hash mỗi password, ta gặp vấn đề đó là:

- **2 password giống nhau** (user vô tình trùng password) thì chuỗi `hash(password)` sẽ giống nhau.
- User cố tình đặt password đơn giản và phổ biến (ví dụ password < 4 kí tự, toàn số, toàn chữ) -> dễ nhớ cho user nhưng dễ tra ngược.

Và nếu chỉ hash password thì nếu mất hash_value, có thể tra trong rainbow table để tìm ra được password của người dùng.

Giờ ta thử thay vì `hash(password)` ta sẽ `hash(salt + password)`:

Từ `md5(123456)`

```
id |          hash_md5                |
---------------------------------------
1  | e10adc3949ba59abbe56e057f20f883e |
```

Thành `md5(7nWZLcCK0vsPzIM + 123456)`

```
id |          hash_md5                |    salt         |
---------------------------------------------------------
1  | 0510210d4b370165658bdc0d0b005244 | 7nWZLcCK0vsPzIM |
```

Giờ giả sử, ta mất bảng dữ liệu gồm `hash_md5, salt`, kẻ tấn công sẽ phải **tính toán lại** rainbow table của tất cả các trường hợp cộng với salt. Nếu salt là random cho từng user, kẻ tấn công sẽ phải tính toán toàn bộ trường hợp cộng với riêng từng salt cho toàn bộ user.

Chi phí cho 2 phép tính trên là vô cùng lớn và tốn rất nhiều thời gian để thực hiện. Vậy tóm lại mục đích của salt và random-salt là:

- Bảo vệ user kể cả khi user dùng password phổ biến và password không mạnh vì user không thể nhớ được các password phức tạp nhưng tốc độ tính toán của máy tính thì càng ngày càng nhanh.
- Tạo ra nhiều chi phí tính toán, kẻ tấn công không thể tính toán trước rainbow table.

\=> Ta trả lời đc 3 câu hỏi:

- Salt có thể lưu trong database, cùng với hash_value.
- Không cần tìm cách giữ bí mật salt, nhưng cũng đừng **tự ý công khai** salt.
- Nhưng bắt buộc phải random salt cho từng user.

## 3\. Hash ở đâu?

Giờ giả sử `hash(password)` ở client-side thì vấn đề là gì?

- Biết được thuật toán dùng để hash.
- Salt sẽ phải sinh ra ở client, vì ta cần hash password với salt (`hash(salt + password)`), và db chỉ lưu kết quả hash, không lưu salt.
- Nhưng nếu salt sinh ra ở client và salt random thì làm sao để compare với hash_value trong database? Vì lần chứng thực tới, salt sẽ lại random và sẽ khác với kết quả trong database -> salt phải duy nhất cho tất cả các trường hợp.
- Hoặc salt có thể lưu ở DB, nhưng server phải gửi salt về trước cho user trước khi thực hiện hash -> dễ dàng biết được salt hơn.

Nhìn sơ thì thấy việc dùng duy nhất một salt đã chống lại luận điểm ở mục số 2. Vậy quy trình chứng thực đúng là như thế nào?

- User sẽ gửi plain-text password lên server và over HTTPs.
- Server sẽ kiểm tra trong database lấy ra salt của user đó, cộng chuỗi ta được `salt + password`.
- Thực hiện `hash(salt + password)` trên server side.
- Compare kết quả trên với `hash_md5` trong database.

## 4\. Tại sao dùng bcrypt thay cho SHA-512

Kết quả của SHA-512 có độ dài 128 kí tự, độ dài của key là 64 bytes. Trông có vẻ cũng khá chắc chắn, vậy tại sao OWASP recommend sử dụng PBKDF2, bcrypt hoặc scrypt hơn là SHA2?

SHA2 là hash algorithm (tất nhiên), nó được thiết kế với mục tiêu là tốc độ, với các CPU hiện đại, có thể generate hàng triệu kết quả trên giây. Nếu dùng một thuật toán có tốc độ như SHA2 tức là bạn đã đem lợi điểm tới cho kẻ tấn công brute-force. Thuật toán nhanh + cấu hình server mạnh, việc brute-force càng trở lên nhanh chóng hơn.

Trong khi đó, bcrypt được gọi là slow-hash algorithm, `bcrypt()` mất 100ms để tính toán ra chuỗi hash, chậm hơn 10.000 lần so với sha1().

Có nghĩa là vẫn đạt được mục đích hash nhưng giảm thiểu nguy cơ tấn công brute-force.

**Tóm lại**: SHA-512 không phải là một thuật toán yếu, mà vấn đề là SHA-512 không phù hợp cho việc hash password. Nếu cần hash password thì ta nên dùng các thuật toán slow hash như PBKDF2, bcrypt và scrypt.

## 5\. Tại sao cần Pepper?

Một thực tế là nếu bạn chỉ có “muối” mà không có “tiêu”, ăn thịt gà luộc sẽ không ngon :v. Giả sử, database bạn chạy RAID-1, một ổ cứng hư và cần thay một ổ cứng mới. Nhưng như ta biết, đĩa bị hư là mirror của đĩa còn lại, bạn phải tiêu hủy ổ cứng hư đó nếu không ai đó có thể lục thùng rác và tái tạo lại một phần dữ liệu trong đĩa hư đó.

Xin lưu ý, bạn cần `wipe` trước khi vứt bỏ một ổ cứng có dữ liệu dù cá nhân hay server, tuy nhiên đĩa bị sốc điện, bad-sector thì `wipe` cũng chưa đủ an toàn, tốt nhất nên ngiền ra bã.

Dù random-salt đã làm tăng chi phí tạo ra rainbow table nhưng đời không biết đâu mà lần, kẻ tấn công luôn có những động lực không tưởng để đạt được cái mình muốn. Giả sử kẻ tấn công có một siêu siêu máy tính và một mirror ổ cứng hư lục từ một cái thùng rác nào đó. Với siêu máy tính đó, ta có rainbow-table để tra ngược ra password cần tìm.

Vậy làm sao để giảm thiểu nguy cơ trên? Nguyên tắc là không bỏ tất cả trứng trong một giỏ, đó là pepper. Pepper là một chuỗi tương tự như salt, nhưng khác biệt là ta cần **giữ bí mật pepper**, lưu ở một chỗ khác ngoài database, và không cần pepper-per-user, chỉ cần 1 pepper là đủ.

Từ

```
hash(salt + password)
```

Thành

```
hash(pepper + salt + password)
```

Ta nên lưu pepper ở application hoặc ở một service khác, nếu database bị compromise, thì kẻ tấn công cũng không có pepper để tạo ra rainbow-table.

## 6\. Bonus

![dropbox-store-password](https://dropboxtechblog.files.wordpress.com/2016/09/layers.png)

Trong khi tìm câu trả lời để viết bài này, mình tìm được một bài blog của dropbox nói về cách họ lưu password như thế nào. Thấy có 2 điểm khá hay nên muốn nói thêm.

- Trước khi hash password với salt-per-user, họ có `SHA512(password)` trước để **cố định** độ dài của input-password. Theo Dropbox thì việc này giải quyết 2 issues của `bcrypt`
  - Một số implementation của bcrypt cắt đầu vào còn 72 bytes.
  - Một số implementation khác của bcrypt thì không cắt đầu vào nhưng dẫn tới một vấn đề khác là DoS attack bởi vì cho phép độ dài mật khẩu tùy ý.
- Dropbox cũng có **global pepper** nhưng thay vì dùng nó để hash thì họ encrypt. Tức là thay vì `hash(pepper + salt + password)` thì họ `AES256(salt + password) + global-pepper-key`. Theo như họ giải thích thì pepper là một lớp phòng thủ sâu hơn và lưu trữ ở một nơi riêng biệt. Nhưng đồng nghĩa với việc là nơi lưu trữ pepper vẫn có thể bị compromise, và khi bị compromise thì việc rotate key không dễ dàng. Dùng pepper để encrypt vẫn đạt được mục đích bảo mật tương tự nhưng thêm khả năng rotate key khi bị compromise.

## 7\. Migrate

Sau khi viết bài này, bạn [@vanhtuan0409](https://github.com/vanhtuan0409) có một câu hỏi về việc làm thế nào migrate một hệ thống dùng SHA1 –> bcrypt. Mình thấy đây là một điểm cũng khá cần thiết nên xin phép note thêm.

Ở đây có 2 trường hợp:

- Hash password bằng SHA1 nhưng không có salt -> mình gọi là `sha1_value`.
- Hash password bằng SHA1 + trong DB có salt-per-user, mình có `sha1_value, salt`.

Về ý tưởng thì ta sẽ dùng SHA1 như cách Dropbox dùng SHA512 để cố định độ dài input.

Với trường hợp đầu ta cần sinh ra thêm salt-per-user và migrate `bcrypt(salt, sha1_value)` trong đó `sha1_value = SHA1(password)` -> Tương tự cách của dropbox, **may mắn** là do sai thiết kế từ đầu (thiếu salt) nên migrate dễ.

Với trường hợp thứ 2 thì hơi lằng nhằng hơn 1 xíu, ta cần migrate kiểu `bcrypt(salt, SHA1(salt, password))` nếu thực sự muốn bcrypt với salt hoặc thực ra chỉ cần `bcrypt(SHA1(salt, password)` cũng được. Tùy tình huống bạn cần tradeoff có thể lựa chọn cách phù hợp.

## 8\. Thông tin của bạn có an toàn?

Như ta thấy, ta đã làm rất nhiều thứ để đảm bảo rằng thông tin của chúng ta trở lên an toàn. Vậy thực sự thông tin của chúng ta đã an toàn hay không? Câu trả lời rất tiếc là KHÔNG? Thông tin của chúng ta có thể an toàn với “bên ngoài” nhưng không an toàn với “bên trong”. Tại sao lại vậy?

Giờ bắt đầu với thông tin cơ bản nhất như địa chỉ, email, sở thích … Khi ta build staing environment, thông tin user được copy sang một môi trường khác, developer có thể overwrite hash_value của user bằng value của `hash(salt + 654321)` và dễ dàng đăng nhập trên staing environment với password là `654321` và tất cả các thông tin cơ bản của user đã có thể đọc được. Nhưng ít nhất developer vẫn không biết chính xác password của user là gì.

Nhưng, lại là nhưng. Người quản trị hệ thống có mọi quyền trên server mà họ quản trị, password dù đã over HTTPs nhưng tới server vẫn là plain-text. Vẫn có thể capture request ngay ở đầu server và output ra plain-text password của user và cuối cùng thì người quản trị hệ thống vẫn biết được chính xác password của user là gì. Đó là lí do tại sao ta không nên dùng một password cho tất cả các dịch vụ.

Vậy làm thế nào để bảo vệ info của user trong trường hợp này, rất tiếc về mặt kỹ thuật không có cách nào để đảm bảo việc này. Ta chỉ có thể áp dụng policy, NDA về mặt con người để hạn chế vấn đề này thôi.

## 9\. Ref

- [https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords](https://security.stackexchange.com/questions/211/how-to-securely-hash-passwords)
- [https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords](https://blogs.dropbox.com/tech/2016/09/how-dropbox-securely-stores-your-passwords)

**Lưu ý**:

- Trong bài viết dùng MD5 để minh họa cho đơn giản, trong thực tế ta không dùng MD5.
- Trong bài viết giả định kẻ tấn công bằng cách nào đó có db users, trong thực tế việc này rất khó do có các tầng bảo mật khác như thiết kế infrastructure, define rule/policy về con người … Trong bài này mình không bàn đến các vấn đề đó.
]]></description>
            <link>https://hungvn.com/blog/bam-va-luu-password-dung-cach</link>
            <guid isPermaLink="true">https://hungvn.com/blog/bam-va-luu-password-dung-cach</guid>
            <pubDate>Mon, 11 Mar 2019 15:35:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách đặt breakpoints CSS chính xác nhất]]></title>
            <description><![CDATA[
Trong khoảng thời gian tới hoặc lâu hơn, tôi muốn bạn quên đi CSS. Hãy quên đi việc phát triển web. Hãy quên giao diện người dùng.

Và khi bạn quên những điều này, tôi muốn bạn cho phép tâm trí của bạn đi lang thang. Để lang thang ngược thời gian. Trở lại tuổi trẻ của bạn. Trở lại ngày đầu tiên đến trường.

Đó là một thời gian đơn giản hơn, khi tất cả những gì bạn phải lo lắng là vẽ hình và giữ sự không kiểm soát của bạn.

![](https://cdn-images-1.medium.com/max/2600/1*XoDgRc5GXaxo7j47ClsIgw.png)

Hãy nhìn vào các chấm ở trên. Chú ý một số trong số chúng được kết lại với nhau, và một số trong số chúng lan ra? Những gì tôi muốn bạn làm là chia chúng thành năm nhóm cho tôi, mà bạn thấy phù hợp.

Tiếp tục. Sau khi kiểm tra xem không có ai đang xem, hãy vẽ một vòng tròn quanh mỗi năm nhóm bằng ngón tay giống trẻ của bạn.

Bạn có thể đã đưa ra một cái gì đó như dưới đây, phải không? (Và bất cứ điều gì bạn làm, đừng nói với tôi rằng bạn đã cuộn xuống mà không thực hiện bài tập. Tôi sẽ đối mặt với lòng bàn tay.)

![](https://cdn-images-1.medium.com/max/2600/1*cZcTR2tVMzYg1U1h3cqdNg.png)

Chắc chắn, hai dấu chấm bên phải có thể đã đi cả hai chiều. Nếu bạn nhóm chúng lại với nhau thì nó OK, tôi đoán vậy. Họ nói rằng, không có câu trả lời sai, nhưng tôi không bao giờ sai, vì vậy tôi không bao giờ bị kết thúc ở mức độ đặc biệt đó.

Trước khi tôi tiếp tục, bạn thử vẽ một cái gì đó như dưới đây?

![](https://cdn-images-1.medium.com/max/2600/1*RZryP0xAyOy1_WRpBdPIog.png)

Chắc là không. Đúng không?

Nhưng điều đó về cơ bản là những gì bạn đã làm nếu bạn đặt điểm dừng của mình tại các vị trí khớp với chiều rộng chính xác của các thiết bị phổ biến (320px, 768px, 1024px).

![](https://cdn-images-1.medium.com/max/2600/1*pwC0py16i-sQr1agaP26QQ.png)

Có những từ có ý nghĩa dưới đây đã bao giờ bạn nghe hoặc bạn đã nói?

> “Is the medium breakpoint _up to_ 768px, or including 768? I see… and that's iPad landscape, or is that ‘large'? Oh, large is 768px _and up._ I see. And small is 320px? What is this range from 0 to 319px? A breakpoint _for ants_?”

I could proceed to show you the correct breakpoints and leave it at that. But I find it very curious that the above method (“silly grouping”) is so widespread.

Why should that be?

I think the answer to this problem, like so many problems, comes down to misaligned terminology. After all, _waterboarding at Guantanamo Bay_ sounds super rad if you don't know what either of those things are. (Oh [I wish](https://www.reddit.com/r/Showerthoughts/comments/2ucx09/waterboarding_at_guantanamo_bay_sounds_super_rad/) that was my joke.)

I think we mix up “boundaries” and “ranges” in our discussions and implementations of breakpoints.

Tell me, if you do breakpoints in Sass, do you have a variable called `$large` that is, say, 768px?

Is that the lower boundary of the range you refer to as large, or the upper boundary? If it's the lower, then you must have no $small because that should be 0, right?

And if it's the upper boundary then how would you define a breakpoint `$large-and-up`? That must be a media query with a `min-width` of `$medium`, right?

And if you are referring to just a boundary when you say large, then we're in for confusion later on because a media query is always a _range_.

This situation is a mess and we're wasting time thinking about it. So I have three suggestions:

1.  Get your break*points* right
2.  Name your _ranges_ sensibly
3.  Be declarative

### Tip #1: Get your breakpoints right

So what are the _right_ breakpoints?

Your kindergarten self already drew the circles. I'll just turn them into rectangles for you.

![](https://cdn-images-1.medium.com/max/2600/1*-ldpo5wcYVnuyRFbO24WPQ.png)

600px, 900px, 1200px, and 1800px if you plan on giving the giant-monitor people something special. On a side note, if you're ordering a giant monitor online, make sure you specify it's for a computer. You don't want to [get a giant lizard in the mail](http://metro.co.uk/2016/06/16/this-monster-lizard-at-the-door-is-absolutely-terrifying-5947737/).

Those dots your channeled young self has been playing with actually represent the 14 most common screen sizes:

![image credit](https://cdn-images-1.medium.com/max/1600/1*199KbL2oM2P5d4pFMBXYxQ.png)

So we can make a pretty little picture that allows for the easy flow of words between the folks dressed up as business people, designers, developers, and testers.

![I'm regretting my choice of orange and green, but I'm not redoing all of these pictures now.](https://cdn-images-1.medium.com/max/2400/1*7YeOvzoYgUEDJdfQy2ERXg.png)

### Tip #2: Name your ranges sensibly

Sure, you could name your breakpoints [papa-bear and baby-bear](https://css-tricks.com/naming-media-queries/) if you like. But if I'm going to sit down with a designer and discuss how the site should look on different devices, I want it to be over as quickly as possible. If naming a size _portrait tablet_ facilitates that, then I'm sold. Heck, I'd even forgive you for calling it “iPad portrait.”

“But the landscape is changing!” you may shout. “Phones are getting bigger, tablets are getting smaller!”

But your website's CSS has a shelf life of about three years (unless it's Gmail). The iPad has been with us for twice that time, and it has yet to be dethroned. And we know that Apple no longer makes new products, they just remove things from existing ones (buttons, holes, etc).

So 1024 x 768 is here to stay, folks. Let's not bury our heads in the sand. (Fun fact: ostriches don't live in cities because there is no sand, and thus nowhere to hide from predators.)

Conclusion: communication is important. Don't purposefully detach yourself from helpful vocabulary.

### Tip #3: Be declarative

I know, I know, that word “declarative” again. I'll put it another way: your CSS should define _what_ it wants to happen, not _how_ it should happen. The “how” belongs hidden away in some sort of mixin.

As discussed earlier, part of the confusion around breakpoints is that variables that define a _boundary_ of a range are used as the _name_ of the range. $large: 600px simply makes no sense if large is a range. It's the same as saying var coordinates = 4;.

So we can hide those details inside a mixin rather than expose them to be used in the code. Or we can do one better and not use variables at all.

At first I did the below snippet as a simplified example. But really I think it covers all the bases. To see it in action, [check out this pen](http://codepen.io/davidgilbertson/pen/aBpJzO). I'm using Sass because I can't imagine building a site without it. The logic applies to CSS or Less just the same.

```scss
@mixin for-phone-only {
  @media (max-width: 599px) {
    @content;
  }
}
@mixin for-tablet-portrait-up {
  @media (min-width: 600px) {
    @content;
  }
}
@mixin for-tablet-landscape-up {
  @media (min-width: 900px) {
    @content;
  }
}
@mixin for-desktop-up {
  @media (min-width: 1200px) {
    @content;
  }
}
@mixin for-big-desktop-up {
  @media (min-width: 1800px) {
    @content;
  }
}

// usage
.my-box {
  padding: 10px;

  @include for-desktop-up {
    padding: 20px;
  }
}
```

Note that I'm forcing the developer to specify the -up or -only suffix.

> Ambiguity breeds confusion.

An obvious criticism might be that this doesn't handle custom media queries. Well good news, everybody. If you want a custom media query, write a custom media query. (In practice, if I needed more complexity than the above I'd cut my losses and run into the loving embrace of [Susy](http://susydocs.oddbird.net/en/latest/toolkit/#breakpoint)'s toolkit.)

Another criticism might be that I've got eight mixins here. Surely a single mixin would be the sane thing to do, then just pass in the required size, like so:

```scss
@mixin for-size($size) {
  @if $size == phone-only {
    @media (max-width: 599px) {
      @content;
    }
  } @else if $size == tablet-portrait-up {
    @media (min-width: 600px) {
      @content;
    }
  } @else if $size == tablet-landscape-up {
    @media (min-width: 900px) {
      @content;
    }
  } @else if $size == desktop-up {
    @media (min-width: 1200px) {
      @content;
    }
  } @else if $size == big-desktop-up {
    @media (min-width: 1800px) {
      @content;
    }
  }
}

// usage
.my-box {
  padding: 10px;

  @include for-size(desktop-up) {
    padding: 20px;
  }
}
```

Sure, that works. But you won't get compile-time errors if you pass in an unsupported name. And to pass in a sass variable means exposing 8 variables just to pass to a switch in a mixin.

Not to mention the syntax `@include for-desktop-up {...}` is totes more pretty than `@include for-size(desktop-up) {...}`.

A criticism of both these code snippets might be that I'm typing out 900px twice, and also 899px. Surely I should just use variables and subtract 1 when needed.

If you want to do that, go bananas, but there are two reasons I wouldn't:

1.  These are not things that change frequently. These are also not numbers that are used anywhere else in the code base. No problems are caused by the fact that they _aren't_ variables — unless you want to expose your Sass breakpoints to a script that injects a JS object with those variables into your page.
2.  The syntax is _nasty_ when you want to turn numbers into strings with Sass. Below is the price you pay for believing that repeating a number twice is the worst of all evils:

```scss
@mixin for-size($range) {
  $phone-upper-boundary: 600px;
  $tablet-portrait-upper-boundary: 900px;
  $tablet-landscape-upper-boundary: 1200px;
  $desktop-upper-boundary: 1800px;

  @if $range == phone-only {
    @media (max-width: #{$phone-upper-boundary - 1}) {
      @content;
    }
  } @else if $range == tablet-portrait-up {
    @media (min-width: $phone-upper-boundary) {
      @content;
    }
  } @else if $range == tablet-landscape-up {
    @media (min-width: $tablet-portrait-upper-boundary) {
      @content;
    }
  } @else if $range == desktop-up {
    @media (min-width: $tablet-landscape-upper-boundary) {
      @content;
    }
  } @else if $range == big-desktop-up {
    @media (min-width: $desktop-upper-boundary) {
      @content;
    }
  }
}

// usage
.my-box {
  padding: 10px;

  @include for-size(desktop-up) {
    padding: 20px;
  }
}
```

Oh and since I've taken on a ranty tone over the last few paragraphs … I pity the fool who does something magical like store breakpoints in a Sass list and loop over them to output media queries, or something similarly ridiculous that future developers will struggle to decipher.

> Complexity is where the bugs hide.

Finally, you may be thinking “shouldn't I be basing my breakpoints on content, not devices?”. Well I'm amazed you made it this far and the answer is yes … for sites with a single layout. Or if you have multiple layouts and are happy to have a different set of breakpoints for each layout. Oh and also if your site design doesn't change often, or you're happy to update your breakpoints when your designs update since you'll want to _keep_ them based on the content, right?

For complex sites, life is much easier if you pick a handful of breakpoints to use across the site.

We're done! But this post has not been as furry as I would like, let me see if I can think of an excuse to include some…

Oh, I know!

### Bonus tips for breakpoint development

![Yes, even flickr has breakpoints at 768 and 1400](https://cdn-images-1.medium.com/max/2400/1*ClU6ZZNLtd0ux8nqRPfhng.png)

1.  If you need to experience CSS breakpoints for screen sizes bigger than the monitor you're sitting at, use the `responsive` mode in Chrome DevTools and type in whatever giant size you like.
2.  The blue bar shows `max-width` media queries, the orange bar is `min-width` media queries, and the green bar shows media queries with both a min and a max.
3.  Clicking a media query sets the screen to that width. If you click on a green media query more than once, it toggles between the max and min widths.
4.  Right click a media query in the media queries bar to go to the definition of that rule in the CSS.

---

Hey, thanks for reading! Comment with your tops ideas, I'd love the hear them. And click the little heart if you think I deserve it, or leave it hollow and empty, like my sense of self-worth will be if you don't.
]]></description>
            <link>https://hungvn.com/blog/cach-dat-breakpoints-css-chinh-xac-nhat</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-dat-breakpoints-css-chinh-xac-nhat</guid>
            <pubDate>Fri, 22 Feb 2019 22:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[3 lỗi perfomance thường mắc phải với JavaScript]]></title>
            <description><![CDATA[
Điều gì sẽ xảy ra nếu tôi nói với bạn mọi thứ bạn biết là sai lầm, điều gì sẽ xảy ra nếu bạn tìm hiểu một số tính năng chính mà ECMAScript yêu thích của chúng ta đã xuất bản trong những năm gần đây, thực sự là những bẫy performance nguy hiểm, được gói gọn trong một line callback function ?
Câu chuyện này bắt đầu từ vài năm trước, trở lại thời kỳ ngây thơ của ES5...

![](https://cdn-images-1.medium.com/max/1600/0*9ZI7OIRHE7ARhiuK)

Tôi vẫn còn nhớ ngày đó, ES5 đã được phát hành và các hàm array mới tuyệt vời đã được giới thiệu cho JavaScript. Trong số đó có forEach, reduce, map, filter - chúng làm cho chúng ta cảm thấy ngôn ngữ đang phát triển, có nhiều chức năng hơn, viết mã trở nên thú vị và mượt mà hơn, và kết quả dễ đọc và dễ hiểu hơn.

Đồng thời, một môi trường mới phát triển - Node.js, nó cho chúng ta khả năng chuyển đổi dễ dàng từ front-end sang back-end trong khi thực sự muốn phát triển full stack development.

Ngày nay, Node.js, sử dụng ECMAScript mới nhất trên V8, đang cố gắng được coi là một phần của các ngôn ngữ phát triển phía server-side lớn và do đó, nó cần phải chứng minh hiệu suất xứng đáng. Vâng, có rất nhiều thông số cần được tính đến, và vâng, không có ngôn ngữ nào vượt trội hơn tất cả. Nhưng, việc viết JavaScript bằng cách sử dụng các tính năng vượt trội được cung cấp như chức năng array đã đề cập ở trên có giúp ích hay làm hại performance ứng dụng của bạn không?

Moreover, client-side javascript is claiming to be a reasonable solution for more than just presentation\view, as end-users computers grow stronger, and networks faster — but can we rely on this when our application requires blazing fast performance and might be a very large and complex one?

Hơn nữa, javascript phía client-side là một giải pháp hợp lý cho nhiều thứ hơn là chỉ view, vì máy tính của người dùng cuối phát triển mạnh hơn và mạng nhanh hơn - nhưng chúng ta có thể dựa vào điều này khi ứng dụng của chúng tôi yêu cầu hiệu năng nhanh và có thể là một rất lớn và phức tạp?

Để kiểm tra những câu hỏi này, tôi đã thử so sánh một vài kịch bản và đi sâu vào để hiểu kết quả mà tôi nhận được. Tôi đã thực hiện các thử nghiệm sau trên Node.js v10.11.0 và trong trình duyệt Chrome, cả trên macOS.

#### **1\. Looping Over an Array**

The first scenario which came to mind was summing an array of 10k items, this is a valid real-life solution I stumbled upon while trying to fetch a long table of items from the database and enhance it with the total sum, without having an additional query to the DB.

I compared the summing of random 10k items using for, for-of, while, forEach, and reduce. Running the tests 10,000 times returned the following results:

```javascript
For Loop, average loop time: ~10 microseconds
For-Of, average loop time: ~110 microseconds
ForEach, average loop time: ~77 microseconds
While, average loop time: ~11 microseconds
Reduce, average loop time: ~113 microseconds
```

While googling how to sum an array, reduce was the best-offered solution but it’s the slowest. My go-to forEach wasn’t much better. Even the newest for-of (ES6) provides inferior performance. It turns out, the good old for loop (and also while) provides the best performance by far — 10x better!

How can the newest and recommended solution make JavaScript so much slower? The cause of this pain comes from two main reasons, reduce and forEach requires a call back function to be executed which is called recursively and bloats the stack, and additional operation and verification which are made over the executed code (described [here](https://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.21)).

#### **2\. Duplicating an Array**

While this sounds like a less interesting scenario, this is the pillar of immutable functions, which doesn’t modify the input when generating an output.

Performance testing findings here again show the same interesting trend — when duplicating 10k arrays of 10k random items, it is faster to use the old school solutions. Again the trendiest ES6 spread operation `[…arr]` and Array from `Array.from(arr)` plus the ES5 map `arr.map(x => x)` are inferior to the veteran slice `arr.slice()` and concatenate `[].concat(arr)`.

```javascript
Duplicate using Slice, average: ~367 microseconds
Duplicate using Map, average: ~469 microseconds
Duplicate using Spread, average: ~512 microseconds
Duplicate using Concat, average: ~366 microseconds
Duplicate using Array From, average: ~1,436 microseconds
Duplicate manually, average: ~412 microseconds
```

#### **3\. Iterating Objects**

Another frequent scenario is iterating over objects, this is mainly necessary when we try to traverse JSON’s and objects, and while not looking for a specific key value. Again there are the veteran solutions like the for-in `for(let key in obj)`, or the later `Object.keys(obj)` (presented in es6) and `Object.entries(obj)` (from ES8) which returns both key and value.

Performance analysis of 10k objects iterations, each of which contains 1,000 random keys and values, using the above methods, reveals the following.

```javascript
Object iterate For-In, average: ~240 microseconds
Object iterate Keys For Each, average: ~294 microseconds
Object iterate Entries For-Of, average: ~535 microseconds
```

The cause is the creating of the enumerable array of values in the two later solutions, instead of traversing the object directly without the keys array. But the bottom line result is still causing concerns.

#### **Bottom Line**

My conclusion is clear — if blazing fast performance is key for your application, or if your servers require to handle some load — using the coolest, more readable, cleaner options will blow a major punch to your application performance — which can get up to 10 times slower!

Next time, before blindly adopting the slickest new trends, make sure they also align with your requirements — for a small application, writing fast and a more readable code is perfect — but for stressed servers and huge client-side applications, this might not be the best practice.
]]></description>
            <link>https://hungvn.com/blog/3-loi-perfomance-thuong-mac-phai-voi-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/3-loi-perfomance-thuong-mac-phai-voi-javascript</guid>
            <pubDate>Fri, 18 Jan 2019 21:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Web Architecture 101]]></title>
            <description><![CDATA[
Khái niệm kiến trúc web cơ bản mà tôi ước tôi biết khi mới trở thành developer.

![](https://cdn-images-1.medium.com/max/1600/1*K6M-x-6e39jMq_c-2xqZIQ.png)

Biểu đổ trên trình bày khá đủ về kiến trúc của chúng tôi ở **[Storyblocks](https://www.storyblocks.com/)**. Nếu bạn không phải là một web developer lâu năm thì ảnh trên trông sẽ khá phức tạp. Việc mổ xẻ dưới đây chắc sẽ giúp nó dễ tiếp cận hơn trước khi chúng ta đào sâu vào chi tiết của mỗi thành phần.

> Người dùng search trên Google từ khóa “Strong Beautiful Fog And Sunbeams In The Forest”. Kết quả đầu tiên đến từ Storyblocks, trang stock và vector của chúng tôi. Người dùng click vào kết quả và được chuyển tiếp đến trang chi tiết về bức ảnh. Về cơ bản là trình duyệt của người dùng gửi một request đến server DNS để tìm cách liên hệ với Storyblocks, và sau đó gửi request.
>
> ---
>
> Request này sẽ gửi đến load balancer, và nó chọn ngẫu nhiên 1 trong số các web server chúng tôi đang chạy để xử lý request. Web server tìm thông tin về ảnh từ caching service và lấy dữ liệu còn lại từ database. Cũng lưu ý rằng "hồ sơ màu" của bức ảnh chưa được tính toán, nên chúng tôi gửi một job đến hàng đợi "job queue", và job server sẽ xử lý đồng bộ, đồng thời cập nhật database với kết quả có được sau khi xử lý.
>
> ---
>
> Tiếp đó, chúng tôi thử tìm những bức ảnh tương tự bằng cách gửi một request đến service "full text search" với đầu vào là tiêu đề bức ảnh. Người dùng tình cờ đăng nhập vào Storyblocks với tư cách thành viên thì chúng tôi tìm thông tin tài khoản từ "account service". Cuối cùng, chúng tôi bắn một sự kiện đến firehose để lưu lại trên hệ thống lưu trữ đám mây và load vào data warehouse, thứ sẽ được phân tích để trả lời những câu hỏi về business.
>
> ---
>
> Server render HTML view và gửi nó trở lại trình duyệt của người dùng, trước hết thông qua load balancer. Trang web chứa JavaScript và CSS được load từ hệ lưu trữ đám mấy, nó kết nối với CDN, nên trình duyệt của người dùng có thể liên hệ với CDN để nhận nội dung. Sau cùng, trình duyệt hiển thị trang web cho người dùng.

Giờ tôi sẽ đi lần lượt từng thành phần, giới thiệu theo kiểu "101 ..." nhằm cung cấp cho bạn một mô hình chuẩn để suy nghĩ về kiến trúc web (web architecture) về sau.

### 1\. DNS

DNS là viết tắt của "Domain Name Server" và nó là công nghệ xương sống để để www (world wide web) trở nên khả dĩ. Ở mức độ cơ bản thì DNS cung cấp một tham chiếu key/value từ domain name (chẳng hạn [google.com](http://google.com) ...) đến một địa chỉ IP (chẳng hạn 85.129.83.120 ...), giúp máy tính điều hướng request đến server tương ứng. Tương tự với số điện thoại, sự khác biệt giữa domain và địa chỉ IP chính là sự khác biệt giữa việc "gọi John Doe" và "gọi đến số 201-867-5309". Bạn cần một danh bạ để tìm số của John, và tương tự, bạn cần DNS để tìm địa chỉ IP cho domain (tên miền). Thế nên bạn có thể xem DNS là một cuốn danh bạ cho internet.

Còn nhiều điều chi tiết hơn mà chúng ta có thể đề cập đến nhưng tôi sẽ bỏ qua vì nó không phải ở mức giới thiệu kiểu "101".

P/S: 101 là gì thì đọc ở đây nhé [http://www.slate.com/articles/news_and_politics/explainer/2006/09/101_101.html](http://www.slate.com/articles/news_and_politics/explainer/2006/09/101_101.html)

### 2\. Load Balancer (Cân bằng tải)

Trước khi đi sâu vào cân bằng tải, chúng ta cần thảo luận về "**horizontal scaling**" (mở rộng theo chiều ngang) và "**vertical scaling**" (mở rộng theo chiều dọc). Chúng là gì và khác nhau như thế nào? Đơn giản "horizontal scaling" nghĩa là mở rộng quy mô bằng cách thêm nhiều máy tính vào nguồn tài nguyên, trong khi "vertical scaling" nghĩa là tăng cường sức mạnh cho một máy tính đã có (chẳng hạn như CPU, RAM).

Trong web development, gần như bạn luôn muốn mở rộng theo kiểu "horizontal". Vì, server có thể bỗng dưng bị chết, mạng gặp sự cố, toàn bộ trung tâm dữ liệu thường xuyên mất mạng. Có nhiều hơn một server cho phép bạn lập kế hoạch cho các sự cố để ứng dụng vẫn tiếp tục chạy (fault tolerant). Lý do thứ hai, "horizontal scaling" sẽ cho bạn kết hợp tối thiểu các phần backend khác nhau của ứng dụng (web server, database, service X, ...) bằng cách để chúng chạy trên nhiều server. Cuối cùng, bạn có thể mở rộng quy mô đến một mức mà "vertical scaling" không thể làm được. Đó là vì không có một máy tính nào trên thế giới đủ lớn để thực hiện tất cả tính toán cho ứng dụng. Hãy nghĩ nền tảng tìm kiếm của Google như một ví dụ điển hình (dù điều này ứng dụng cho các công ty ở quy mô bé hơn nhiều). **Storyblocks**, chạy từ 150 đến 400 AWS EC2 tại thời điểm viết bài này, để đạt được khối lượng tính toán ấy bằng "vertical scaling" là một thách thức rất lớn.

Trở lại với cân bằng tải, chúng là ma thuật để mở rộng theo kiểu "horizontal", điều hướng _incoming request_ đến một trong nhiều server và gửi phản hồi từ server về client. Bất kỳ server nào cũng phải xử lý request theo cùng một cách, do đó chỉ còn lại một vấn đề là phân bổ request qua nhiều server để chúng không bị quá tải (overload).

Vậy đó, khái niệm cân bằng tải khá đơn giản. Tất nhiên công nghệ nằm phía sau nó rất phức tạp nhưng không cần đề cập với phiên bản "101" làm chi.

### 3\. Web Application Servers

Web server là nơi thực thi business logic, xử lý request của user và gửi lại HTML đến trình duyệt của user. Để làm việc đó, chúng kết nối với nhiều infra phía back-end như database, caching layer, job queue, search service, microservice, data/logging queue, ... Như đã đề cập ở trên, ít nhất 2 server thường được kết nối với cân bằng tải để xử lý request của người dùng.

Bạn nên biết rằng triển khai server yêu cầu một ngôn ngữ cụ thể (Node.js, Ruby, PHP, Scala, Java, C# .NET, ...) và một web framework cho ngôn ngữ đó (Express, Ruby on Rails, Play, Laravel, ...). Tuy nhiên đi sâu vào chi tiết của những ngôn ngữ này nằm ngoài phạm vi của bài viết.

### 4\. Database Servers

Mọi ứng dụng web hiện đại đều sử dụng một hoặc nhiều database để lưu trữ thông tin. Database cung cấp phương thức để định nghĩa cấu trúc dữ liệu, insert dữ liệu mới, tìm dữ liệu đã có, cập nhật hoặc xóa dữ liệu, thực hiện tính toán, ...

Dù tôi tránh đào sao vào một công nghệ cụ thể cho mỗi thành phần của kiến trúc web, sẽ rất tệ nếu tôi không đề cập đến SQL và NoSQL.

SQL là viết tắt của "Structured Query Language" (ngôn ngữ truy vấn có cấu trúc) được phát minh vào thập niên 70 của thế kỷ trước, cung cấp một chuẩn để truy vấn dữ liệu. SQL database lưu trữ dữ liệu theo bảng, được liên kết với nhau thường bằng ID. Hãy lấy một ví dụ cơ bản về lưu trữ địa chỉ của người dùng. Bạn có 2 bảng, _users_ và _user_addresses_, liên kết với nhau bằng id của người dùng.

![sql](646f6ef3-7806-4835-bc29-950c6532657b.png)

NoSQL, nghĩa là "Non-SQL", là một công nghệ cơ sở dữ liệu mới hơn, dùng để xử lý khối lượng dữ liệu lớn được sinh ra bởi những ứng dụng web có quy mô lơn (hầu hết các biến thể của SQL không scale theo kiểu "horizontal" tốt và chỉ có thể scale theo kiểu "vertical" đến một mức độ nhất định). Nếu bạn không biết gì về NoSQL, tôi đề nghị xem những tài liệu dưới đây:

- [https://www.w3resource.com/mongodb/nosql.php](https://www.w3resource.com/mongodb/nosql.php)
- [http://www.kdnuggets.com/2016/07/seven-steps-understanding-nosql-databases.html](http://www.kdnuggets.com/2016/07/seven-steps-understanding-nosql-databases.html)
- [https://resources.mongodb.com/getting-started-with-mongodb/back-to-basics-1-introduction-to-nosql](https://resources.mongodb.com/getting-started-with-mongodb/back-to-basics-1-introduction-to-nosql)

### 5\. Caching Service

Một _caching service_ (dịch vụ lưu bộ nhớ đệm) cung cấp lưu trữ dữ liệu theo kiểu "key/value" đơn giản giúp nó tìm kiếm thông tin với thời gian gần như bằng 0\. Các ứng dụng thường tận dụng _caching service_ để lưu kết quả của những tính toán đắt đỏ để nhận kết của từ bộ nhớ đệm thay vì phải tính toán lại một lần nữa khi cần. Ứng dụng có thể cache kết quả của một truy vấn cơ sở dữ liệu, gọi đến một dịch vụ bên ngoài, cache HTML của một đường link, ... Dưới đây là một vài ví dụ thực tế:

- Google lưu kết quả tìm kiếm cho những truy vấn thông thường như "dog" hoặc "Taylor Swift" để không phải tính toán lại mỗi lần
- Facebook lưu nhiều dữ liệu bạn nhìn thấy khi đăng nhập, chẳng hạn bài viết, bạn bè... Bạn có thể đọc chi tiết về Facebook caching ở [đây](https://medium.com/@shagun/scaling-memcache-at-facebook-1ba77d71c082).
- Storyblocks lưu HTML output, kết quả tìm kiếm, ...

Hai công nghệ caching phổ biến nhất là Redis và Memcache.

### 6\. Job Queue & Servers

Hầu hết ứng dụng web đều cần làm một số công việc bất đồng bộ ở phía back-end mà không kết hợp trực tiếp vào dữ liệu trả về cho người dùng. Chẳng hạn, Google cần crawl và index toàn bộ internet để trả về kết quả tìm kiếm. Nó không được làm mỗi lần bạn tìm kiếm. Thay vào đó, nó crawl các trang web một cách bất đồng bộ, và cập nhật index theo thời gian.

Mặc dù có nhiều kiến trúc khác nhau cho các công việc bất đồng bộ, nhưng phố biến nhất là kiến trúc "job queue". Nó chứa 2 thành phần: một hàng đợi "job" cần được chạy, và một hoặc nhiều "job server" (hay còn lại là worker) để chạy job trong hàng đợi.

Job queue chứa một danh sách job cần được chạy bất đồng bộ. Hàng đợi đơn giản nhất là FIFO (first in first out) mặc dù hầu hết ứng dụng sẽ cần một vài hàng đợi có ưu tiên. Mỗi khi ứng dụng cần chạy job thì nó chỉ cần thêm job đó vào hàng đợi.

Storyblocks, chẳng hạn, tận dụng "job queue" để hỗ trợ rất nhiều công việc phía back-end nhằm phục vụ thị trường của chúng tôi. Chúng tôi chạy job để encode video và ảnh, xử lý file CSV, thống kê người dùng, gửi mật khẩu reset email, ... Lúc đầu chúng tôi sử dụng hàng đợi FIFO đơn giản, sau đó nâng cấp lên hàng đợi ưu tiên để đảm bảo rằng những hoạt động khẩn như gửi mật khẩu reset email được hoàn thành càng sớm càng tốt.

Job server xử lý job. Chúng thăm dò "job queue" để xác định có job cần làm hay không, và nếu có thì chúng sẽ đẩy job vào hàng đợi và thực thi nó.

### 7\. Full-text Search Service

Hầu hết ứng dụng web hỗ trợ một vài chức năng tìm kiếm mà người dùng thường sẽ cung cấp một tham số văn bản (còn gọi là "query") và ứng dụng trả về kết quả "liên quan". Công nghệ hỗ trợ đặc tính này thường gọi là "full-text search", sử dụng index để nhanh chóng tìm tài liệu chứa từ khóa cần truy vấn.

![full-text search](eba8d45b-27eb-4e56-8380-6db35a45329d.png)

Dù có thể thực hiện "full-text search" trực tiếp từ database (chẳng hạn MySQL hỗ trợ full-text search), nó thường chạy một "search service" riêng để tính toán và lưu trữ chỉ mục và cung cấp một giao diện truy vấn riêng. Nền tảng full-text search phổ biến nhất hiện nay là Eltasticsearch, bên cạnh một số lựa chọn khác như Sphinx hoặc Apache Solr.

### 8\. Services

Khi ứng dụng đạt đến quy mô nhất định, sẽ có một số "service" được tahcs ra để chạy như một ứng dụng riêng. Chúng không được public bên ngoài nhưng ứng dụng và các service khác có thể tương tác với chúng. Storyblocks có một số service như vậy:

- Account service để lưu trữ dữ liệu người dùng trên tất cả các trang web của chúng tôi, cho phép chúng tôi dễ dàng cung cấp các cơ hội "cross-sell" và tạo những trải nghiệm người dùng nhất quán hơn
- Content service lưu trữ metadata cho video, audio, ảnh. Nó cũng cung cấp giao diện để download nội dung và xem lịch sử download.
- Payment service cung cấp giao diện thanh toán bằng thẻ tín dụng.
- HTML → PDF service cung cấp giao diện đơn giản để sinh ra file PDF từ HTML.

### 9\. Data

Ngày nay, công ty muốn tồn tại thì phải dựa trên cách họ khai thác dữ liệu. Hầu hết những ứng dụng bây giờ, mỗi lần đạt đến một quy mô nhất định, hãy tận dụng kênh dữ liệu (data pipeline) để đảm bảo rằng dữ liệu được thu thập, lưu trữ và phân tích. Một kênh dữ liệu bao gồm 3 giai đoạn chính:

1.  Ứng dụng gửi dữ liệu, sự kiện về tương tác của người dùng cho "firehose" (cung cấp giao diện streaming để nhập và xử lý dữ liệu). Thông thường dữ liệu thô được xử lý sẽ được gửi đến firehose khác. AWS Kinesis và Kafka là hai công nghệ phố biến nhất cho mục đích này.
2.  Dữ liệu thô cũng như dữ liệu đã được chuyển đổi được lưu trữ đến cloud. AWS Kinesis cung cấp một setting gọi là "firehose" sẽ lưu dữ liệu thô vào S3 để dễ cấu hình.
3.  Dữ liệu được chuyển đổi sẽ được tải vào data warehouse để phân tích. Chúng tôi sử dụng AWS Redshift, mặc dù các công ty lớn khác thường dùng Oracle hoặc công nghệ warehouse độc quyền. Nếu bộ dữ liệu đủ lớn, công nghệ NoSQL MapReduce như Hadoop sẽ được sử dụng để phân tích.

Một bước khác không được mô tả trong biểu đồ kiến trúc là: tải dữ liệu từ database của ứng dụng và service vào data warehouse. Chẳng hạn ở Storyblocks, chúng tôi tải VideoBlocks, AudioBlocks, Storyblocks, account service, ... vào Redshift mỗi đêm. Điều này cung cấp cho bộ phân tích những dữ liệu tổng thể bằng cách cấp phát dữ liệu business cùng với dữ liệu tương tác của người dùng.

### 10\. Cloud storage

Dịch vụ đám mây là cách đơn giản nhất để lưu trữ, truy xuất và chia sẻ dữ liệu trên internet, theo AWS. Bạn có thể dùng nó để lưu trữ và truy cập với lợi thế là tương tác với nó quả RESTful API. Amazon S3 là dịch vụ lưu trữ đám mây phổ biến nhất ngày nay, và chúng tôi dựa vào nó để lưu trữ video, ảnh, audio, CSS và JavaScript, dữ liệu sự kiện người dùng và hơn thế nữa.

### 11\. CDN

CSN là viết tắt của "Content Delivery Network" và công nghệ cung cấp một cách để phục vụ nội dung tĩnh như HTML, CSS, JavaScript và ảnh trên web nhanh hơn so với việc chỉ dùng một server. Nó hoạt động bằng cách phân tán nội dung qua nhiều "edge server" khắp thế giới để người dùng cuối có thể download nội dung từ "edge server" thay vì từ server gốc. Chẳng hạn như ảnh dưới đây, một người dùng từ Tây Ban Nha request một trang web mà có server gốc là ở New York, nhưng các tài nguyên tĩnh của trang web lại được tải về từ "edge server" của CDN từ Anh.

![cdn](0bf32d18-11cf-496a-98b7-ccbbe31ec4b5.png)
]]></description>
            <link>https://hungvn.com/blog/web-architecture-101</link>
            <guid isPermaLink="true">https://hungvn.com/blog/web-architecture-101</guid>
            <pubDate>Sun, 06 Jan 2019 23:31:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Một mô hình sử dụng Git branches hiệu quả]]></title>
            <description><![CDATA[
Mới đầu mình tính viết về [git-flow](https://github.com/nvie/gitflow) - một tool đơn giản dùng để quản lý Git branches, xong thấy bài viết [này](http://nvie.com/posts/a-successful-git-branching-model/) về một ví dụ sử dụng Git branches hay quá, nên quyết định dịch luôn.

## Mở đầu

Ngay bây giờ, tôi sẽ giới thiệu với các bạn mô hình sử dụng Git mà tôi đã và đang sử dụng trong các dự án khoảng một năm trở lại đây. Đó là một mô hình thực sự thành công, nhưng mãi đến giờ tôi mới có cơ hội để có thể viết về nó và chia sẻ với các bạn. Tôi sẽ không đi vào chi tiết dự án, mà chỉ xoay quanh chiến lược quản lý các phân nhánh mà thôi.

![](git-model@2x.png)

Trong bài viết dưới đây, tôi sử dụng Git để quản lý version cho toàn bộ source code. Nếu các bạn có hứng thú với việc phân tích dữ liệu thời gian thực dựa vào hoạt động trên Git, có thể tham khảo phần mềm mà [GitPrime](http://gitprime.com/) mà công ty tôi phát triển.

## Tại sao lại chọn Git?

Đã có quá nhiều cuộc chiến nổ ra khi bàn về ưu điểm nhược điểm của Git so với các công cụ quản lý source code tập trung khác (như CVS, SVN). Là một developer, tôi cảm thấy yêu thích Git hơn. Git thực sự đã thay đổi cách suy nghĩ về merging và branching. Những ai đã từng làm việc với CVS/Subversion đều hiểu merging/branching không hề đơn giản, trong [tài liệu về CVS/Subversion](http://svnbook.red-bean.com/) branching và merging chỉ được nhắc đến ở chapter cuối, dành cho các users có kinh nghiệm. Còn với Git, branching/merging là một phần trong workflow hàng ngày của bạn, được mô tả ở những phần đầu tiên trong [Git book](http://book.git-scm.com/).

## Phân tán, nhưng tập trung

Mô hình Git mà tôi sử dụng hoạt động xoay quanh một repo trung tâm. Nên nhớ đó "chỉ được xem như" là repo trung tâm, chứ về mặt kỹ thuật thì GIT không hề có cái gì gọi là repo trung tâm cả. Ví dụ như repo origin ở hình bên dưới.

![](centr-decentr@2x.png)

Mỗi developer sẽ pull và push với origin. Bên cạnh đó, mỗi người có thể pull những thay đổi từ những người khác để tạo thành các sub teams. Điều này sẽ thực sự có ích khi phải làm việc nhóm 2-3 người trở lên để hoàn thành một feature lớn, mà không phải đẩy source code vẫn đang dở dang lên origin. Ở hình vẽ bên trên, các subteams là Alice-Bob, Alice-David, Clair-David.

Về mặt kỹ thuật, đơn giản là Alice định nghĩa một Git remote là bob, trỏ đến repo của Bob, và ngược lại.

## Những branches chính

Repo trung tâm sẽ chứa hai branches chính hoạt động mãi mãi:

- master
- develop

Nhánh master tại origin là nhánh quen thuộc với tất cả các Git users. Song song là nhánh develop.

![](main-branches@2x.png)

origin/master được coi là nhánh chính với HEAD phản ánh trạng thái production-ready.

origin/develop được coi là nhánh chính với HEAD phản ánh trạng thái thay đổi mới nhất trong quá trình phát triển, chuẩn bị cho release tiếp theo.

Khi source code bên develop đạt đến một mức độ ổn định nào đó và sẵn sàng để release thì sẽ được merge sang bên master và đánh dấu với release number.

Như vậy, theo định nghĩa về nhánh master, chúng ta mặc định hiểu rằng khi có thay đổi được merge vào master thì tức là sẽ có một phiên bản production mới được release. Nhờ đó chúng ta có thể sử dụng script để tự động build lên production server mỗi khi có commit ở master.

## Những branches phụ

Bên cạnh hai branches chính master và develop, mô hình mà tôi đang sử dụng còn có thêm rất nhiều những branches phụ để giúp các team members có thể phát triển song song, dễ dàng tracking theo features, chuẩn bị cho release hoặc fix nhanh các vấn đề production. Khác với hai branches chính kia, các branches phụ này chỉ tồn tại trong một khoảng thời gian ngắn, rồi sẽ bị xoá đi.

- Feature branches
- Release branches
- Hotfix branches

Phía trên là các loại branches khác nhau tôi hay sử dụng. Mỗi loại branches lại có một nhiệm vụ riêng, và cách xử lý riêng. Tôi sẽ đi sâu vào phân tích ở đoạn sau.

Về mặt kỹ thuật, chả có branch nào là "đặc biệt" so với các branches khác cả. Tất cả chỉ là Git branches thông thường, chúng chỉ được phân loại bằng cách ta sử dụng ra sao thôi.

### Feature branches

- Tách từ: develop
- Merge vào: develop
- Naming convention: tự do, ngoại trừ master, develop, release-_, hotfix-_

![](fb@2x.png)

Feature branches (hay còn gọi là topic branches) được sử dụng để phát triển các feature mới phục vụ cho release sau này. Khi bắt đầu phát triển một chức năng, có thể chưa rõ được thời điểm chức năng đó được tích hợp vào hệ thống và release. Feature branch sẽ tồn tại trong quá trình chức năng được phát triển, cuối cùng sẽ được merge lại vào develop (khi quyết định lần release tới bao gồm chức năng đó) hoặc bị bỏ đi (khi thấy chức năng không còn cần thiết).

Về cơ bản thì feature branches chỉ tồn tại ở repos của developers, chứ ko phải ở origin.

#### Tạo feature branch

```
$ git checkout -b myfeature develop
```

#### Merge vào develop

```
$ git checkout develop
$ git merge --no--ff myfeature
$ git branch -d myfeature
$ git push origin develop
```

--no-ff giúp thao tác merge luôn tạo ra một commit mới, ngay cả khi có thể merge theo fast-forward. Flag này giúp chúng ta không bị mất thông tin liên quan đến lịch sử các commits của feature branch.

![](merge-without-ff@2x.png)

Ở trường hợp bên phải, không thể nhận biết được những commits nào phát triển cùng chức năng nếu không ngồi đọc log message của từng commit. Khi dấy, nếu muốn revert lại cả feature (phải revert nhiều commits liên quan) thì thực sự là đau đầu. Và đó là lý do mà --no-ff được sử dụng.

Đương nhiên, nó sẽ tạo ra thêm vài commit, nhưng chả có vấn đề gì cả.

### Release branches

- Tách từ: develop
- Merge vào: develop và master
- Naming convention: release-\*

Release branches được sử dụng để chuẩn bị cho release bản production mới. Tất cả các công việc cuối cùng trước khi release sẽ được thực hiện ở đây, ngoài ra còn để fix nốt các bugs lẻ tẻ, chuẩn bị meta-data (version number, build dates, etc..). Nhờ việc tách nhánh ra khỏi develop, chúng ta có thể tiếp tục phát triển các features cho đợt release khác một cách bình thường.

Thời điểm được lựa chọn để tách nhánh từ develop là khi develop phản ánh được trạng thái mong muốn cho việc release mới. Ít nhất lúc đó tất cả các features dành cho đợt release phải được merge vào develop rồi. Những features nhắm đến các lần release sau thì chưa được merge vào, phải đợi sau khi tách nhánh.

Chúng ta sẽ tiến hành đánh version theo rule của dự án ngay sau khi tạo release branch.

#### Tạo release branch

```
$ git checkout -b release-1.2 develop
$ ./bump-version.sh 1.2
$ git commit -a -m "Bumped version number to 1.2"
```

Ở ví dụ trên, bump-version.sh tượng trưng cho một script thay đổi một vài files trong source code để phản ánh version mới. Sau khi tạo branch mới và chuyển sang branch đó, chúng ta sẽ thực hiện nâng version, rồi commit thao tác đó.

Branch mới này sẽ tồn tại cho đến khi việc release được thực hiện gọn ghẽ. Trong khoảng thời gian đó, có thể thực hiện fix bugs ở branch này, tuy nhiên nghiêm cấm việc bổ sung feature mới lên đó. Tốt nhất nếu có features mới thì hãy merge vào develop, và đợi đợt release sau.

#### Kết thúc release branch

Khi source code trên release branch sẵn sàng để release, đầu tiên, phải merge vào master, sau đó phải đc merge lại vào develop để những lần release sau cũng chứa những thay đổi ở lần này.

```
$ git checkout master
$ git merge --no-ff release-1.2
$ git tag -a 1.2
```

Vậy là source code đã được release lên master, và đã được tag để tiện sau này tham chiếu.

```
$ git checkout develop
$ git merge --no-ff release-1.2
```

Ở bước này, rất có thể sẽ có confict, nên hãy fix nó rồi commit nhé.

Bây giờ thì việc release đã hoàn thành, và chúng ta ko cần đến branch này nữa.

```
$ git branch -d release-1.2
```

### Hotfix branches

- Tách từ: master
- Merge vào: develop và master
- Naming convention: hotfix-\*

![](hotfix-branches@2x.png)

Hotfix branches cũng giống release branches ở chỗ được sử dụng để chuẩn bị cho việc release production mới, chỉ khác ở chỗ là ko có plan từ trước. Khi có một bug nghiêm trọng trên bản production cần được giải quyết ngay lập tức, một hotfix branch sẽ được tách ra từ master và được đánh version để nhận biết.

Ưu điểm của việc tách nhánh này ở chỗ các team members khác có thể tiếp tục công việc ở develop trong khi những người khác có thể tập trung vào fix bug của production.

#### Tạo hotfix branch

Hotfix branch được tạo ra từ master. Ví dụ hiện tại version 1.2 là phiên bản production đang chạy và xuất hiện lỗi nghiêm trọng. Tuy nhiên source code trên develop vẫn chưa ổn định, vì thế chúng ta phải tách nhánh hotfix và tiến hành sửa lỗi.

```
$ git checkout -b hotfix-1.2.1 master
$ ./bump-version.sh 1.2.1
$ git commit -a -m "Bumped version number to 1.2.1"
```

Sau khi tách nhánh phải tiến hành up version luôn nhé!

Sau khi sửa lỗi, hãy thực hiện commit.

```
$ git commit -m "Fixed severe production problem"
```

#### Kết thúc hotfix branch

Sau khi kết thúc sửa lỗi, những thay đổi phải được merge lại master, đồng thời cũng phải merge vào develop để ngăn lỗi xảy ra ở những lần release sau. Nghe rất giống với xử lý trên release branch phải không.

```
$ git checkout master
$ git merge --no-ff hotfix-1.2.1
$ git tag -a 1.2.1

$ git checkout develop
$ git merge --no-ff hotfix-1.2.1
```

Tuy nhiên, có một điểm cần lưu ý rằng: **khi đang tồn tại một release branch thì cần phải merge hotfix vào release branch đó, thay cho develop**. Khi release branch được merge vào develop thì cuối cùng những thay đổi trong hotfix cũng được merge vào develop, nên không có vấn đề gì cả. Trừ khi thực sự công việc ở develop cần phần hotfix ngay lập tức và ko thể đợi release branch được merge, thì cần cẩn thận merge hotfix vào develop.

Cuối cùng, chúng ta cũng ko cần đến branch này nữa:

```
$ git branch -d hotfix-1.2.1
```
]]></description>
            <link>https://hungvn.com/blog/mot-mo-hinh-su-dung-git-branches-hieu-qua</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mot-mo-hinh-su-dung-git-branches-hieu-qua</guid>
            <pubDate>Sun, 06 Jan 2019 23:24:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giới thiệu về Atomic CSS]]></title>
            <description><![CDATA[
## Những vấn đề với cách viết CSS hiện tại

### Specificity war, thâm cung nội chiến

Bạn còn nhớ lần đầu bạn viết CSS giống như thế nào không? Có thể là khai báo style cho một thẻ HTML nào đó.

```css
a {
  text-decoration: none;
}

p {
  color: rainbow;
}
```

Sau đó bạn biết thêm về ID và class:

```css
#header {
  margin: 10px;
  text-align: center;
  color: fabulous;
}

.text {
  font-weight: 700;
  font-size: 20px;
}
```

Và bạn học được cách xử lý các pseudo selectors, hoặc khai báo cho các phần tử anh chị em con cháu họ hàng, v.v…

```css
#header > a:first-child {
  color: unicorn;
}

#header p > a.text::before {
  content: "⛓";
  font-family: Comic Sans;
}
```

Rồi khi bạn đã quen với CSS và bắt tay vào làm dự án thực tế, bạn bàng hoàng nhận ra kẻ thù không ở đâu xa, chúng đang lởn vởn quanh ta í mà. Bạn bước vào cuộc chiến gọi là [“specificity war”](https://css-tricks.com/a-specificity-battle/), đánh nhau tơi bời khói lửa với class được viết bởi các chiến hữu trong team. Quả là một trận đấu kinh hoàng khi ai cũng muốn đè đầu cưỡi cổ (override) người đi trước. Kẻ nắm giữ !important trong tay cứ nghĩ đã gần với chiến thắng, nào ngờ xuất hiện tiểu nhân dùng inline style + !important. Tình anh em sứt mẻ, chiến hữu quay đầu không nhìn mặt nhau. Bạn ức chế và gào lên "đậu phộng CSS 🥜".

> **Specificity là gì?**
>
> Specificity là một trọng số được trình duyệt sử dụng để quyết định CSS style nào sẽ được áp dụng cho các element. Specificity được tính toán dựa vào phân loại selector và số lượng selector áp dụng lên một element. Bạn có thể đọc thêm về chủ đề này [ở đây](http://gockinhnghiem.com/2011/11/09/specificity-trong-css-la-gi/) hoặc trên trang [MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity). [http://cssspecificity.com](http://cssspecificity.com) minh hoạ khá cụ thể cách tính specificity.

### Block\_\_Element--Modifier

Dân tay to mặt bự đọc đến đây có lẽ đang âm thầm (hoặc công khai) cười khẩy: "Ai kêu gà, xài BEM là được rồi". Chíp chíp 🐥

> **Cho những bạn chưa biết:**
>
> [BEM - Block Element Modifier](https://css-tricks.com/bem-101/) là một phương pháp đặt tên CSS class được phát triển bởi Yandex. Theo lý thuyết, BEM giúp bạn xây dựng các class theo từng block, mỗi block lại có element con, và các element này có thể sẽ có giao diện khác nhau tuỳ thuộc vào modifier của nó.
>
> Ví dụ đây là CSS:
>
> ```javascript
> /* Block */
> .btn {
> }
>
> /* Element */
> .btn__price {
> }
>
> /* Modifier */
> .btn--big {
> }
>
> .btn--green {
> }
> ```
>
> Áp dụng vào HTML:
>
> `<button class="btn btn--big btn--green"><span class="btn__price">$9.99</span></button>`

Hoàn toàn không sai. BEM là một phương pháp hiệu quả để chia nhỏ trang thành từng component, và bạn hoàn toàn có thể tránh được cuộc thánh chiến ở trên bằng cách chỉ sử dụng class được đặt tên theo BEM. Ngoài ra, khi một component không còn được dùng nữa, bạn có thể tự tin xoá đi class của nó mà không sợ ảnh hưởng đến các component khác.

Tuy nhiên BEM cũng có những vấn đề “khó chịu” mà bạn có thể xem thêm ở bài viết [Battling BEM CSS: 10 Common Problems And How To Avoid Them](https://www.smashingmagazine.com/2016/06/battling-bem-extended-edition-common-problems-and-how-to-avoid-them/). Kinh nghiệm cá nhân là khi làm việc với BEM, có thể bạn sẽ bỏ kha khá thời gian chỉ để suy nghĩ về ngữ nghĩa (semantics) của class. Bạn sẽ phải cân nhắc block này nên đặt tên là gì, những thành phần con của nó có nên là element hay là một component khác, rồi element này nên có tên chi, nên gọi nó là wrapper, container, hay body, v.v… Đừng coi thường việc đặt tên nhé, một trong những vấn đề khó nhai nhất của khoa học máy tính đấy. Ngoài ra tên class thường dính liền với cấu trúc/ nội dung HTML mà nó được sử dụng, dẫn đến việc khi refactor code lại (chuyển thành component tổng quát hơn), chúng ta phải tốn thời gian suy nghĩ tên khác cho hợp lý.

Với mình, việc suy nghĩ thêm về ngữ nghĩa cho CSS class không đem lại hiệu quả đáng kể. Vì không giống như HTML, trình duyệt và crawlers không quan tâm bạn đặt tên class có ý nghĩa hay không. Chúng chỉ có giá trị với lập trình viên, và thường thì chúng ta chỉ muốn viết HTML/CSS sao cho giống với thiết kế từ designers nhất mà thôi.

### Tính tái sử dụng và kích thước tập tin CSS

Mỉa mai thay, tính chất “cascading” của CSS vốn được sinh ra để hỗ trợ tái sử dụng code lại là một con dao 2 lưỡi và đem đến phiền muộn cho biết bao nhiêu người. Cascading cùng với specificity làm cho CSS trở nên khó dự đoán và lời khuyên là hạn chế cascading được bao nhiêu hay bấy nhiêu. Điều này dẫn đến tập tin CSS chứa nhiều khai báo bị trùng lắp.

```javascript
.ie6 #footer-content .flex-control-nav li a,
.ie7 #footer-content .flex-control-nav li a,
.ie8 #footer-content .flex-control-nav li a {
  float: left;
}

#nav.challenger-a li.menu-products {
  float: left;
}
```

Khi dự án của bạn phát triển, nhiều component xuất hiện đồng nghĩa với kích thước tập tin CSS ngày càng to ra. Đáng buồn là, không phải tất cả CSS được gửi xuống cho người dùng sẽ thật sự được sử dụng trong trang.

![](https://res.cloudinary.com/duqeezi8j/image/upload/f_auto,c_scale,w_1000/v1545725390/1_qoyWe6NLqjzVRlDb5YWQAA_nhykgd.jpg)

_Kích thước tập tin CSS của các website lớn, tính đến tháng 11 năm 2016\. Nguồn: [1]_

## Vậy atomic CSS giải quyết được những vấn đề trên à?

Có thể. Nhưng trước hết hãy xem atomic CSS là gì đã.

Atomic CSS là cách khai báo các class sao cho mỗi class chỉ mô tả một tính năng duy nhất. Để xây dựng component lớn hơn, chúng ta sẽ kết hợp các class nguyên tử này lại với nhau. Chẳng hạn như:

```css
.white {
  color: #fff;
}

.bg-green {
  background-color: #3d9970;
}

.px-10 {
  padding-left: 10px;
  padding-right: 10px;
}
/*  Oát đờ hợi (ಠ_ಠ) */
```

Trong ví dụ trên, class white chỉ làm duy nhất một việc là đổi chữ sang màu trắng, bg-green sẽ thiết lập nền sang màu xanh, trong khi px-10 chỉnh padding ở bên trái và phải (trục x/ trục hoành) thành 10px. Một component được viết theo atomic CSS sẽ giống như thế này:

```html
<button class="b1 b--green bg-green white br-5 ma-10 f3 ttu fw-400 padding-10">
  <span class="bg-dark o4 white padding-x-12 fw-600 br-left-5">$9.99</span>
  Purchase
</button>
```

See the Pen [BEM vs atomic CSS](https://codepen.io/ehkoo/pen/KbmGEq/) by Ehkoo ([@ehkoo](https://codepen.io/ehkoo)) on [CodePen](https://codepen.io).

Atomic CSS đang được sử dụng bởi các công ty như [npm](https://www.npmjs.com/), [StackOverflow](https://stackoverflow.design/product/guidelines/using-stacks#goals), [Heroku](https://design.herokai.com/purple3), v.v…

**Chuyện bên lề: Functional CSS, Atomic CSS, hay Utility-first CSS?**

“Functional CSS” là tên gọi đầu tiên mình bắt gặp khi tìm hiểu về cách viết CSS này. Từ “functional” ngoài nghĩa như trong “functional programming” còn có nghĩa là “hoạt động” (trích [từ điển Oxford](https://en.oxforddictionaries.com/definition/functional)). Do đó “functional CSS” có thể hiểu là "CSS hoạt động được", hoàn toàn không liên quan đến ý tưởng chính: đặt CSS class thành từng hàm nhỏ.

Một tên gọi khác là "Atomic CSS", theo nghĩa mỗi class là một “nguyên tử” độc lập. Tên gọi này rất phù hợp với tiêu chí chia nhỏ class, nhưng đáng tiếc thay khi nó “có thể” nhầm lẫn là có liên quan tới phương thức [Atomic Design](http://atomicdesign.bradfrost.com/chapter-2/). Ngoài ra, có một thư viện của Yahoo! cũng tên là [Atomic CSS](https://acss.io/).

Cuối cùng, “Utility-first CSS” có lẽ là tên gọi mô tả chính xác nhất. “Utility-first” mang nghĩa "tập trung xây dựng các class hỗ trợ". Điểm trừ của thuật ngữ này là…tên dài quá.

Suy đi xét lại thiệt hơn thì trong bài viết này mình chọn “atomic CSS” (chữ “a” viết thường) vì…gõ nhanh thôi. Nhưng bạn để ý là 3 thuật ngữ này đều dùng chung cho một cách viết CSS nhé.

## Vậy có gì hay?

### Tránh cảnh binh đao

Lợi ích đầu tiên là cũng giống như BEM, atomic CSS chỉ cho phép khai báo các class nên chúng không xảy ra tranh chấp specificity. Đồng thời vì mỗi class chỉ mô tả một tính năng duy nhất, việc các thuộc tính giẫm chân lên nhau được hạn chế ở mức thấp nhất.

Còn vẫn ghét nhau quá, muốn đạp nhau cho chết thì đây:

```html
<div class="red">
  Roses are red
  <div class="blue">
    Violets are blue
    <div class="yellow">
      Honey is sweet
      <div class="brown">But not as sweet as you</div>
    </div>
  </div>
</div>
```

_Credit: @huytd_

### Tập tin CSS nhẹ hơn

Bằng cách xây dựng component bằng những class nguyên tử, bạn không cần phải lặp đi lặp lại những khai báo đã có. Khi nhận được thiết kế cho component mới, bạn chỉ cần kết hợp những class đã có sẵn với nhau hoặc viết thêm atomic classes. Những class mới xuất hiện sẽ tiếp tục được tái sử dụng nên số lượng class bạn thêm vào sẽ ngày càng giảm đi khi tuổi thọ của dự án dài ra. Trong bài viết [By The Numbers: A Year and Half with Atomic CSS](https://medium.com/@johnpolacek/by-the-numbers-a-year-and-half-with-atomic-css-39d75b1263b4), John Polacek đã thử nghiệm chuyển đổi từ CSS truyền thống sang atomic CSS và kết quả là dung lượng tập tin giảm từ 123.1KB xuống còn 72.7KB (chưa nén gzip).

![](https://res.cloudinary.com/duqeezi8j/image/upload/c_scale,f_auto,w_1000/v1545725434/1_Tvxaigmr3ve2GrWDwHB9Pw_qtsoai.jpg)

Kết quả cuối cùng là càng ngày bạn sẽ càng viết ít CSS lại.

### Không phải suy nghĩ chuyện đặt tên class

Vì các atomic classes được đặt tên gần với thuộc tính của chúng, bạn không cần phải suy nghĩ nên đặt tên gì. Một lợi ích nữa là nhìn vào HTML bạn có thể tương đối biết được style của một element. Lấy ví dụ:

```html
<!-- BEM -->
<button class="btn btn--big btn--green"><span class="btn__price">$9.99</span> Purchase</button>

<!-- atomic CSS -->
<button class="b1 b--green bg-green white br-5 ma-10 f3 ttu fw-400 padding-10">
  <span class="bg-dark o4 white padding-x-12 fw-600 br-left-5">$9.99</span>
  Purchase
</button>
```

Với BEM, bạn có thể sơ đoán "à cái nút này là cái nút màu xanh bự nè", nhưng “bự” là cái gì "bự", font size hay height, và cái gì "xanh", chữ xanh, nền xanh hay viền xanh. Khi đi đến btn\_\_price thì hoàn toàn không thể biết được style của nó. So sánh với atomic CSS, bạn có thể đọc ngay là "nút này có viền 1px, viền màu xanh, nền xanh, chữ trắng, bo tròn góc 5px, margin ở bốn phía 10px, font ở level 3, chữ được chuyển thành chữ hoa có font weight 400, padding bốn phía 10px". Tương tự với thẻ SPAN, bạn có thể đọc là "nền đen có opacity 0.4, chữ trắng, padding trái phải 12px, font weight 600, bo tròn góc bên trái 5px".

Liệu việc đọc style như thế này có cần thiết? Nếu bạn mới bắt đầu, câu trả lời có thể là không, nhưng khi đã quen rồi, đọc class nhanh giúp bạn debug và thay đổi style dễ dàng hơn.

### Xây dựng prototype nhanh hơn

Prototyping, hay là chuyện làm những giao diện giả để kiểm tra UI/UX, không còn lạ với dân làm frontend nữa. Một trong những lý do bạn chọn Bootstrap, Foundation, hay Bulma… cho dự án vì đơn giản chúng cung cấp những component được xây dựng sẵn, cùng với hệ thống grid và các class hỗ trợ. Nhưng rồi bạn sẽ lâm vào cảnh đánh nhau với các class của framework để tuỳ biến cho phù hợp với chuẩn thiết kế. Kết quả ra sao thì bạn biết rồi.

Các framework được thiết kế theo hướng atomic không có nhiều component, nhưng bù lại chúng không đặt quá nhiều ý kiến riêng và ép buộc bạn phải làm theo. Hầu hết đều cho phép bạn tuỳ chỉnh màu sắc, kích thước theo ý, từ đó bạn có thể xây dựng lên những component cần thiết.

## Hạn chế

### Bùng nổ class

[Tachyons](http://tachyons.io/docs/themes/skins/) là một trong những atomic CSS framework phổ biến nhất. Trong phiên bản 4.10.0, Tachyons hỗ trợ 37 màu. Giả sử mỗi màu sẽ có class tương ứng với màu chữ, màu nền, màu viền, hover đổi màu chữ, hover đổi màu nền, và hover đổi màu viền. Tachyons có 3 breakpoints. Như vậy tổng số class được tạo ra là 37 x 8 (thuộc tính) x 3 = 888 classes. Nếu bạn phải sử dụng nhiều màu hơn, ví dụ như color palette của [Material Design](https://material.io/design/color/the-color-system.html#tools-for-picking-colors), hỗ trợ nhiều thuộc tính và pseudo selector hơn, thêm vài breakpoints nữa, bạn cũng có thể đoán được số lượng class phình ra như thế nào.

Thực tế là không phải tất cả class màu đều được sử dụng, nên việc tạo ra class để bao gồm tất cả các trường hợp là không cần thiết. Cách giải quyết ở đây là chỉ viết thêm class khi bạn thật sự cần đến nó.

### Tìm và thay đổi class theo yêu cầu mới khó hơn

Giả sử một ngày đẹp trời nào đó, đồng chí Nguyễn Văn Xài Nơ quyết định nền màu xanh của tất cả các nút phải đậm hơn chút xíu, nút bự nghĩa là font size phải ở level 2\. Với BEM, bạn chỉ cần thay đổi giá trị của class .btn--green và .btn--big là xong. Trong khi đó bạn không thể đổi mã màu của .bg-green bởi vì thay đổi này chỉ áp dụng trên nút và biết đâu được màu cũ vẫn được dùng ở nơi khác. Bạn cũng không thể tuỳ tiện tăng font size của .f3. Giải pháp an toàn nhất là tìm tất cả các nút, xoá đi class cũ và thêm vào f2 bg-dark-green. Bạn tìm các nút bằng cách nào? Search and Replace… bg-green white br-5 ma-10 f3 -> bg-dark-green white br-5 ma-10 f2? Lỡ như có một class nào đó chen vào giữa bg-green white br-5 ma-10 letter-spacing-1 f3 và thế là tèn tén ten.

Nếu dự án của bạn sử dụng React, Vue, hay các thư viện hỗ trợ (web) component khác, việc thay đổi này không thành vấn đề. Còn với thuần HTML thì…coi bộ cực đó. Bạn có thể đặt tên cho UI component bằng data-, nhưng như vậy markup sẽ bị rối và ở phía người dùng, các thuộc tính này hoàn toàn không được dùng đến.

```html
<button
  data-ui-name="button-big-green"
  class="b1 b--green bg-green white br-5 ma-10 f3 ttu fw-400 padding-10"
>
  <span class="bg-dark o4 white padding-x-12 fw-600 br-left-5">$9.99</span>
  Purchase
</button>
```

### Nghi ngờ từ cộng đồng

Thành thật mà nói, atomic CSS rất không tự nhiên khi tiếp xúc lần đầu tiên. Chúng ta đã quá quen với cách viết CSS truyền thống/ BEM, và khi nhìn thấy một đống class đi chung với những cái tên xa lạ như ma, px, hay ttu, nghi ngờ là phản ứng rất dễ hiểu.

> **Vậy có khác gì inline style?**

Nhìn sơ qua thì đúng là giống như inline style vậy, và ai cũng biết inline style là bad practice. Nhưng atomic classes khác hoàn toàn và mạnh mẽ hơn inline style nhiều. Atomic classes cho phép bạn viết media queries, @support, pseudo selectors hay sử dụng animation, những điều mà inline style không làm được. Và vì atomic CSS được lưu trong tập tin CSS, trình duyệt có thể lưu vào bộ nhớ đệm, không giống như inline style.

> **Tên class thấy gớm**

Kiểu viết tắt ma (margin all), px (padding x), ph (padding horizontal) hay bg rất phổ biến trong cộng đồng atomic CSS. Ban đầu bạn có thể thấy khó hiểu và tốn thời gian để học, nhưng sau một thời gian chúng sẽ trở nên tự nhiên.

Ngoài ra còn một số ý kiến phản đối atomic CSS nữa mà nếu muốn, bạn có thể đọc bài viết [The Problem with Atomic CSS](https://medium.com/simple-human/the-problem-with-atomic-css-d0c09c7aa38e) rồi tự đưa ra nhận xét. Spoiler alert: không phải tất cả luận điểm trong bài đều hợp lý.

## Tích hợp vào dự án

Nếu bạn đọc đến đây và không cảm thấy atomic CSS là một ý tưởng dị hợm thì bài viết này coi như đã thành công. Để dùng atomic CSS trong dự án, bạn có thể chọn cách dùng các thư viện có sẵn, hoặc tự xây dựng thư viện riêng.

### Dùng hàng ăn sẵn

Cách này phù hợp với những dự án mới hoặc bạn muốn thử nghiệm với atomic CSS. Hiện tại thì hai thư viện phổ biến nhất là [Tachyons](http://tachyons.io/) và [Tailwind](http://tailwindcss.com/). Tachyons có lượng người dùng đông đảo vì xuất hiện trước, nhưng Tailwind lại mạnh mẽ hơn vì cho phép bạn thay đổi màu sắc, kích thước, v.v… hoàn toàn theo ý muốn. Không thì bạn có thể dùng hệ thống thiết kế của [StackOverflow](https://stackoverflow.design/product/guidelines/using-stacks#goals) hay [Heroku](https://design.herokai.com/purple3) cũng được.

Sự thật là các atomic classes quá nhỏ nên chúng gần như giống hệt nhau ở tất cả framework, có khác chăng chỉ là tên gọi mà thôi.

### Tự trồng

Trong một dự án đang chạy, nếu muốn áp dụng atomic CSS thì không gì tốt hơn là tự trồng lấy một framework. Các atomic classes rất nhỏ và đơn giản nên hoàn toàn không có gì khó để tự viết cả. Bạn có thể từ từ bóc tách các thuộc tính của các class cũ và chuyển chúng thành atomic classes. Dự án của bạn có thể sắp xếp các tập tin (S)CSS như thế này.

```scss
styles/utils/
├── _animation.scss
├── _background.scss
├── _border.scss
├── _box-shadow.scss
├── _color.scss
├── _cursor.scss
├── _display.scss
├── _flex.scss
├── _font-size.scss
├── _font-weight.scss
├── _height.scss
├── _letter-spacing.scss
├── _line-height.scss
├── _list.scss
├── _margin.scss
├── _max-width.scss
├── _padding.scss
├── _ratio.scss
├── _text-align.scss
└── _width.scss
```

Về việc đặt tên, bạn có thể chọn kiểu viết tắt px, ma hay ttu như trong Tachyons, hoặc kiểu đầy đủ padding-x, margin-all, text-transform-uppercase. Cái này tuỳ thuộc vào sở thích của từng team.

Ngoài ra, việc viết lặp đi lặp lại nhóm class có thể gây nhàm chán, do đó bạn đừng quên tận dụng các công cụ tiền xử lý CSS như SASS, LESS, hay Stylus để cuộc sống dễ thở hơn. Chẳng hạn như đoạn code dưới đây để tạo ra các class liên quan đến height:

```scss
$list: 28 96 128 640;

@each $value in $list {
  .h-#{$value} {
    height: #{$value}px;
  }
}
```

Khi cần thêm một giá trị mới, bạn chỉ cần bỏ nó vào $list. Bạn cũng có thể dùng mixin để tạo ra các class responsive:

```scss
@include media(extra-large) {
  $list: 28 96 128 640;

  @each $value in $list {
    .h-#{$value}-xl {
      height: #{$value}px;
    }
  }
}
```

## Kết

Nếu nhóm của bạn đang dùng BEM hay các phương pháp phát triển CSS khác và hài lòng với chúng, bạn có thể không cần atomic CSS. Atomic CSS không phải sinh ra là để triệt tiêu BEM, mà bổ sung và giúp bạn làm việc với CSS một cách hiệu quả hơn.

Cuối cùng, hãy xem video này và quyết định có nên xài atomic CSS không nhé ;)

<YouTube id="16W7c0mb-rE" />
]]></description>
            <link>https://hungvn.com/blog/gioi-thieu-ve-atomic-css</link>
            <guid isPermaLink="true">https://hungvn.com/blog/gioi-thieu-ve-atomic-css</guid>
            <pubDate>Sun, 06 Jan 2019 17:18:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P19: Bên trong custom element + thủ thuật xây dựng component tối ưu]]></title>
            <description><![CDATA[
**_Đây là bài cuối cùng trong series rồi (chắc vậy á, lâu nay không thấy họ đăng bài mới). Cảm ơn mọi người đã ủng hộ mình trong suốt thời gian qua. Tuy nhiên nếu SessionStack có bài viết nào mới thì mình sẽ cập nhật thêm._**

- Element: phần tử
- Custom element: phần tử tùy chọn (tức là những element do người dùng tự tạo ra)
- Component: thành phần

Chào các bạn đến với bài thứ 19 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

# Khái quát

Trong bài trước chúng ta đã thảo luận về Shadow DOM API và 1 vài ý tưởng vốn là các mảnh ghép của 1 bức tranh lớn hơn: web components. Toàn bộ ý tưởng đằng sau tiêu chuẩn **web components** là có thể mở rộng các tính năng sẵn có của HTML bằng cách tạo ra các element vừa nhỏ gọn, hướng mô đun và có thể tái sử dụng nhiều lần. Đây là 1 tiêu chuẩn tương đối mới trong W3C và đã được chấp nhận bởi đa số các trình duyệt lớn và có thể thấy nó xuất hiện trong nhiều môi trường production... dĩ nhiên là với 1 chút sự giúp đỡ từ các thư viện polyfill mà chúng ta sẽ nói sau.
\*\_Polyfill là để chỉ việc biến đổi, thay thế hoặc chỉnh sửa các tính năng mới của ngôn ngữ JS, HTML, CSS sao cho nó có thể hoạt động được trên các trình duyệt cũ như IE

Như các bạn đã biết, trình duyệt cung cấp cho chúng ta 1 số ít các công cụ quan trọng để xây dựng website và các webapp. Ta đang nói về HTML, CSS & Javascript. Bạn dùng HTML để kiến trúc nên app của bạn, CSS để trang điểm và làm cho nó đẹp hơn rồi dùng Javascript thực hiện các hành động khác. Tuy nhiên, trước khi **web components** được giới thiệu thì không có cách nào dễ dàng để liên kết các hành vi của Javascript đến với kiến trúc của HTML.

Trong bài viết này, chúng ta sẽ tìm hiểu về nền tảng của web component: **custom element**. Nói ngắn gọn, API custom element cho phép bạn tạo ra các custom HTML element với logic Javascript và CSS style tích hợp sẵn. Rất nhiều người cảm thấy bối rối nhầm lẫn custom element với Shadow DOM. Nhưng chúng là 2 ý tưởng hoàn toàn khác nhau và chúng thực sử bổ khuyết cho nhau thay vì thay thế lẫn nhau.

Một vài framework và library như Angular, React... cố giải quyết cùng 1 vấn đề bằng cách giới thiệu ý tưởng riêng của họ. Bạn có thể so sánh custom element với Angular directive hoặc React component. Tuy nhiên, custom element gần gũi với trình duyệt mà không yêu cầu gì hơn ngoài bản gốc của Javascript, HTML, CSS. Dĩ nhiên, điều này không có nghĩa rằng nó là bản thay thế cho các Javascript framework điển hình. Các framework hiện đại cho phép chúng ta thực hiện nhiều thứ hơn là chỉ giả lập hành vi của custom element. Vì thế mà chúng có thể cùng hoạt động bên cạnh nhau.

# API

Trước khi chúng ta đào sâu hơn thì hãy cùng duyệt qua những gì mà API cung cấp. Object global customElements sẵn có cho ta vài phương thức:

- define(tagName, constructor, options): Định nghĩa custom element mới. Nó nhận vào 3 đối số: 1 thẻ tên hợp lệ cho custom element, định nghĩa lớp cho custom element và 1 object options. Hiện tại thì chỉ có 1 option được hỗ trợ là extends, mang giá trị là 1 string chỉ định tên của element có sẵn để mở rộng. Thường được dùng để tạo ra các tùy biến của element sẵn có.
- get(tagName): Trả về constructor của 1 custom element nếu như element được định nghĩa và ngược lại thì trả về undefined. Nó nhận vào 1 đối số duy nhất: thẻ tên hợp lệ của custom element.
- whenDefined(tagName): Trả về 1 promise và được resolve khi custom element được định nghĩa. Nếu như element đã được định nghĩa rồi thì nó sẽ resolve ngay lập tức. Promise bị reject nếu như thẻ tên không phải là tên hợp lệ của custom element. Nó nhận vào 1 đối số: thẻ tên hợp lệ của 1 custom element.

# Cách tạo custom element

Tạo ra custom element rất đơn giản. Bạn chỉ cần làm 2 việc: định nghĩa 1 lớp cho element và cho nó extends từ lớp HTMLElement, việc thứ 2 là đăng ký tên cho element đó:

```javascript
class MyCustomElement extends HTMLElement {
  constructor() {
    super();
    // …
  }

  // …
}

customElements.define("my-custom-element", MyCustomElement);
```

Hoặc nếu muốn thì bạn có thể sử dụng anonymous class (lớp vô danh) trong trường hợp bạn muốn code gọn gàng hơn 1 chút:

```javascript
customElements.define(
  "my-custom-element",
  class extends HTMLElement {
    constructor() {
      super();
      // …
    }

    // …
  }
);
```

Như các bạn đã thấy, custom element được đăng ký bằng phương thức customElements.define(...)

# Custom element giải quyết vấn đề gì ?

Vậy chứ vấn đề ở đây là gì? **Div soups** chẳng hạn. Thế div soups là cái nồi gì? Thì rõ theo nghĩa đen thì nó là cái nồi súp thẻ div. Trong các ứng dụng webapp hiện đại thì đây là kiểu kiến trúc rất phổ biến khi ta có rất nhiều các thẻ div lồng nhau như thế này đây:

```html
<div class="top-container">
  <div class="middle-container">
    <div class="inside-container">
      <div class="inside-inside-container">
        <div class="are-we-really-doing-this">
          <div class="mariana-trench">…</div>
        </div>
      </div>
    </div>
  </div>
</div>
```

Kiểu kiến trúc như thế này thường được dùng vì nó bảo trình duyệt phải render những gì mà developer muốn. Nhưng nó lại làm cho code HTML khó đọc và rất khó bảo trì. Ví dụ chúng ta có 1 component trông như thế này:
![](https://cdn-images-1.medium.com/max/1000/0*v56OyrPtg_cZzzaZ)

Vậy thì theo cách cũ, HTML sẽ như thế này:

```html
<div class="primary-toolbar toolbar">
  <div class="toolbar">
    <div class="toolbar-button">
      <div class="toolbar-button-outer-box">
        <div class="toolbar-button-inner-box">
          <div class="icon">
            <div class="icon-undo">&nbsp;</div>
          </div>
        </div>
      </div>
    </div>
    <div class="toolbar-button">
      <div class="toolbar-button-outer-box">
        <div class="toolbar-button-inner-box">
          <div class="icon">
            <div class="icon-redo">&nbsp;</div>
          </div>
        </div>
      </div>
    </div>
    <div class="toolbar-button">
      <div class="toolbar-button-outer-box">
        <div class="toolbar-button-inner-box">
          <div class="icon">
            <div class="icon-print">&nbsp;</div>
          </div>
        </div>
      </div>
    </div>
    <div class="toolbar-toggle-button toolbar-button">
      <div class="toolbar-button-outer-box">
        <div class="toolbar-button-inner-box">
          <div class="icon">
            <div class="icon-paint-format">&nbsp;</div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
```

Tuy nhiên, tưởng tượng rằng chúng ta có thể làm như thế này:

```html
<primary-toolbar>
  <toolbar-group>
    <toolbar-button class="icon-undo"></toolbar-button>
    <toolbar-button class="icon-redo"></toolbar-button>
    <toolbar-button class="icon-print"></toolbar-button>
    <toolbar-toggle-button class="icon-paint-format"></toolbar-toggle-button>
  </toolbar-group>
</primary-toolbar>
```

Rõ ràng ví dụ thứ 2 nhìn sạch sẽ và gọn hơn nhiều. Dễ bảo trì, dễ đọc cho cả trình duyệt và developer. Đơn giản hơn nhiều.

Vấn đề tiếp theo là khả năng tái sử dụng. Công việc của developer chúng ta đòi hỏi không chỉ viết code hoạt động được mà còn phải bảo trì được. Và 1 điều làm cho code dễ bảo trì là nó có thể dễ dàng tái sử dụng 1 phần nào đó của code thay vì phải viết đi viết lại nhiều lần.

Dưới đây là 1 ví dụ đơn giản nhưng bạn sẽ hiểu ý tưởng của nó. Giả sử ta có element sau:

```html
<div class="my-custom-element">
  <input type="text" class="email" />
  <button class="submit"></button>
</div>
```

Nếu chúng ta cần sử dụng nó ở nơi nào khác thì ta sẽ phải viết lại đoạn HTML trên nhiều lần. Giả sử như ta cần thay đổi 1 phần nào đó và áp dụng cho mọi element. Ta sẽ phải đi tìm tất cả mọi nơi có đoạn code đó và chỉnh sửa chính xác cùng 1 thay đổi y chang nhau rất nhiều lần, bùm.....

Vậy thì không tốt hơn nếu ta chỉ cần như vậy thôi sao:

```html
<my-custom-element></my-custom-element>
```

Nhưng webapp hiện đại không chỉ có HTML tĩnh. Bạn cần tương tác với nó nữa. Và đây là lúc ta cần Javascript. Thường thì bạn sẽ tạo ra 1 vài element, ghép chúng vào bất kỳ event listener nào mà bạn muốn để cho nó có thể tương tác phản hồi khi có input từ người dùng. Bất kể là click, kéo-thả, hover, nhấn bàn phím, vân vân

```javascript
var myDiv = document.querySelector(".my-custom-element");

myDiv.addEventListener("click", _ => {
  myDiv.innerHTML = "<b> I have been clicked </b>";
});
<div class="my-custom-element">I have not been clicked yet.</div>;
```

Với API custom element, toàn bộ phần logic này có thể được đóng gói vào bên trong chính element đó. Xem ví dụ bên dưới

```javascript
class MyCustomElement extends HTMLElement {
  constructor() {
    super();

    var self = this;

    self.addEventListener("click", _ => {
      self.innerHTML = "<b> I have been clicked </b>";
    });
  }
}

customElements.define("my-custom-element", MyCustomElement);
<my-custom-element>I have not been clicked yet</my-custom-element>;
```

Mới đầu nhìn vào thì có vẻ như giải pháp custom element này đòi hỏi nhiều Javascript. Tuy nhiên trong các ứng dụng thực tế thì bạn sẽ hiếm khi gặp phải trường hợp mà bạn tạo ra 1 element mà không phải tái sử dụng nó. Một diều điển hình nữa trong các webapp hiện đại là đa số các element đều được tạo ra bằng code trong quá trình hoạt động (dynamic). Vì thế bạn cần phải xử lý các trường hợp riêng biệt khi element được thêm vào bằng Javascript hoặc nó được định nghĩa trước kia trong kiến trúc HTML. Bạn sẽ có toàn bộ những tính năng ấy nếu dùng custom element.

Tóm lại, custom element làm code bạn dễ hiểu, dễ bảo trì hơn, chia nhỏ nó thành các module khép kín nhỏ hơn, có thể tái sử dụng.

# Các yêu cầu

Trước khi bạn bắt đầu tạo custom element của chính mình, bạn nên biết rằng có 1 số quy tắc đặc biệt mà ta phải tuân theo:

- Tên **phải** chứa dấu gạch ngang (-). Bằng cách này bộ parser của HTML mới hiểu được element nào là do người dùng tạo ra và element nào là sẵn có. Nó cũng đảm bảo rằng không có xung đột khi đặt tên với các element sẵn có (bất kể bây giờ hay trong tương lai, khi một element mới được thêm vào). Ví dụ, `<my-custom-element>` là 1 tên hợp lệ trong khi `<myCustomElement>` và `<my_custom_element>` thì không.
- Không được đăng ký cùng 1 thẻ tên nhiều hơn 1 lần. Điều này sẽ làm cho trình duyệt bắn ra 1 biệt lệ DOMException. Bạn không thể ghi đè các custom element.
- Custom element không thể tự đóng thẻ. Bộ parser HTML chỉ cho phép 1 nhóm các element sẵn có có thể tự đóng thẻ của nó (ví dụ: `<img>`, `<link>`, `<br>`).

# Các khả năng

Vậy thì bạn thực sự có thể làm được gì với custom element? Và câu trả lời là: rất nhiều thứ.

Một trong số những tính năng tốt nhất là định nghĩa class của element thực sự liên kết đến chính DOM element của nó. Điều này có nghĩa bạn có thể dùng trực tiếp this với event listener, truy cập vào các property của nó, truy cập các node con và vân vân.

```javascript
class MyCustomElement extends HTMLElement {
  // ...

  constructor() {
    super();

    this.addEventListener("mouseover", _ => {
      console.log("I have been hovered");
    });
  }

  // ...
}
```

Dĩ nhiên là nó cho bạn khả năng để ghi đè lại node con của 1 element với nội dung mới. Và cũng dĩ nhiên là điều này không nên làm, bởi vì nó sẽ dẫn đến nhiều vấn đề không mong muốn. Rõ ràng nếu như bạn có 1 custom element đang hoạt động và đột nhiên phát hiện ra phần markup của element của mình bị thay đổi thì sẽ bối rối lắm.

Có 1 vài vị trí đặc biệt mà bạn có thể định nghĩa để thực thi code tại các thời điểm cụ thể trong vòng đời của element.

- constructor: constructor được gọi 1 lần khi element được tạo ra hoặc nâng cấp (chúng ta sẽ nói về nó sau). Đa số nó được dùng để khởi tạo state (trạng thái), gắn kết các event listener, tạo shadow DOM, vân vân. Lưu ý bạn hầu như cần phải gọi super() trong constructor.
- connectedCallback: phương thức connectedCallback được gọi mỗi lần element được thêm vào DOM. Nó có thể được dùng (khuyến nghị nên dùng) để delay (hoãn lại) vài việc cho đến khi element thực sự được gắn vào trang (chẳng hạn như lấy tài nguyên từ server).
- disconnectedCallback: tương tự như connectedCallback thì disconnectedCallback được gọi khi 1 element bị lấy ra khỏi DOM. Thường là để giải phóng tài nguyên. Lưu ý rằng disconnectedCallback không bao giờ được gọi nếu như user đóng tab. Hãy cẩn thận với những thứ mà bạn khởi tạo lúc đầu.
- attributeChangedCallback: phương thức này được gọi khi 1 attribute của element được thêm vào, gỡ ra, cập nhật hoặc thay thế. Nó cũng được gọi khi element được tạo ra bởi parser. Tuy nhiên, lưu ý rằng nó chỉ áp dụng cho các attribute nằm trong danh sách an toàn (whitelist) của property observedAttributes
- addoptedCallback: phương thức này được gọi khi document.adoptNote(...) được gọi để đưa đó sang 1 document khác.

Lưu ý rằng tất cả các callbacks ở trên đều là **đồng bộ**. Ví dụ, connectedCallback được gọi ngay lập tức sau khi element được thêm vào DOM và trong lúc đó không có gì xảy ra.

# Phản chiếu property

Các element HTML sẵn có cung cấp 1 khả năng rất tiện dụng: phản chiếu property. Nghĩa là các giá trị của 1 vài property được phản chiếu trực tiếp về DOM dưới dạng attribute. Một ví dụ điển hình là property id.

```javascript
myDiv.id = "new-id";
```

Cũng sẽ cập nhật DOM thành:

```html
<div id="new-id">...</div>
```

Và nó cũng áp dụng theo hướng ngược lại nữa. Phần này cực kỳ tiện lợi bởi vì nó cho phép bạn cấu hình các element khai báo.

Custom element không có tính năng như thế này nhưng có 1 cách để bạn tự triển khai. Ta có thể có được tính năng tương tự khi định nghĩa các getter & setter cho các property.

```javascript
class MyCustomElement extends HTMLElement {
  // ...

  get myProperty() {
    return this.hasAttribute("my-property");
  }

  set myProperty(newValue) {
    if (newValue) {
      this.setAttribute("my-property", newValue);
    } else {
      this.removeAttribute("my-property");
    }
  }

  // ...
}
```

# Mở rộng element

API custom element cho phép bạn không chỉ tạo ra các element HTML mà còn có thể mở rộng element sẵn có. Phương pháp này hoạt động cực tốt cho cả element sẵn có và custom element. Bạn chỉ cần mở rộng định nghĩa class của nó là được.

```javascript
class MyAwesomeButton extends MyButton {
  // ...
}

customElements.define("my-awesome-button", MyAwesomeButton);
```

Hoặc trong trường hợp của element có sẵn, ta cần thêm 1 param thứ 3 vào hàm customElements.define(...) - một object với property extends và giá trị là thẻ tên của element đang được mở rộng. Bằng cách này trình duyệt biết được chính xác thì element nào đang được mở rộng bởi vì có rất nhiều element sẵn có cùng chia sẻ giao diện DOM. Nếu không chỉ định element nào mà mình muốn mở rộng, trình duyệt sẽ không biết được chức năng nào đang được mở rộng.

```javascript
class MyButton extends HTMLButtonElement {
  // ...
}

customElements.define("my-button", MyButton, { extends: "button" });
```

Một element gốc mở rộng (extended native element) còn được gọi là element được tùy biến (customized built-in element).

Nguyên tắc vàng cho bạn đó là luôn luôn mở rộng các element đang tồn tại sẵn. Và làm việc này một cách dần dần. Nó cho phép bạn giữ lại tất cả các tính năng trước đó (property, attribute, các hàm).

Chú ý rằng element được tùy biến chỉ được hỗ trợ từ Chrome 67 trở lên. Nó sẽ được triển khai cho các trình duyệt khác ngoại trừ Safari.

# Nâng cấp element

Như đã nói ở trên, chúng ta sử dụng phương thức customElements.define(...) để đăng ký 1 custom element. Nhưng nó không có nghĩa rằng đó là việc đầu tiên bạn phải làm. Đăng ký custom element có thể được hoãn lại sau này. Kể cả sau khi chính element đó được thêm vào DOM. Quá trình này được gọi là nâng cấp element. Để giúp bạn biết được thực sự khi nào thì element được định nghĩa thì trình duyệt có cung cấp phương thức customElements.whenDefine(...). Bạn truyền thẻ tên của element vào, nó trả về 1 promise và sẽ được resolve khi element đăng ký xong.

```javascript
customElements.whenDefined("my-custom-element").then(_ => {
  console.log("My custom element is defined");
});
```

Ví dụ, khi bạn muốn delay 1 vài thứ cho đến khi tất cả các element con được định nghĩa xong, cực kỳ có ích khi mà bạn có các custom element lồng nhau. Thỉnh thoảng element cha sẽ dựa vào sự triển khai của các element con. Trong trường hợp này bạn cần đảm bảo rằng các element con được định nghĩa trước element cha.

# Shadow DOM

Như đã nói, custom element và shadow DOM đi đôi với nhau. Custom element được dùng để đóng gói logic Javascript vào bên trong 1 element trong khi shadow DOM được dùng để tạo ra 1 môi trường khép kín cho phần DOM không bị ảnh hưởng bởi các yếu tố bên ngoài. Mình đề nghị bạn nên đọc lại [bài viết trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-17---ben-trong-Shadow-DOM---xay-dung-component-khep-kin) để hiểu thêm về shadow DOM và các ý tưởng của nó.

Để sử dụng shadow DOM cho custom element, bạn chỉ cần đơn giản gọi this.attachShadow

```javascript
class MyCustomElement extends HTMLElement {
  // ...

  constructor() {
    super();

    let shadowRoot = this.attachShadow({mode: 'open'});
    let elementContent = document.createElement('div');
    shadowRoot.appendChild(elementContent);
  }

  // ...
});
```

# Template

Chúng ta đã tìm hiểu sơ về template trong [bài viết trước về shadow DOM](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-17---ben-trong-Shadow-DOM---xay-dung-component-khep-kin) và chúng xứng đáng có 1 bài viết riêng. Ở đây chúng ta sẽ đưa ra 1 ví dụ đơn giản làm thế nào để bạn có thể kết hợp các template vào quá trình tạo ra custom element. Sử dụng thẻ `<template>` bạn có thể khai báo thẻ của 1 mảnh DOM, một thứ được parse nhưng không được render trên trang.

```javascript
<template id="my-custom-element-template">
  <div class="my-custom-element">
    <input type="text" class="email" />
    <button class="submit"></button>
  </div>
</template>let myCustomElementTemplate = document.querySelector('#my-custom-element-template');

class MyCustomElement extends HTMLElement {
  // ...

  constructor() {
    super();

    let shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.appendChild(myCustomElementTemplate.content.cloneNode(true));
  }

  // ...
});
```

Giờ đây chúng ta có thể kết hợp custom element với shadow DOM và template, ta có được 1 element khép kín trong phạm vi của chính nó và có kiến trúc HTML riêng biệt cũng như Javascript logic

# Styling

Chúng ta đã đi qua phần của HTML & Javascript, giờ là về CSS. Rõ ràng thì ta cần 1 cách để chỉnh style cho các element. Chúng ta có thể thêm CSS stylesheet vào bên trong shadow DOM nhưng bạn sẽ thắc mắc là làm thế nào ta có thể chỉnh style của element từ bên ngoài với vai trò là 1 user của element đó. Và câu trả lời lại đơn giản: bạn cứ style nó giống như cách bạn làm với các element gốc.

```javascript
my-custom-element {
  border-radius: 5px;
  width: 30%;
  height: 50%;
  // ...
}
```

Lưu ý rằng style định nghĩa từ bên ngoài có độ ưu tiên cao hơn và nó sẽ ghi đè style định nghĩa từ element.

Bạn cũng biết có 1 số trường hợp khi trang được load nhưng nội dung trên trang vẫn ở dạng HTML thô và chưa được style (flash of unstyled content - FOUC). Bạn có thể ngăn chặn tình huống này bằng cách định nghĩa style cho các undefined component và sử dụng một số cách transition khi chúng được định nghĩa xong. Để làm như vậy ta cần dùng selector :defined

```javascript
my-button:not(:defined) {
  height: 20px;
  width: 50px;
  opacity: 0;
}
```

# Element không tồn tại (unknown) và custom element chưa định nghĩa (undefined)

Tiêu chuẩn HTML rất linh động và cho phép khai báo bất kỳ thẻ nào ta muốn. Nếu trình duyệt không thể nhận ra thẻ đó thì nó sẽ được parse dưới dạng HTMLUnknownElement.

```javascript
var element = document.createElement("thisElementIsUnknown");

if (element instanceof HTMLUnknownElement) {
  console.log("The selected element is unknown");
}
```

Tuy nhiên, điều này lại không áp dụng với custom element. Bạn có nhớ khi chúng ta bàn về việc có 1 số quy tắc đặt tên để định nghĩa custom element? Lý do là nếu như trình duyệt nhận ra tên **hợp lệ** cho 1 custom element thì nó sẽ parse nó dưới dạng HTMLElement và trình duyệt cân nhắc để trở thành custom element chưa định nghĩa.

```javascript
var element = document.createElement("this-element-is-undefined");

if (element instanceof HTMLElement) {
  console.log("The selected element is undefined but not unknown");
}
```

Mặc dù không có sự khác biệt nào có thể nhìn bằng mắt thường giữa HTMLElement và HTMLUnknownElement nhưng cũng có vài thứ mà ta cần phải nhớ. Parser sẽ đối xử với chúng khác nhau. Nếu một element có cái tên hợp lệ (theo kiểu custom element như đã nói ở trên) thì sẽ được kiểm tra xem nó có phần triển khai nào cho custom element không. Nó sẽ được đối xử như 1 div bình thường cho tới khi phần triển khai đó được định nghĩa. Ngược lại element chưa định nghĩa thì không triển khai bất kỳ phương thức hay property nào.

# Hỗ trợ từ trình duyệt

Phiên bản đầu tiên của custom element được giới thiệu trong Chrome 36+. Cái gọi là API v0 của custom element mà giờ đây đã không dùng nữa và cân nhắc rằng đó là những yếu kém mặc dù vẫn đang tồn tại. Nếu bạn muốn tìm hiểu về v0 thì có thể đọc [bài viết ở đây](https://www.html5rocks.com/en/tutorials/webcomponents/customelements/). API v1 của custom element xuất hiện kể từ Chrome 54 và Safari 10.1 (chỉ có 1 phần). Microsoft Edge thì đang trong giai đoạn thử mẫu và Mozilla đã có từ v50 những không được kích hoạt sẵn và cần người dùng tự kích hoạt nó. Hiện tại chỉ có các trình duyệt webkit mới hỗ trợ hoàn toàn. Tuy nhiên như đã nhắc ở trên, có các polyfill tồn tại cho phép bạn dùng custom element trên tất cả các trình duyệt, kể cả IE11.

# Kiểm tra tính khả dụng

Để đảm bảo trình duyệt có hỗ trợ custom element bạn có thể làm là thực hiện 1 bài kiểm tra nhỏ để xem property customElements có tồn tại trong object window hay không:

```javascript
const supportsCustomElements = "customElements" in window;

if (supportsCustomElements) {
  // Bạn có thể dùng API Custom elements ở đây
}
```

Hoặc nếu ta dùng thư viện polifyll:

```javascript
function loadScript(src) {
  return new Promise(function (resolve, reject) {
    const script = document.createElement("script");

    script.src = src;
    script.onload = resolve;
    script.onerror = reject;

    document.head.appendChild(script);
  });
}

// Chạy lazy load cho polyfill nếu cần thiết
if (supportsCustomElements) {
  // Trình duyệt hỗ trợ sẵn cho custom element. Bạn có thể dùng bình thường.
} else {
  loadScript("path/to/custom-elements.min.js").then(_ => {
    // Polyfill cho custom element đã được kích hoạt. Bạn có thể dùng bình thường.
  });
}
```

Vậy nói gọn gọn lại, 1 phần của tiêu chuẩn web component là custom element cho bạn các khả năng sau:

- Liên kết Javascript và CSS với HTML element
- Cho phép bạn mở rộng các element HTML sẵn có (cả element gốc và custom element)
- Không cần thư viện hay framework ngoài. Bạn chỉ cần Javascript, HTML và CSS gốc và có thể cần thêm thư viện polyfill để hỗ trợ trình duyệt cũ.
- Nó được xây dựng để hoạt động trơn tru, mượt mà với các tính năng khác của web component (shadow DOM, template, slots, vân vân)
- Liên kết chặt chẽ với công cụ dev của trình duyệt.
- Tận dụng các tính năng tiếp cận sẵn có.

Custom element không khác với những thứ chúng ta đã dùng bấy lâu nay. Nó chỉ là 1 cách khác để làm cho mọi việc dễ dàng hơn khi phát triển webapp. Nó mở ra cánh cổng đến với việc xây dựng những app phức tạp với tốc độ nhanh. Tuy nhiên càng phức tạp thì càng có nhiều khả năng có lỗi mà khó tìm hiểu hoặc tái lập. Vì thế khi debug ta cần nhiều ngữ cảnh và công cụ như SessionStack để hỗ trợ.

SessionStack tích hợp vào trong webapp và bắt đầu thu thập các thông tin như sự kiện người dùng, dữ liệu mạng, biệt lệ, thông báo debug, thay đổi trên DOM, vân vân, và gửi chúng về server của họ.

Sau đó, dữ liệu thu được sẽ được xử lý để tạo ra đoạn video trải nghiệm để bạn có thể xem user đã tương tác như thế nào với sản phẩm của bạn. Bên cạnh những thông tin kỹ thuật mà SessionStack đã cung cấp thì nó còn cho phép bạn khả năng để tái hiện lại các vấn đề mà bạn không bao giờ biết được khi debug trước đây.

Để đảm bảo cho SessionStack luôn luôn thực hiện được các phiên làm việc hoàn hảo đến từng pixel thì team của họ đã bám sát lấy những công nghệ, framework và tiêu chuẩn web tiên tiến cũng như mới nhất.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p19-ben-trong-custom-element-thu-thuat-xay-dung-component-toi-uu</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p19-ben-trong-custom-element-thu-thuat-xay-dung-component-toi-uu</guid>
            <pubDate>Sun, 06 Jan 2019 00:03:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P18: WebRTC & cơ chế mạng peer-to-peer]]></title>
            <description><![CDATA[
**_Thêm một bài nữa mang nặng kiến thức về mạng mà mình lại không chuyên về mảng này, nếu mình dịch chỗ nào không phù hợp thì nhờ mọi người giúp đỡ nhé @_@\_**

- **Peer-To-Peer hay P2P**: Mạng ngang hàng
- **Real-time**: thời gian thực

Chào các bạn đến với bài thứ 18 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

# Khái quát

Đầu tiên thì WebRTC là cái gì vậy? Nó là viết tắt của chữ **R**eal **T**ime **C**ommunication (Giao tiếp thời gian thực), nghe qua chắc bạn cũng đã có cái gì sơ sơ về công nghệ này rồi nhỉ.

WebRTC lấp đầy 1 khoảng trống lớn trong nền tảng web. Trước đây, các công nghệ P2P chẳng hạn như những app chat trên desktop có thể làm những việc mà web không làm được. Nhưng WebRTC đã thay đổi điều đó.

Về cơ bản WebRTC cho phép webapp có thể thiết lập giao tiếp Peer-To-Peer, chính là nội dung trong bài viết này. Ta sẽ thảo luận về các chủ đề sau đây để có thể mang đến cho bạn 1 cái nhìn toàn cảnh về "ruột gan phèo phổi" của WebRTC:

- Giao tiếp Peer-To-Peer
- Tường lửa và NAT Traversal
- Tín hiệu (Signaling), Phiên (Session), Giao thức (Protocol)
- Các API của WebRTC

# Giao tiếp Peer-To-Peer

Để có thể giao tiếp lẫn nhau thông qua trình duyệt web, mỗi trình duyệt của user phải thực hiện những bước sau đây:

- Đồng ý để bắt đầu giao tiếp
- Biết cách xác định vị trí của đối tượng
- Vượt qua an ninh và tưởng lửa bảo vệ
- Chuyển giao tất cả các giao tiếp đa phương tiện theo real-time

1 trong số những thách thức lớn nhất liên quan đến các giao tiếp P2P dựa trên trình duyệt là làm sao để biết vị trí & thiết lập 1 kết nối socket mạng (network socket connection) với 1 trình duyệt khác để vận chuyển dữ liệu 2 chiều. Ta sẽ xem xét những khó khăn liên quan đến việc thiết lập kết nối này.

Khi webapp của bạn cần dữ liệu hoặc tài nguyên, nó sẽ lấy về từ các server. Tuy nhiên, nếu bạn muốn tạo ra 1 ứng dụng video chat chẳng hạn, bằng cách kết nối trực tiếp đến trình duyệt của người khác - thì đây là vấn đề, vì bạn không biết địa chỉ bởi vì trình duyệt của người kia không phải là 1 web server. Vì vậy để có thể thiết lập 1 kết nối P2P ta cần rất nhiều thứ.

# Tường lửa và NAT Traversal

Thường thì máy tính của bạn không không có địa chỉ IP public tĩnh. Lý do là máy tính của bạn phải núp đằng sau tường lửa và thiết bị NAT (Network access translation - Bộ phiên dịch truy cập mạng).

Thiết bị NAT sẽ dịch địa chỉ IP cá nhân từ bên trong tường lửa thành địa chỉ IP công khai (public-facing IP). Ta cần các thiết bị NAT để bảo mật và giải quyết sự giới hạn của IPv4 đối với những địa chỉ IP công khai sẵn có. Đó là lý do tại sao webapp không nên giả định rằng thiết bị hiện tại có 1 địa chỉ IP public tĩnh.

Cùng tìm hiểu 1 chút về cách hoạt động của các thiết bị NAT. Nếu như bạn đang ở trong môi trường công cộng và kết nối vào mạng WiFi, máy tính của bạn sẽ được gán 1 địa chỉ IP mà nó chỉ tồn tại đằng sau NAT. Giả sử IP là 172.0.23.4, tuy nhiên, với thế giới bên ngoài, địa chỉ IP của bạn có thể mang giá trị khác, ví dụ 164.53.27.98. Vì vậy, thế giới bên ngoài sẽ thấy các request của bạn đến từ địa chỉ 164.53.27.98 nhưng thiết bị NAT sẽ đảm bảo các response cho những request (được gửi từ máy của bạn) sẽ trả về đúng chỗ là 172.0.23.4. Ơn trời các bảng ánh xạ (mapping table). Lưu ý rằng ngoài địa chỉ IP thì cổng (port) cũng là điều kiện cần thiết cho các giao tiếp mạng.

Do có sự tham gia của các thiết bị NAT, trình duyệt của bạn cần tìm được địa chỉ IP của máy tính có trình duyệt mà bạn muốn giao tiếp.

Đến đây thì ta lại phải nhờ đến các server **STUN** (**S**ession **T**raversal **U**tilities for **N**AT - Tiện ích truyền tải theo phiên cho NAT) và **TURN** (**T**raversal **U**sing **R**elays around **N**AT - Truyền tải sử dụng điểm chuyển tiếp vòng quanh NAT). Để các công nghệ WebRTC hoạt động được, đầu tiên thì 1 request hỏi địa chỉ IP public của bạn sẽ được gửi đến server STUN. Bạn cứ nghĩ theo hướng kiểu như máy tính đang tạo truy vấn đến 1 server từ xa để hỏi về địa chỉ IP mà server đó nhận câu truy vấn là bao nhiêu. Server từ xa sẽ trả về địa chỉ IP mà nó thấy. Nói ngắn gọn là máy tính của bạn "hỏi" 1 server từ xa địa chỉ IP của chính máy bạn là bao nhiêu.

Giả sử tiến trình này hoạt động bình thường và bạn nhận được địa chỉ IP public của mình cũng như số port, bạn sẽ có thể nói với những peer ngang hàng khác làm thế nào để kết nối trực tiếp đến bạn. Những peer này cũng có thể làm cùng 1 việc là sử dụng STUN & server TURN và nói cho bạn biết nên liên lạc đến địa chỉ nào.

# Signaling, Sessions, Protocols

**_Tín hiệu, phiên, giao thức_**

Quá trình khám phá thông tin mạng được mô tả ở trên chỉ là 1 phần của chủ đề về Signaling to bự hơn nhiều, trong trường hợp của WebRTC thì phần signaling này dựa trên 1 chuẩn JSEP (**J**avascript **S**ession **E**stablishment **P**rotocol - Giao thức thiết lập phiên của Javascript). Signaling bao gồm cả khám phá mạng (network discovery) và NAT Traversal, tạo và quản lý phiên, bảo mật giao tiếp, siêu dữ liệu (metadata) và phối hợp khả năng của media, xử lý lỗi.

Để kết nối có thể hoạt động, peer thu được những điều kiện về local media cho metadata (ví dụ: những khả năng về kích thước và kiểu codec) và gom góp các địa chỉ mạng có thể có cho host của ứng dụng. Cơ chế signaling dùng để truyền tới/lui những thông tin quan trọng này không được định nghĩa trong API của WebRTC.

Signaling không được quy định bởi chuẩn WebRTC và nó không được triển khai bằng API của nó để cho phép sử dụng một cách linh động các công nghệ và giao thức cần thiết. Các WebRTC developer sẽ đối phó với signaling và server xử lý signaling.

Giả sử app WebRTC dựa trên trình duyệt của bạn có thể xác định được địa chỉ IP public của nó bằng cách sử dụng STUN như đã nói ở trên, bước tiếp theo thực sự là 1 màn đàm phán & thiết lập phiên kết nối đến với peer.

Phần đàm phán và thiết lập khởi tạo phiên xảy ra khi dùng 1 giao thức signaling/giao tiếp được đặc tả trong các giao tiếp đa phương tiện. Giao thức này cũng chịu trách nhiệm cho việc điều hành các quy định trong đó phiên được quản lý và hủy bỏ.

Một trong số các giao thức như vậy có tên là **S**ession **I**nitiation **P**rotocol (SIP - Giao thức khởi tạo phiên). Lưu ý rằng do sự linh động của WebRTC signaling, SIP không phải là giao thức signaling duy nhất có thể dùng. Giao thức signaling được chọn phải hoạt động với 1 giao thức ở tầng ứng dụng gọi là **S**ession **D**escription **P**rotocol (SDP - Giao thức mô tả phiên), giao thức này được sử dụng trong trường hợp của WebRTC. Tất cả các metadata đa phương tiện cụ thể được truyền đi bằng giao thức SDP này.

Bất kỳ peer nào (ví dụ: app tận dụng WebRTC) thử giao tiếp với 1 peer khác đều sinh ra 1 tập các ứng viên giao thức Interactive Connectivity Establishment (ICE - Thiết lập kết nối tương tác). Những ứng viên này biểu diễn 1 bộ kết hợp của địa chỉ IP, port, giao thức giao vận được dùng. Lưu ý rằng 1 máy tính có thể có nhiều giao diện mạng (không dây, có dây, vân vân), vì thế có thể được gán nhiều địa chỉ IP cho mỗi giao diện.

Dưới đây là sơ đồ lấy từ MDN mô tả lại sự trao đổi:
![](https://cdn-images-1.medium.com/max/1000/0*SXRTlnVxy2-hE9ZX)

# Thiết lập kết nối

Mỗi peer đầu tiên phải thiết lập địa chỉ IP public như đã nói ở trên. "Kênh" (channel) dữ liệu signaling sau đó được tự động tạo ra để xác định các peer và hỗ trợ đàm phán peer-to-peer và thiết lập phiên.

Thế giới bên ngoài hoàn toàn không biết hoặc không thể truy xuất đến những "kênh" này và nó cũng yêu cầu 1 định danh duy nhất nếu muốn truy cập.

Lưu ý rằng, do sự linh động của WebRTC và cũng bởi tiến trình signaling không được cụ thể hóa trong các tiêu chuẩn, ý tưởng và cách thực hiện của "kênh" có thể sẽ có ít nhiều khác biệt tuy vào công nghệ sử dụng. Rõ ràng, 1 vài giao thức không cần đến cơ chế "kênh" mà vãn giao tiếp được.

Chúng ta sẽ giả sử rằng "kênh" được dùng trong việc triển khai cho các mục đích được nhắc tới ở bài viết này.

Một khi 2 hoặc nhiều peer đã cùng kết nối vào 1 "kênh" thì những peer đã có thể giao tiếp và trao đổi thông tin phiên. Tiến trình này về mặt nào đó thì tương tự như [mô hình publish/subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern). Về cơ bản, peer khởi tạo ban đầu sẽ gửi 1 "lời đề nghị" sử dụng 1 giao thức signaling chẳng hạn như Session Initiation Protocol (SIP - Giao thức khởi tạo phiên) và SDP. Người khởi tạo sẽ chờ để nhận được "câu trả lời" từ bất kỳ người nhận nào đã kết nối với "kênh".

Khi đã nhận được câu trả lời, 1 tiến trình diễn ra để xác định và trao đổi giao thức ứng viên ICE tốt nhất (Interactive Connectivity Establishment - Thiết lập kết nối tương tác) mà mỗi peer thu thập được. Một khi chọn được ứng viên ICE tối ưu thì về cơ bản sẽ có nhiều thứ theo sau đó được chấp nhận, bao gồm: những metadata cần thiết, các định tuyến mạng (địa chỉ IP và port) và các thông tin media thường dùng để giao tiếp với mỗi peer. Phiên mạng socket mạng giữa những peer sau đó được thiết lập hoàn chỉnh và kích hoạt. Tiếp đó, các luồng dữ liệu local và các endpoint kênh dữ liệu được tạo ra bởi mỗi peer, dữ liệu đa phương tiện cuối cùng được chuyển đi theo cả 2 đường sử dụng bất kỳ công nghệ giao tiếp 2 chiều nào.

Nếu như tiến trình đồng ý chấp nhận ứng viên ICE tốt nhất bị thất bại, thỉnh thoảng nguyên nhân là do tường lửa hoặc kỹ thuật NAT đang dùng, thì giải pháp dự phòng sau đó là sử dụng 1 server TURN dưới dạng 1 điểm chuyển tiếp thay thế. Tiến trình này về cơ bản sẽ dùng 1 server hoạt động như người trung gian và nó chuyển tiếp bất kỳ dữ liệu nào truyền qua lại giữa các peer. Lưu ý rằng đây không phải là giao tiếp peer-to-peer thực thụ trong đó các peer truyền dữ liệu 2 chiều trực tiếp đến với nhau.

Khi sử dụng giải pháp dự phòng TURN để giao tiếp, mỗi peer sẽ không cần phải biết làm thế nào để liên lạc và truyền dữ liệu đến bên kia. Thay vào đó, nó cần biết server TURN public nào để gửi và nhận dữ liệu đa phương tiện theo thời gian thực xuyên suốt phiên giao tiếp.

Điều quan trọng cần phải hiểu rằng đây chắc chẳn là 1 dạng "kế hoạch dự phòng" và chỉ dùng khi không còn cách nào khác. Các server TURN phải khá vững chắc, có băng thông rộng, khả năng xử lý và có thể xử lý 1 lượng lớn dữ liệu tiềm tàng. Cách sử dụng server TURN vì thế rõ ràng là sẽ phát sinh thêm chi phí và sự phức tạp.

# Các API của WebRTC

Có 3 mục phân loại API chính trong WebRTC:

- **Media Capture and Streams** (luồng media và chụp media) - cho phép bạn truy xuất vào các thiết bị đầu vào, chẳng hạn như microphone hay web camera. API cho phép bạn lấy 1 luồng media từ các thiết bị đó.
- **RTCPeerConnection** - dùng những API này, bạn có thể gửi theo thời gian thực 1 luồng âm thanh & hình ảnh đã bắt được thông qua internet đến 1 endpoint WebRTC khác. Bạn có thể tạo ra kết nối giữa máy local và peer từ xa. Nó cũng cung cấp các phương thức để kết nối đến 1 peer từ xa, duy trì và kiểm soát kết nối & đóng kết nối 1 khi ta không cần đến nó nữa.
- **RTCDataChannel** - API này cho phép bạn truyền dữ liệu tùy ý. Mỗi kênh dữ liệu được liên kết với 1 RTCPeerConnection.

Chúng ta sẽ đi sâu vào thảo luận mỗi loại trên.

## Media Capture & Streams

API **Media Capture & Streams**, thường được gọi là _Media Stream API_ hoặc _Stream API_, là 1 API hỗ trợ những luồng (stream) dữ liệu âm thanh hay hình ảnh, các phương thức để làm việc với chúng, những hạn chế liên kết với từng loại dữ liệu, callback thành công/thất bại khi sử dụng dữ liệu bất đồng bộ và những sự kiện được bắn ra suốt quá trình.

Phương thức getUserMedia() của [MediaDevices](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices) nhắc nhở người dùng cấp quyền để sử dụng đầu vào media, nó tạo ra 1 [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) kèm với các track chứa kiểu request của media. Luồng đó có thể chứa 1 track video (được tạo ra bởi phần cứng hay nguồn video ảo chẳng hạn như camera, thiết bị ghi video, dịch vụ chia sẻ màn hình, vân vân), 1 track audio (tương tự, được tạo ra bởi nguồn ghi vật lý hoặc nguồn ghi ảo như microphone, bộ chuyển A/D...) và có thể có cả những loại track khác.

Nó sẽ trả về 1 [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) và resolve thành object [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream). Nếu người dùng từ chối cấp quyền hoặc là media phù hợp không tồn tại thì promise đó sẽ bị reject với PermissionDeniedError hoặc NotFoundError.

Mô hình singleton MediaDevice có thể được truy xuất thông qua object navigator như sau:

```javascript
navigator.mediaDevices
  .getUserMedia(constraints)
  .then(function (stream) {
    /* use the stream */
  })
  .catch(function (err) {
    /* handle the error */
  });
```

Lưu ý là bạn cần truyền object constraints để nói cho API loại stream nào để trả về. Bạn có thể cấu hình tất cả những thứ linh tinh liên quan, bao gồm cả camera mà bạn dùng (camera trước/sau), tần suất khung hình, độ phân giải, vân vân.

Kể từ phiên bản 25, các trình duyệt dựa trên nhân Chromium cho phép dữ liệu âm thanh từ getUserMedia() có thể được truyền đến element audio hoặc video (nhưng lưu ý rằng mặc định thì các media element bị tắt tiếng (mute))

getUserMedia còn có thể được dùng như 1 [node đầu vào cho Web Audio API](http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled)

```javascript
function gotStream(stream) {
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  var audioContext = new AudioContext();
  // Tạo AudioNode từ stream
  var mediaStreamSource = audioContext.createMediaStreamSource(stream);
  // Kết nối nó đến điểm đích để nghe bạn
  // hoặc bất kỳ node nào khác đang xử lý
  mediaStreamSource.connect(audioContext.destination);
}

navigator.getUserMedia({ audio: true }, gotStream);
```

### Giới hạn về sự riêng tư

Là 1 API có thể chứa nhiều điều lo ngại đáng kể về quyền riêng tư, getUserMedia() được tổ chức bởi các đặc điểm kỹ thuật với những yêu cầu rất cụ thể về thông báo người dùng và quản lý quyền truy cập. getUserMedia() phải luôn luôn xin quyền từ người dùng trước khi mở bất kỳ thiết bị thu thập thông tin media nào chẳng hạn như webcam hay microphone. Trình duyệt có thể có tính năng cấp quyền trên mỗi domain (once-per-domain), nhưng nó phải hỏi bạn ít nhất là lần đầu tiên hoạt động và người dùng phải đặc biệt cấp quyền tiếp theo nếu họ muốn.

Một điều quan trọng tương đương là các quy định xung quanh thông báo (notification). Trình duyệt được yêu cầu phải hiển thị 1 thông số thể hiện camera hoặc microphone đang hoạt động, hơn hết thảy bất kỳ thông số thể hiện phần cứng nào khác. Họ cũng phải hiện 1 chỉ số cho thấy rằng quyền được được cấp để sử dụng thiết bị đầu vào, kể cả nếu như thiết bị đó chưa được kích hoạt để ghi chép tại thời điểm đó.

# RTCPeerConnection

Giao diện **RTCPeerConnection** thể hiện 1 kết nối WebRTC giữa máy tính local và peer từ xa. Nó cung cấp các phương thức để kết nối đến peer từ xa, duy trì, kiểm soát kết nối và ngắt kết nối một khi nó không cần dùng tới nữa.

Dưới đây là 1 mô hình kiến trúc của WebRTC thể hiện vai trò của RTCPeerConnection:
![](https://cdn-images-1.medium.com/max/1000/0*Nm9r_NLcAhJernmo)

Từ góc độ của Javascript, điều cần hiểu trong mô hình trên là **RTCPeerConnection** trao cho các web developer một cái nhìn tinh tế từ những sự phức tạp xuất phát từ đống "nội tạng" rối rắm bên dưới. Các mã codec và giao thức được dùng bởi WebRTC thực hiện 1 lượng lớn công việc dể làm cho giao tiếp real-time hoạt động được, kể cả với các mạng không đáng tin cậy:

- Che dấu mất gói tin (Package loss concealment - PLC, là 1 kỹ thuật dùng để che đậy ảnh hưởng của tình trạng mất gói tin trong giao tiếp VoIP)
- Hủy bỏ phản hồi (Echo cancellation - trong mạng máy tính thì "echo" được hiểu là quá trình gửi trả về gói tin đã gửi đi)
- Khả năng thích ứng băng thông
- Bộ đệm jitter động (jitter buffer - Trong kỹ thuật VoIP thì jitter buffer là vùng dữ liệu chia sẻ nơi mà các gói tin âm thanh có thể được thu thập, lưu trữ và gửi đi đến bộ xử lý âm thanh)
- Tự động chiếm quyền kiểm soát
- Giảm nhiễu và xóa nhiễu
- "Dọn dẹp" hình ảnh

# RTCDataChannel

Cũng như hình ảnh và âm thanh, WebRTC cũng hỗ trợ giao tiếp real-time cho các loại dữ liệu khác.

API RTCDataChannel cho phép peer-to-peer trao đổi các dữ liệu tùy ý.

Có rất nhiều trường hợp sử dụng API này, ví dụ:

- Dùng trong các game
- Ứng dụng chat real-time
- Truyền file
- Các mạng phi tập trung

API cũng có nhiều tính năng để tận dụng tối đa RTCPeerConnection và kích hoạt sức mạnh cũng như sự linh động của giao tiếp peer-to-peer:

- Tận dụng cài đặt phiên của RTCPeerConnection
- Đa kênh đồng thời với khả năng phân chia mức độ ưu tiên
- Ngữ cảnh vận chuyển đáng tin cậy và không đáng tin cậy.
- Tích hợp sẵn bảo mật (DTLS) và kiểm soát tắc nghẽn.

Cú pháp tương tự như WebSocket mà ta đã biết, với phương thức send() và sự kiện message:

```javascript
var peerConnection = new webkitRTCPeerConnection(servers, {
  optional: [{ RtpDataChannels: true }],
});

peerConnection.ondatachannel = function (event) {
  receiveChannel = event.channel;
  receiveChannel.onmessage = function (event) {
    document.querySelector("#receiver").innerHTML = event.data;
  };
};

sendChannel = peerConnection.createDataChannel("sendDataChannel", {
  reliable: false,
});

document.querySelector("button#send").onclick = function () {
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};
```

Sự giao tiếp diễn ra trực tiếp giữa các trình duyệt, vì thế RTCDataChannel có thể nhanh hơn nhiều so với WebSocket kể cả khi cần đến 1 server chuyển tiếp (TURN).

# WebRTC trong thế giới thực

Trong thế giới thực thì WebRTC cần có server, tuy nhiên thực tế lại đơn giản hơn:

- Các user tự khám phá ra đối tác của họ và trao đổi các chi tiết chẳng hạn như tên.
- Các ứng dụng WebRTC phía client (các peer) trao đổi thông tin mạng.
- Các peer trao đổi dữ liệu về media chẳng hạn như định dạng hình ảnh và độ phân giải.
- Các ứng dụng WebRTC phía client di chuyển xuyên qua các [cổng NAT](http://en.wikipedia.org/wiki/NAT_traversal) và tường lửa.

Nói cách khác, WebRTC cần phải có 4 tính năng ở phía server:

- User khám phá ra và giao tiếp.
- Signaling
- Di chuyển NAT/tường lửa
- Các server chuyển tiếp trong trường hợp giao tiếp peer-to-peer thất bại.

Giao thức [STUN](http://en.wikipedia.org/wiki/STUN) và bản mở rộng [TURN](http://en.wikipedia.org/wiki/Traversal_Using_Relay_NAT) của nó được dùng bởi [ICE](http://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment) để kích hoạt RTCPeerConnection nhằm đối phó với di chuyển NAT và các thay đổi mạng mơ hồ khác.

Như đã nhắc đến trước đó, ICE là 1 giao thức để kết nối các peer, chẳng hạn như 2 ứng dụng video chat client. Khi khởi tạo, ICE sẽ thử kết nối trực tiếp đến các peer với độ trễ thấp nhất có thể thông qua UDP. Trong tiến trình này, các server STUN có 1 tác vụ duy nhất: kích hoạt 1 peer phía sau NAT để tìm địa chỉ public & số port. Bạn có thể kiểm tra các server STUN đang tồn tại ở danh sách này (Google cũng có 1 số server)

| | # source : http://code.google.com/p/natvpn/source/browse/trunk/stun_server_list |
| | # A list of available STUN server. |
| | |
| | stun.l.google.com:19302 |
| | stun1.l.google.com:19302 |
| | stun2.l.google.com:19302 |
| | stun3.l.google.com:19302 |
| | stun4.l.google.com:19302 |
| | stun01.sipphone.com |
| | stun.ekiga.net |
| | stun.fwdnet.net |
| | stun.ideasip.com |
| | stun.iptel.org |
| | stun.rixtelecom.se |
| | stun.schlund.de |
| | stunserver.org |
| | stun.softjoys.com |
| | stun.voiparound.com |
| | stun.voipbuster.com |
| | stun.voipstunt.com |
| | stun.voxgratia.org |
| | stun.xten.com |

[view raw](https://gist.github.com/zziuni/3741933/raw/212e4b6316110dc5c128d08f65ff8f174d7ae383/stuns) [stuns](https://gist.github.com/zziuni/3741933#file-stuns) hosted with ❤ by [GitHub](https://github.com).
![](https://cdn-images-1.medium.com/max/1000/1*ONNxJHqmMTXB1Nuq3qTNXQ.png)

## Tìm những ứng viên kết nối

Nếu như UDP thất bại, ICE sẽ thử TCP: đầu tiên là HTTP, sau đó là HTTPS. Nếu kết nối trực tiếp thất bại - cụ thể là bởi vì dịch chuyển NAT & tường lửa mức độ doanh nghiệp - ICE sẽ dùng 1 server TURN trung gian (điểm chuyển tiếp). Nói cách khác, ICE đầu tiên sẽ dùng STUN với UDP để kết nối trực tiếp các peer với nhau, nếu thất bại, nó sẽ đổi kế hoạch sang dùng server chuyển tiếp TURN. Cụm từ "tìm kiếm ứng viên" nhắc đến quá trình tìm kiếm các giao diện mạng & port.
![](https://cdn-images-1.medium.com/max/1000/1*0REL14sYPR34hY7yua6-PA.png)

# Bảo mật

Có rất nhiều cách mà 1 ứng dụng hoặc plugin giao tiếp real-time có thể bị ảnh hưởng về bảo mật. Ví dụ:

- Dữ liệu hoặc media không được mã hóa có thể bị chặn trên đường đi giữa các trình duyệt hay giữa trình duyệt và server
- Một ứng dụng có thể ghi chép và phân phối âm thanh, hình ảnh mà user hoàn toàn không biết
- Malware hoặc virus máy tính có thể được cài đặt cùng với 1 ứng dụng hoặc plugin vớ vẩn.

WebRTC có nhiều tính năng để tránh các vấn đề trên:

- WebRTC triển khai sử dụng các giao thức bảo mật chẳng hạn như [DTLS](http://en.wikipedia.org/wiki/Datagram_Transport_Layer_Security) và [SRTP](http://en.wikipedia.org/wiki/Secure_Real-time_Transport_Protocol)
- Mã hóa là điều cần thiết đối với tất cả các component của WebRTC, bao gồm cả cơ chế signaling.
- WebRTC không phải là 1 plugin: các component của nó chạy trong sandbox của trình duyệt và không chạy ở luồng riêng, các component không yêu cầu cài đặt riêng lẻ và được cập nhật mỗi khi trình duyệt được cập nhật.
- Truy xuất camera và microphone phải được cấp quyền rõ ràng và khi camera hoặc microphone đang hoạt động thì phải được thể hiện ra ở phía giao diện người dùng.

WebRTC là 1 công nghệ cực kỳ thú vị & mạnh mẽ dành cho các sản phẩm cần làm việc với mô hình truyền tải real-time giữa các trình duyệt.

Ví dụ, ở SessionStack, họ cho phép user tích hợp thư viện Javascript của họ vào bên trong webapp của user. Nhiệm vụ của nó là bắt đầu thu thập các dữ liệu như sự kiện người dùng, thay đổi trên DOM, dữ liệu mạng, biệt lệ, thông báo debug, vân vân, và gửi chúng về cho server.

Trong khi đó, user của bạn có thể vào trong webapp của họ, mở 1 phiên làm việc bình thường và xem nó hoạt động theo thời gian thực. Sử dụng các dữ liệu thu thập được, SessionStack có thể tái tạo mọi thứ đã từng xảy ra trên trình duyệt của user, kết hợp các thông tin về hình ảnh thuần túy với 1 bộ giả lập console của trình duyệt và mọi thứ bên trong nó. Bạn cứ nghĩ nó giống như desktop từ xa nhưng không bắt người dùng cuối phải tải về bất cứ chương trình nào. Và trên hết tất cả các thông tin hình ảnh, bạn có thể thực sự thấy được các thông tin kỹ thuật lấy từ phiên.

Họ đã làm được tất cả điều đó thuần túy với các server, tuy nhiên sử dụng WebRTC họ có thể thật sự không cần phụ thuộc vào server nữa mà giao tiếp trực tiếp giữa các trình duyệt với nhau, giảm độ trễ và sức mạnh tính toán cần thiết.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p18-webrtc-co-che-mang-peer-to-peer</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p18-webrtc-co-che-mang-peer-to-peer</guid>
            <pubDate>Sun, 06 Jan 2019 00:00:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P17: Bên trong Shadow DOM + xây dựng component khép kín]]></title>
            <description><![CDATA[
**_Trong bài có nhiều từ mình để nguyên mà không dịch nhé, vì dịch ra thì bay mất nghĩa @_@\_**

- **element**: phần tử
- **custom element**: phần tử tự tạo
- **component**: thành phần
- **custom component**: thành phần tự tạo
- **markup**: nói chung là ngôn ngữ đánh dấu, hay nói dễ hiểu hơn là code HTML (Hyper Text **Markup** Language)

Chào các bạn đến với bài thứ 17 trong series khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

# Khái quát

Web Components (Thành phần web) là 1 bộ các công nghệ khác nhau cho phép ta tạo ra những custom element có thể tái sử dụng. Tính năng của chúng được đóng gói tách hoàn toàn khỏi code và bạn có thể dùng nó trong webapp của mình.

Có 4 loại Web Component tiêu chuẩn:

- Shadow DOM (Bóng của DOM)
- HTML Templates (các mẫu HTML)
- Custom elements (Các custom element)
- HTML Imports

Trong bài này ta sẽ tập trung vào **Shadow DOM**

Shadow DOM được thiết kế như 1 công cụ dùng để xây dựng các app dựa trên component. Nó cung cấp các giải pháp cho các vấn đề chung trong ngành phát triển web mà bạn chắc chắn đã gặp qua:

- **Isolated DOM (DOM cô lập)**: 1 DOM của component khép kín (ví dụ: document.querySelector() không trả về các node trong Shadow DOM của component). Điều này cũng làm đơn giản hóa các CSS Selector trong webapp của bạn bởi vì các DOM component đều bị cô lập, nó cho phép bạn khả năng sử dụng chung nhiều id/class mà không lo bị xung đột về cách đặt tên.
- **Scoped CSS (CSS trong phạm vi)**: CSS định nghĩa bên trong Shadow DOM chỉ có phạm vi trong nó. Các quy tắc về style không lọt ra ngoài và style của trang cũng không can thiệp vào nó.
- **Composition (kết hợp)**: Thiết kế 1 API khai báo, dựa trên markup cho component của bạn.

# Shadow DOM

Bài viết này giả định rằng bạn đã quen thuộc với các khái niệm và API về DOM. Nếu bạn chưa rõ thì có thể đọc bài viết chi tiết về nó ở đây: [https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction)

Shadow DOM cũng chỉ là 1 DOM bình thường, ngoại trừ 2 điều sau:

- Cách tạo ra/sử dụng trong mối quan hệ với toàn bộ trang so với cách mà bạn tạo/sử dụng DOM thường.
- Cách tương tác của nó trong mối quan hệ với toàn bộ trang

Một cách tổng quát, bạn tạo ra các node DOM và nối (append) chúng dưới dạng children vào element khác. Trong trường hợp của Shadow DOM, bạn tạo ra 1 cây DOM trong phạm vi (scoped DOM) và được kết nối vào element tuy nhiên nó tách biệt với children của chính nó. Cây con trong phạm vi này được gọi là **shadow tree**. Element mà nó nối vào được gọi là **shadow host**. Bất cứ thứ gì bạn thêm vào shadow tree trở thành 1 phần local của element chủ, bao gồm cả `<style>`. Đây là cách mà Shadow DOM có được phạm vi của CSS style.

# Tạo Shadow DOM

Một **shadow root** là 1 phần của document và được nối vào 1 element chủ (host element). Thời điểm bạn nối 1 shadow root chính là lúc element có được shadow DOM của nó. Để tạo shadow DOM cho 1 element, ta gọi element.attachShadow():

```javascript
var header = document.createElement("header");
var shadowRoot = header.attachShadow({ mode: "open" });
var paragraphElement = document.createElement("p");

paragraphElement.innerText = "Shadow DOM";
shadowRoot.appendChild(paragraphElement);
```

Phần [thông số kỹ thuật](http://w3c.github.io/webcomponents/spec/shadow/#h-methods) này định nghĩa 1 danh sách các element mà shadow tree **không thể** nối vào.

# Tính kết hợp trong Shadow DOM

Tính kết hợp là 1 trong số những tính năng quan trọng nhất của Shadow DOM.

Khi viết code HTML, "kết hợp" là cách mà bạn xây dựng webapp. Bạn kết nối và cài đặt các viên gạch khác nhau (còn gọi là các element) chẳng hạn như `<div>`, `<header>`, `<form>`, vân vân, để xây dựng UI cho webapp. Một số tag thậm chí có thể hoạt động với nhau.

Sự kết hợp định nghĩa tại sao các element như `<select>`, `<form>`, `<video>`... lại linh động và chấp nhận các element HTML cụ thể làm children của nó để thực hiện các công việc đặc biệt.

Ví dụ, `<select>` biết cách render các element `<option>` thành 1 danh sách dropdown với các item được định nghĩa trước.

Shadow DOM giới thiệu các tính năng sau mà từ đó ta có thể thực hiện tính "kết hợp".

# Light DOM (DOM nhẹ)

Đây là đoạn markup mà user của component của bạn viết ra. DOM này tồn tại bên ngoài Shadow DOM của component. Nó là một children thực của element. Tưởng tượng rằng bạn đã tạo ra 1 custom component có tên `<extended-button>` có thể mở rộng button mặc định của HTML và bạn muốn thêm 1 bức hình, thêm vài đoạn text bên trong nó, thì dưới đây là những gì mà nó nên có:

```html
<extended-button>
  <!-- thẻ img và span là Light DOM của extended-button -->
  <img src="boot.png" slot="image" />
  <span>Launch</span>
</extended-button>
```

extended-button là component tùy chọn mà bạn định nghĩa, đoạn HTML bên trong nó được gọi là **Light DOM** và được thêm vào bởi user của component của bạn.

Shadow DOM ở đây chính là component mà bạn đã tạo ra (tức là `<extended-button>`). Với component thì Shadow DOM là local, nó định nghĩa cho chính bản thân nó cấu trúc nội bộ, CSS trong phạm vi và đóng gói toàn bộ các chi tiết về triển khai.

# Flattened DOM tree (Cây DOM phẳng)

Kết quả của trình duyệt khi phân phối Light DOM - một sản phẩm được tạo ra bởi user và đặt vào trong Shadow DOM của bạn cùng với phần định nghĩa của custom component, sẽ render ra sản phẩm cuối cùng. Cây phẳng (flattened tree) là những gì sau cuối mà bạn thấy trong DevTools và được render trên trang.

```html
<extended-button>
  #shadow-root
  <style>
    …
  </style>
  <slot name="image">
    <img src="boot.png" slot="image" />
  </slot>
  <span id="container">
    <slot>
      <span>Launch</span>
    </slot>
  </span>
</extended-button>
```

# Templates

Khi bạn phải tái sử dụng liên tục 1 vài đoạn markup nào đó trên trang web, cách tốt hơn là ta sử dụng 1 kiểu template hơn là cứ lặp đi lặp lại cùng 1 cấu trúc đó hết lần này đến lần khác. Trước đây vẫn làm được điều này nhưng bây giờ thì dễ hơn nhiều với element HTML `<template>` hỗ trợ sẵn bởi rất nhiều trình duyệt hiện đại. Element này và nội dung của nó không được render trên DOM nhưng nó vẫn có thể tham chiếu đến bằng Javascript.

Cùng xem 1 ví dụ đơn giản nào:

```html
<template id="my-paragraph">
  <p>Paragraph content.</p>
</template>
```

Đoạn code đó sẽ không hiển thị trên trang của bạn trừ khi bạn tham chiếu đến nó bằng Javascript và nối nó vào DOM bằng 1 cách nào đó, chẳng hạn như:

```javascript
var template = document.getElementById("my-paragraph");
var templateContent = template.content;
document.body.appendChild(templateContent);
```

Giờ đây, để đạt được cùng 1 mục đích chung thì có nhiều kỹ thuật khác nhau để lựa chọn nhưng như đã đề cập trước đây, sẽ dễ dàng hơn nhiều nếu như các kỹ thuật đó được hỗ trợ natively. template được các trình duyệt hỗ trợ khá tốt (trừ IE)

![](https://cdn-images-1.medium.com/max/1000/0*3SRCEtv7rMhWpB5s)

Tự bản thân template đã rất có ích rồi, nhưng nó còn hoạt động tốt hơn nữa với các custom element. Chúng ta sẽ định nghĩa vài custom element trong 1 bài viết khác, còn bây giờ, trong lúc này thì bạn nên biết là có 1 API customElement trên trình duyệt cho phép chúng ta định nghĩa thẻ (tag) riêng của ta với các tùy chọn render.

Giờ ta sẽ định nghĩa 1 web component sử dụng template trên làm nội dung cho Shadow DOM, chúng ta gọi nó là `<my-paragraph>`:

```javascript
customElements.define(
  "my-paragraph",
  class extends HTMLElement {
    constructor() {
      super();

      let template = document.getElementById("my-paragraph");
      let templateContent = template.content;
      const shadowRoot = this.attachShadow({ mode: "open" }).appendChild(
        templateContent.cloneNode(true)
      );
    }
  }
);
```

Điểm then chốt cần chú ý ở đây là chúng ta nối 1 bản sao của nội dung template vào shadow root - thứ được tạo ra bằng phương thức [Node.cloneNode()](https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode)

Và bởi vì ta nối nội dung của nó với 1 Shadow DOM nên ta có thể đưa thêm 1 vài thông tin về style bên trong template với element [`<style>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/style), sau đó phần style này sẽ được đóng gói bên trong custom element. Phần này sẽ không hoạt động nếu ta chỉ nối nó vào 1 DOM bình thường.

Ví dụ ta đổi template thành như sau:

```html
<template id="my-paragraph">
  <style>
    p {
      color: white;
      background-color: #666;
      padding: 5px;
    }
  </style>
  <p>Paragraph content.</p>
</template>
```

Giờ thì component tùy chọn ta đã định nghĩa với template trên có thể được dùng như thế này:
`<my-paragraph></my-paragraph>`

# Slots (khe trống)

Templates có một vài nhược điểm, 1 trong số đó là nội dung của nó thuộc loại "tĩnh", không cho phép ta render kèm theo các dữ liệu hoặc biến để làm cho nó hoạt động theo cách bình thường như các template HTML tiêu chuẩn mà ta thường sử dụng.

Và đây là lúc mà `<slot>` xuất hiện.

Bạn có thể tưởng tượng rằng slots giống như người giữ chỗ, nó cho phép bạn đặt HTML riêng của mình vào trong template. Nó giúp cho bạn tạo ra các template HTML linh động hơn, dễ tùy biến hơn bằng cách thêm vào nhiều slot.

Viết lại template ở phần trên với slot:

```html
<template id="my-paragraph">
  <p>
    <slot name="my-text">Default text</slot>
  </p>
</template>
```

Nếu như nội dung của slot không được định nghĩa khi element được đính kèm theo markup, hoặc nếu như trình duyệt không hỗ trợ slot thì `<my-paragraph>` sẽ chỉ hiện dòng nội dung backup "Default text".

Để định nghĩa nội dung slot, ta cần đính kèm 1 cấu trúc HTML bên trong element `<my-paragraph>` với thuộc tính [slot](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-slot) và gán giá trị của nó với name của slot mà ta muốn nó truyền vào.

Giống như code dưới đây:

```html
<my-paragraph>
  <span slot="my-text">Let's have some different text!</span>
</my-paragraph>
```

Các element có thể được chèn vào trong slot được gọi là [Slotable](https://developer.mozilla.org/en-US/docs/Web/API/Slotable); khi 1 element được chèn vào trong slot thì ta nói nó đã bị slotted.

Để ý rằng ví dụ trên chúng ta đã chèn 1 element `<span>` vào, nó chính là slotted element. Nó có 1 thuộc tính slot giá trị bằng my-text - cùng giá trị với thuộc tính name trong phần định nghĩa của slot ở template.

Sau khi được render trên trình duyệt, đoạn code trên sẽ tạo ra 1 cây Flattened DOM như sau:

```html
<my-paragraph>
  #shadow-root
  <p>
    <slot name="my-text">
      <span slot="my-text">Let's have some different text!</span>
    </slot>
  </p>
</my-paragraph>
```

Lưu ý đến phần tử #shadow-root - nó xuất hiện như 1 chỉ thị rằng Shadow DOM đang tồn tại ở đây.

# Styling

Một component sử dụng Shadow DOM có thể được tùy chỉnh style từ trang chính, có thể định nghĩa style của riêng nó hoặc cung cấp hook dưới dạng [thuộc tính tùy chỉnh CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables) để user có thể ghi đè những thiết lập mặc định.

## Định nghĩa style cho component

**Scoped CSS** (CSS trong phạm vi) là 1 trong số các tính năng tuyệt vời nhất của Shadow DOM:

- Các CSS selector từ trang bên ngoài sẽ không áp dụng được vào bên trong component của bạn
- Các style định nghĩa bên trong component sẽ không ảnh hưởng đến toàn bộ trang. Chúng được đóng gói trong phạm vi của element chủ.

Các CSS selector được dùng bên trong Shadow DOM áp dụng với component một cách cục bộ. Trong thực tiễn thì điều này nghĩa là ta có thể dùng nhiều lần các tên id/class phổ biến mà không cần lo về sự xung đột giữa chúng trên trang. CSS selector càng đơn giản thì càng có hiệu năng tốt hơn.

Giờ ta cùng xem 1 đoạn #shadow-root dưới đây định nghĩa style:

```html
#shadow-root
<style>
  #container {
    background: white;
  }
  #container-items {
    display: inline-flex;
  }
</style>

<div id="container"></div>
<div id="container-items"></div>
```

Tất cả style ở ví dụ trên đều nằm trong vùng local của #shadow-root

Bạn có thể dùng element `<link>` để chèn thêm stylesheets ở ngoài vào trong #shadow-root và nó cũng sẽ thuộc về vùng local.

# pseudo-class :host

_Ai chưa biết về pseudo-class thì có thể tham khảo ở đây: [https://www.w3schools.com/css/css_pseudo_classes.asp](https://www.w3schools.com/css/css_pseudo_classes.asp)_

:host cho phép bạn chọn và chỉnh style cho element làm host (chủ) của shadow tree:

```css
<style>
  :host {
    display: block; /* mặc định thì các custom element có thuộc tính display: inline */
  }
</style>
```

Có 1 điều bạn cần phải cẩn thận khi sử dụng :host: phần định nghĩa :host trong các trang cha (parent) sẽ có ưu tiên cao hơn định :host định nghĩa trong element. Điều này cho phép người dùng có thể ghi đè phần định nghĩa style cao nhất từ bên ngoài. Bên cạnh đó, :host chỉ hoạt động trong ngữ cảnh của 1 shadow root, vì vậy bạn không thể dùng nó bên ngoài Shadow DOM.

Dạng function `:host(<selector>)` cho phép bạn trỏ trực tiếp đến host nếu nó khớp với 1 `<selector>`. Đây là 1 cách rất tuyệt vời để component của bạn có thể đóng gói các hành vi phản hồi đến các tương tác hoặc trạng thái người dùng và chỉnh style cho các node bên trong dựa trên host:

```css
<style>
  :host {
    opacity: 0.4;
  }

  :host(:hover) {
    opacity: 1;
  }

  :host([disabled]) { /* style khi host có thuộc tính disabled */
    background: grey;
    pointer-events: none;
    opacity: 0.4;
  }

  :host(.pink) > #tabs {
    color: pink; /* tô màu cho node #tabs khi host có class="pink" */
  }
</style>
```

# Dựng chủ đề (theme) và element với pseudo-class `:host-context(<selector>)`

Pseudo-class `:host-context(<selector>)` khớp host element nếu nó hoặc bất kỳ element cha (ancestor) nào của nó khớp với `<selector>`.

Một ví dụ phổ biến cho trường hợp này là làm việc với chủ để (theming). Thực tế là có rất nhiều người khi làm theme đều thêm class vào thẻ `<html>` hoặc `<body>`:

```html
<body class="lightheme">
  <custom-container> … </custom-container>
</body>
```

`:host-context(.lightheme)` sẽ chỉnh style cho `<fancy-tabs>` khi nó là con cháu (descendant) của `.lightheme`:

```css
:host-context(.lightheme) {
  color: black;
  background: white;
}
```

:host-context() có thể có ích cho theming nhưng có 1 cách khác còn tốt hơn nữa, đó là định nghĩa 1 style hooks sử dụng các thuộc tính custom của CSS, bạn có thể xem ở đây: [https://developers.google.com/web/fundamentals/web-components/shadowdom#stylehooks](https://developers.google.com/web/fundamentals/web-components/shadowdom#stylehooks)

# Chỉnh style cho host element của component từ bên ngoài

Bạn có thể chỉnh style cho host element của component từ bên ngoài vào bằng cách dùng tag name của nó như 1 selector, kiểu vậy nè:

```css
custom-container {
  color: red;
}
```

Style bên ngoài có mức ưu tiên cao hơn style định nghĩa bên trong Shadow DOM.

Ví dụ, nếu user viết 1 selector như sau:

```css
custom-container {
  width: 500px;
}
```

...thì nó sẽ ghi đè lên rule của component:

```css
:host {
  width: 300px;
}
```

Tức là width lúc này có giá trị 500px

Styling chính component thì chỉ có thể đến mức này thôi. Vậy nếu bạn muốn style các thành phần sâu hơn bên trong của component thì sao? Ta sẽ cần đến các thuộc tính custom của CSS.

# Tạo style hook sử dụng thuộc tính custom của CSS

User có thể dùng mẹo để chỉnh style cho các thành phần bên trong nếu như tác giả của component đó có cung cấp styling hook sử dụng [thuộc tính custom của CSS](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables).

Ý tưởng tương tự với `<slot>` nhưng áp dụng cho style.

Cùng xem ví dụ bên dưới:

```html
<!-- main page -->
<style>
  custom-container {
    margin-bottom: 60px;
    - custom-container-bg: black;
  }
</style>

<custom-container background>…</custom-container>
```

bên trong Shadow DOM của nó:

```css
:host([background]) {
  background: var( - custom-container-bg, #cecece);
  border-radius: 10px;
  padding: 10px;
}
```

Trong trường hợp này, component sẽ sử dụng màu black làm giá trị cho background bởi vì user muốn thế. Nếu không thì nó sẽ dùng giá trị mặc định là #CECECE.

Nếu là tác giả của component, bạn có trách nhiệm cho developer biết về những thuộc tính custom của CSS mà họ có thể sử dụng. Hãy xem như đó là luật bất thành văn khi public một component.

# Javascript API cho slot

Shadow DOM API cung cấp nhiều tiện ích hữu dụng để làm việc với slot

## Sự kiện slotchange

Sự kiện slotchange được bắn ra khi node phân phối của slot bị thay đổi. Ví dụ, nếu user thêm/bớt children từ light DOM.

```javascript
var slot = this.shadowRoot.querySelector("#some_slot");
slot.addEventListener("slotchange", function (e) {
  console.log("Light DOM change");
});
```

Để kiểm soát các kiểu thay đổi khác trên light DOM, bạn có thể dùng MutationObserver trong constructor của element. Chúng ta đã từng thảo luận về nó trong [Phần 10](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-10---Quan-sat-thay-doi-tren-DOM-bang-MutationObserver) rồi.

## Phương thức assignedNodes()

Sẽ rất có ích khi biết rằng các element có liên kết với slot. Gọi `slot.assignedNodes()` sẽ cho phép bạn biết những element nào mà slot render. Option `{flatten: true}` cũng sẽ trả về nội dung fallback của slot (nếu như không có node nào đang được phân phối).

Cùng xem ví dụ sau đây:

```html
<slot name="slot1"><p>Default content</p></slot>
```

Giả sử nó nằm trong 1 component gọi là `<my-container>`

Giờ ta sẽ test thử các cách sử dụng khác nhau của component này và kết quả trả về của `assignedNodes()`:

Trường hợp đầu tiên, ta sẽ thêm nội dung vào slot:

```html
<my-container>
  <span slot="slot1"> container text </span>
</my-container>
```

Gọi `assignedNodes()` sẽ có kết quả `[<span slot='slot1'> container text </span>]`. Để ý rằng kết quả là 1 array các node.

Trong trường hợp thứ 2, ta để nội dung trống trơn:
`<my-container> </my-container>`

Kết quả khi gọi `assignedNodes()` là 1 array rỗng [].

Tuy nhiên nếu như bạn đẩy thêm option `{flatten: true}` thì nó sẽ lấy giá trị mặc định và trả về [<p>Default content</p>].

Ngoài ra, để có thể chạm tới 1 element bên trong slot, bạn có thể gọi `assignedNodes()` để xem nếu có element nào đang được gán vào component slot hay không.

# Mô hình sự kiện (event model)

Thật thú vị khi để ý thấy điều gì xảy ra khi 1 sự kiện nằm trong Shadow DOM được bắn ra.

Mục tiêu của sự kiện được điều chỉnh để bảo trì sự đóng gói, cô lập bởi Shadow DOM. Khi 1 sự kiện được tái-mục-tiêu (re-target), trông giống như là nó xuất phát từ chính component hơn là từ các element bên trong của Shadow DOM - vốn là 1 phần của component.

Dưới đây là danh sách các sự kiện có thể phát ra ngoài Shadow DOM (1 số thì không):

- **Sự kiện Focus**: blur, focus, focusin, focusout
- **Sự kiện cho con trỏ chuột**: click, dbclick, mousedown, mouseenter, mousemove, vân vân.
- **Sự kiện cho con lăn chuột**: wheel
- **Sự kiện cho input**: beforeinput, input
- **Sự kiện cho bàn phím**: keydown, keyup
- **Sự kiện kết hợp**: compositionstart, compositionupdate, compositionend
- **Sự kiện kéo-thả**: dragstart, drag, dragend, drop, vân vân.

# Các sự kiện custom

Các sự kiện custom mặc định thì không phát ra bên ngoài Shadow DOM. Nếu bạn muốn điều phối 1 sự kiện custom và muốn nó phát ra ngoài, bạn cần thêm 2 option: bubbles: true và composed: true

Ví dụ:

```javascript
var container = this.shadowRoot.querySelector("#container");
container.dispatchEvent(new Event("containerchanged", { bubbles: true, composed: true }));
```

Sự hỗ trợ trình duyệt: Để xác định xem trình duyệt có sẵn hỗ trợ cho Shadow DOM hay không thì ta có thể kiểm tra sự tồn tại của attachShadow:

```javascript
const supportsShadowDOMV1 = !!HTMLElement.prototype.attachShadow;
```

Nhưng nói chung là không được nhiều cho lắm:

![](https://cdn-images-1.medium.com/max/1000/0*k0vSOmvdDkRJzcpW)

Nhìn chung thì Shadow DOM có lối hành xử rất khác với DOM thường. Team SessionStack có 1 chút kinh nghiệm khi sử dụng chúng trong thư viện của họ. Thư viện đó khi được tích hợp vào trong webapp thì sẽ bắt đầu thu thập các thông tin chẳng hạn như sự kiện người dùng, dữ liệu mạng, biệt lệ, thông báo debug, thay đổi trên DOM, vân vân, và gửi chúng về cho server của họ.

Sau đó, họ sẽ xử lý các dữ liệu thu được để cho phép bạn có thể dùng SessionStack để tái hiện lại các vấn đề xảy ra trong sản phẩm của bạn. Sự khó khăn họ gặp phải trong quá trình phát triển khi sử dụng Shadow DOM: họ phải kiểm soát mọi thay đổi trên DOM để có thể tái tạo lại sau này. Họ dùng MutationObserver để làm việc đó. Tuy nhiên, Shadow DOM không trigger các sự kiện MutationObserver trong phạm vi toàn cục, nghĩa là họ phải xử lý các component này theo 1 cách hoàn toàn khác.
Họ cũng nhận thấy rằng ngày nay, có rất nhiều webapp đang tận dụng sức mạnh của Shadow DOM nên có vẻ như công nghệ này sẽ có 1 tương lai rất rạng ngời.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p17-ben-trong-shadow-dom-xay-dung-component-khep-kin</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p17-ben-trong-shadow-dom-xay-dung-component-khep-kin</guid>
            <pubDate>Sat, 05 Jan 2019 23:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P16: Engine lưu trữ + lựa chọn API lưu trữ nào cho phù hợp]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 16 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

# Khái quát

Lựa chọn cơ chế lưu trữ đúng đắn cho thiết bị lưu trữ ở local rất quan trọng khi thiết kế webapp. Một engine lưu trữ tốt sẽ đảm bảo thông tin của bạn được lưu chắc chắn, giảm băng thông và cải thiện sự phản hồi. Chiến lược lưu trữ bộ nhớ đệm phù hợp là thành phần cốt lõi cho phép trải nghiệm mobile web offline, càng ngày càng có nhiều người dùng cảm thấy rằng như đó là trải nghiệm mặc định phải có.

Trong chương này, chúng ta sẽ thảo luận về những API lưu trữ có sẵn & các service và cung cấp một số hướng dẫn làm thế nào để lựa chọn đúng loại cho webapp của bạn.

# Data model (mô hình dữ liệu)

Mô hình lưu trữ dữ liệu xác định làm thế nào để dữ liệu được tổ chức nội bộ. Điều này ảnh hưởng toàn bộ thiết kế của webapp, định nghĩa sự cân bằng để làm cho webapp hoạt động hiệu quả nhưng vẫn giải quyết được vấn đề cần giải quyết. Giống như bất cứ thứ gì liên quan đến kỹ thuật, không tồn tại phương pháp nào "tốt hơn" và cũng không có giải pháp một-cho-tất-cả nào hết. Cùng xem qua 1 chút về một số data model mà ta có thể dùng:

- **Kiểu cấu trúc**: Dữ liệu được lưu trong các bảng kèm với các trường đã được định nghĩa, giống như các hệ quản trị cơ sở dữ liệu đặc trưng dựa trên SQL, chúng có tính linh hoạt và các câu truy vấn động. Một ví dụ nổi bật về kho dữ liệu kiểu cấu trúc trên trình duyệt chính là IndexedDB.
- **key/value**: kho dữ liệu key/value, và cả cơ sở dữ liệu NoSQL, cho phép lưu trữ và trích xuất dữ liệu không có cấu trúc được đánh index bằng 1 key duy nhất. Kho dữ liệu kiểu key/value giống như bảng băm (hash table) ở chỗ chúng cho phép truy cập liên tục vào các dữ liệu ẩn đã được đánh index. Một ví dụ điển hình cho kho dữ liệu key/value là Cache API trên trình duyệt và Apache Cassandra trên server.
- **Byte Streams**: mô hình đơn giản này lưu dữ liệu dưới dạng 1 biến độ dài, một chuỗi ẩn các byte, và nó để lại bất kỳ hình thức tổ chức nội bộ nào cho lớp ứng dụng. Mô hình này đặc biệt tốt cho các hệ thống tập tin (file) và các blob dữ liệu có tổ chức dạng phân cấp. Ví dụ điển hình của kho dữ liệu byte stream bao gồm những hệ thống file và các dịch vụ lưu trữ cloud.

# Tính bền vững

Có thể phân tích các phương pháp lưu trữ cho webapp với sự mức độ ưu tiên cho timeframe hơn là dữ liệu nào cần được bền vững:

- **Session Persistence (Bền vững phiên)**: dữ liệu trong mục này chỉ được giữ cố định miễn là một session của web hoặc một tab trên trình duyệt vẫn đang hoạt động. Ví dụ về cơ chế lưu trữ với phiên bền vững chính là [Session Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage)
- **Device Persistence (Bền vững thiết bị)**: dữ liệu trong mục này được giữ cố định xuyên suốt nhiều session và nhiều tab hoặc cửa sổ trình duyệt, trên 1 thiết bị cụ thể. Ví dụ: [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage)
- **Global Persistence (Bền vững toàn cục)**: dữ liệu trong mục này được giữ cố định xuyên suốt các session & các thiết bị. Vì thế, đây là dạng mạnh mẽ nhất của bền vững dữ liệu. Nó không được lưu trữ trên chính thiết bị và điều đó nghĩa là bạn cần phải có 1 kiểu lưu trữ ở phía server. Chúng ta sẽ không thảo luận chi tiết về nó vì bài viết này chỉ tập trung vào lưu trữ dữ liệu trên thiết bị.

# Bền vững dữ liệu trên trình duyệt

Ngày nay có rất ít các browser API cho phép bạn lưu trữ dữ liệu. Chúng ta sẽ tìm hiểu qua một vài thứ như thế và tạo 1 bản so sánh để có thể dễ dàng lựa chọn giải pháp phù hợp.

Tuy nhiên thì đầu tiên, có vài thứ bạn cần phải cân nhắc trước khi chọn làm thế nào để cố định dữ liệu. Dĩ nhiên thì thứ đầu tiên bạn cần phải hiểu kỹ chính là webapp của bạn được dùng như thế nào, sau đó còn có bảo trì và nâng cấp. Thậm chí nếu bạn có câu trả lời cho các câu hỏi đó, bạn cũng sẽ phải kết thúc với 1 số lựa chọn và chọn chúng. Vì thế nên dưới đây là 1 số thứ bạn nên xem qua:

- **Trình duyệt hỗ trợ**: bạn cần phải nhớ kỹ 1 sự thật là các API được xây dựng tốt & được chuẩn hóa có mức độ ưu ái cao hơn, bởi vì chúng hướng tới sự tồn tại lâu dài và được hỗ trợ rộng rãi. Những API đó cũng thường có tài liệu rộng hơn và cộng đồng developer hỗ trợ giàu kinh nghiệm hơn.
- **Transactions (giao dịch)**: đôi khi transactions rất quan trọng đối với 1 tập hợp của các hoạt động lưu trữ tự động thành công hay thất bại. Các cơ sở dữ liệu theo truyền thống luôn hỗ trợ tính năng này sử dụng 1 mô hình transaction, những cập nhật liên quan được nhóm lại thành các đơn vị chuyên biệt.
- **Sync/Async (đồng bộ/bất đồng bộ)**: một vài API lưu trữ thể hiện sự đồng bộ khi mà các request lưu trữ hoặc lấy dữ liệu sẽ chặn tiến trình đang hoạt động cho tới khi request được hoàn thành. Sử dụng API lưu trữ đồng bộ có thể chặn tiến trình chính và làm cho trải nghiệm UI trên webapp bị đông cứng không hoạt động. Nếu có thể, hãy dùng các API bất đồng bộ.

# So sánh

Trong phần này, chúng ta sẽ so sánh các API hiện có dành cho web developer và so sánh chúng với các tiêu chí đã nói ở trên

| API                         | Mô hình dữ liệu (Data model) | Tính bền vững (persistence) | Trình duyệt hỗ trợ | Transactions | Sync/Async |
| --------------------------- | ---------------------------- | --------------------------- | ------------------ | ------------ | ---------- |
| File System (hệ thống file) | Byte stream                  | thiết bị                    | 52%                | Không        | Async      |
| Local Storage               | key/value                    | thiết bị                    | 93%                | Không        | Sync       |
| Session Storage             | key/value                    | session                     | 93%                | Không        | Sync       |
| Cookies                     | cấu trúc                     | thiết bị                    | 100%               | Không        | Sync       |
| Cache                       | key/value                    | thiết bị                    | 60%                | Không        | Async      |
| IndexedDB                   | hỗn hợp (hybrid)             | thiết bị                    | 83%                | Có           | Async      |

# File System API (hệ thống file)

![](https://cdn-images-1.medium.com/max/1000/0*9KPehy4mUb8f-hSp)

Với File System API, webapp có thể tạo, đọc, điều hướng và ghi vào 1 khu vực sandbox thuộc hệ thống local file của user.

API được chia nhỏ thành nhiều chủ đề:

- Đọc và sửa file: File/Blob, FileList, FileReader
- Tạo và ghi file: Blob(), FileWriter
- Các thư mục và truy cập hệ thống file: DirectoryReader, FileEntry/DirectoryEntry, LocalFileSystem

File System API không phải là 1 hệ thống API tiêu chuẩn. Bạn không nên dùng nó trên sản phẩm webapp production bởi vì nó sẽ không hoạt động với tất cả user. Có rất sự không tương thích lớn giữa các triển khai khác nhau và hành vi của chúng sẽ chắc chắn bị thay đổi trong tương lai.

**FileSystem** - interface của File & Directory Entries API được dùng để thể hiện 1 hệ thống file. Những object này có thể được lấy từ thuộc tính [filesystem](https://developer.mozilla.org/en-US/docs/Web/API/FileSystemEntry/filesystem) của bất kỳ entry thuộc hệ thống file nào. Một vài trình duyệt cung cấp thêm các API để tạo & quản lý các hệ thống file.

Interface này sẽ không cấp quyền cho bạn truy cập vào hệ thống file của user. Thay vào đó, bạn sẽ có 1 "ổ đĩa ảo" (virtual drive) bên trong sandbox của trình duyệt. Nếu bạn muốn truy cập vào hệ thống file của user, bạn cần phải gọi hỏi user bằng cách ví dụ như cài 1 Chrome extension.

## Yêu cầu 1 hệ thống file

Một webapp có thể yêu cầu truy cập đến một hệ thống file sandbox bằng cách gọi: window.requestFileSystem():

```javascript
// Lưu ý: Hệ thống file đã được đánh tiền tố tính đến Google Chrome 12.
window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;
window.requestFileSystem(type, size, successCallback, opt_errorCallback);
```

Nếu bạn gọi hàm requestFileSystem() lần đầu tiên thì 1 vùng lưu trữ mới được tạo ra. Quan trọng hãy nhớ rằng hệ thống file này được gói gọn trong sandbox, nghĩa là 1 webapp không thể truy cập file của webapp khác.

Sau khi bạn có quyền truy cập vào hệ thống file, bạn có thể làm tất cả các hoạt động cơ bản với file & thư mục.

FileSystem là 1 lựa chọn lưu trữ khá khác biệt với các loại khác vì nó hướng đến thỏa mãn như cầu lưu trữ ở phía client trong những tình huống không dùng được cơ sở dữ liệu. Một cách tổng quát thì đó là những ứng dụng hoạt động với những cục blob nhị phân cỡ bự và/hoặc chia sẻ dữ liệu với các ứng dụng khác bên ngoài trình duyệt.

Dưới đây là những trường hợp có thể sử dụng FileSystem API:

- Tải lên (upload) liên tục: khi 1 file hay thư mục được chọn để upload, nó copy các file vào trong 1 vùng local sandbox và upload từng phần, từng phần.
- Video game, âm nhạc hoặc các app khác mà có nhiều tài nguyên media.
- Chỉnh sửa âm thanh/hình ảnh với truy cập offline hoặc là lưu đệm local để tăng tốc độ - những cục blob dữ liệu như thế thường rất lớn khi đọc-ghi.
- Xem video offline - cần phải download 1 lượng lớn file để xem sau hoặc seek + streaming hiệu quả.
- Ứng dụng Web Mail offline - download các file đính kèm và lưu chúng ở local.

Tình hình hỗ trợ của API:
![](https://cdn-images-1.medium.com/max/1000/0*ndU4N8xQF6QEQmSY)

# Local Storage

![](https://cdn-images-1.medium.com/max/1000/0*AsoHzlowoLItnUEL)

API localstorage cho phép bạn truy cập object [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) dành cho origin của [Document](https://developer.mozilla.org/en-US/docs/Web/API/Document). Dữ liệu lưu trữ xuyên suốt nhiều session trình duyệt. localstorage tương tự như [sessionStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window.sessionStorage), ngoại trừ việc dữ liệu lưu ở trong dataStorage không bị hết hạn, dữ liệu trong sessionStorage sẽ bị dọn dẹp khi session của trang kết thúc, tức là khi đóng tab trang đó.

Để ý rằng dữ liệu lưu trong localStorage hay sessionStorage là cụ thể cho origin của từng trang, bao gồm sự kết hợp của giao thức (protocol), host và cổng (port).

Tình hình hỗ trợ sáng sủa của nó:
![](https://cdn-images-1.medium.com/max/1000/0*hxC_NUPNycUBhj-L)

# Session Storage

![](https://cdn-images-1.medium.com/max/1000/0*-IMsNws_L1g0Syla)

sessionStorage cho phép bạn truy cập vào 1 object [Storage](https://developer.mozilla.org/en-US/docs/Web/API/Storage) của session cho origin hiện tại. sessionStorage tương tự như [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), như đã giải thích ngắn gọn ở trên. Điểm khác biệt duy nhất là dữ liệu lưu trong localStorage không bị hết hạn, còn trong sessionStorage thì bị xóa khi session của trang kết thúc. Một session của trang tồn tại miễn là cửa sổ trình duyệt vẫn còn mở và tồn tại khi trang reload hoặc restore. **Mở trang trong 1 tab mới hoặc cửa sổ mới sẽ tạo ra session mới**, khác với cách hoạt động của session cookies.

Dữ liệu lưu trong sessionStorage hay localStorage là **dành riêng cho origin của trang**.

Tình hình hỗ trợ của sessionStorage:
![](https://cdn-images-1.medium.com/max/1000/0*PTDs1BkbMgekizit)

# Cookies

![](https://cdn-images-1.medium.com/max/1000/0*VKQINIYfu2O7d7BH)

Một cookie (hay web cookie, cookie trình duyệt) là 1 cục dữ liệu nhỏ xíu mà server gửi đến trình duyệt của user. Trình duyệt có thể lưu nó và gửi ngược về cùng server đó trong request tiếp theo. Thông thường, nó được dùng để cho biết nếu 2 request đến từ cùng 1 trình duyệt - ví dụ: giữ cho user tiếp tục đăng nhập. Nó ghi nhớ thông tin trạng thái cho giao thức HTTP [không trạng thái](https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview#HTTP_is_stateless_but_not_sessionless) (stateless).

Cookies có 3 trường hợp dùng chính:

- **Quản lý session**: login, giỏ hàng online, lưu điểm game hay bất cứ thứ gì server cần nhớ.
- **Cá nhân hóa (Personalization)**: các thiết đặt của người dùng, chủ để và những cài đặt khác.
- **Theo dõi**: ghi lại và phân tích hành vi của người dùng.

Cookies đã từng được dùng để lưu trữ tổng quát ở phía client. Như vậy vẫn hợp pháp vì lúc đó nó là giải pháp duy nhất để lưu trữ thông tin ở phía client, ngày nay thì người ta thường chọn các API lưu trữ hiện đại hơn. Cookies được gửi về với mỗi request nên có thể ảnh hưởng xấu đến hiệu năng (đặc biệt với các kết nối trên thiết bị di động).

Có 2 loại cookies:

- **Cookie phiên (session cookies**: Chúng bị xóa khi client tắt. Trình duyệt web có thể dùng **khôi phục session** để lấy lại gần hết session cookies, giống như là trình duyệt chưa bao giờ bị tắt vậy.
- **Cookie dài hạn (permanent cookie)**: thay vì hết hạn khi người dùng tắt trình duyệt, _permanent cookie_ hết hạn tại 1 ngày nhất định (Expires) hoặc là sau 1 khoảng thời gian nhất định (Max-Age).

Lưu ý rằng các thông tin bí mật và nhạy cảm không nên lưu hoặc vận chuyển với HTTP Cookies bởi vì rõ ràng toàn bộ cơ chế này vốn không an toàn.

Và rõ ràng là cookies hoạt động tốt với tất cả các trình duyệt.

# Cache

![](https://cdn-images-1.medium.com/max/1000/0*XZ2U-ztABhWJOSky)

Interface **Cache** cung cấp cơ chế lưu trữ cho cặp object [Request](http://fetch.spec.whatwg.org/#request)/[Response](http://fetch.spec.whatwg.org/#response) được lưu đệm. Lưu ý rằng interface Cache được dùng trong phạm vi window giống như workers. Bạn không phải dùng nó cùng với service worker mặc dù nó được định nghĩa trong thông tin của service worker.

Một origin có thể có nhiều object Cache (có tên cụ thể). Bạn có trách nhiệm triển khai code (ví dụ như trong [ServiceWorker](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker)) để xử lý cập nhật cho Cache. Các item trong Cache không được cập nhật trừ khi được yêu cầu tường minh; chúng không hết hạn trừ khi bị xóa. Dùng hàm [CacheStorage.open()](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open) để mở 1 object Cache với tên cụ thể và gọi bất kỳ phương thức Cache nào để bảo trì Cache.

Bạn cũng có trách nhiệm dọn dẹp định kỳ các cache entry. Mỗi trình duyệt có 1 giới hạn cứng với số lượng cache lưu trữ cấp cho 1 origin. Hạn mức sử dụng Cache ước tính tồn tại trong API [StorageEstimate](https://developer.mozilla.org/en-US/docs/Web/API/StorageEstimate). Trình duyệt làm công việc tốt nhất của nó để quản lý dung lượng đĩa nhớ nhưng nó có thể xóa lưu trữ Cache của 1 origin. Đại khái là trình duyệt hoặc sẽ xóa tất cả dữ liệu của 1 origin hoặc không làm gì cả. Đảm bảo đánh phiên bản của cache bằng tên và chỉ dùng phiên bản cache nào mà code của bạn có thể sử dụng an toàn. Bạn có thể xem thêm bài [Xóa cache cũ](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker_API/Using_Service_Workers#Deleting_old_caches) để hiểu thêm.

Interface **CacheStorage** thể hiện sự lưu trữ cho các object [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache)

Interface:

- Cung cấp thư mục master của tất cả các cache có tên mà có thể truy xuất bởi [ServiceWorker](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker) hoặc các loại worker khác hoặc phạm vi [window](https://developer.mozilla.org/en-US/docs/Web/API/Window) (bạn không bị giới hạn chỉ sử dụng với service worker kể cả thông tin của [Service Worker](https://w3c.github.io/ServiceWorker/) có định nghĩa như vậy).
- Duy trì khả năng ánh xạ (mapping) tên tương ứng với object [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache)

Dùng phương thức [CacheStorage.open()](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open) để lấy 1 instance của [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache)

Dùng phương thức [CacheStorage.match()](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/match) để kiểm tra nếu 1 [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) có phải là 1 key trong bất kỳ object [Cache](https://developer.mozilla.org/en-US/docs/Web/API/Cache) nào mà object CacheStorage theo dõi.

Bạn có thể truy cập CacheStorage thông qua thuộc tính toàn cục [caches](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/caches)

# IndexedDB

![](https://cdn-images-1.medium.com/max/1000/0*HP66Xm7oe9u8Ofk1)

IndexedDB là 1 cách để bạn lưu trữ dữ liệu một cách bền vững bên trong trình duyệt của người dùng. Bởi vì nó cho phép bạn tạo các webapp với khả năng viết câu truy vấn đa dạng bất kể tình trạng mạng. Những ứng dụng này có thể làm việc online & offline. IndexedDB có ích cho các ứng dụng cần lưu trữ 1 lượng lớn dữ liệu (ví dụ: danh sách các DVD cho mượn trong thư viện) và các ứng dụng không cần sự kết nối internet ổn định để hoạt động (ví dụ: ứng dụng mail, danh sách to-do, notepad).

Trong bài này, nó là cơ sở dữ liệu lưu trữ mà chúng ta sẽ thảo luận chi tiết hơn 1 chút bởi vì các API lưu trữ khác đều được hiểu biết khá rộng. Thêm nữa, IndexedDB càng ngày càng phổ biến với các webapp phức tạp ngày càng gia tăng.

## Bên trong IndexedDB

IndexedDB cho phép bạn lưu trữ và lấy các object được lưu bằng cách dùng key. Tất cả thay đổi bạn thực hiện với cơ sở dữ liệu đều xảy ra trong phạm vi transaction. Giống như nhiều giải pháp lưu trữ web khác, IndexedDB bám sát nguyên tắc cùng origin ([same-origin policy](http://www.w3.org/Security/wiki/Same_Origin_Policy)). Vì thế bạn có thể truy cập dữ liệu lưu trữ trong phạm vi 1 domain nhưng không thể truy cập dữ liệu của các domain khác.

IndexedDB là API bất đồng bộ ([asynchronous](https://developer.mozilla.org/en/IndexedDB#Asynchronous_API)) có thể sử dụng trong hầu hết các ngữ cảnh, bao gồm cả [WebWorkers](https://developer.mozilla.org/En/DOM/Using_web_workers). Nó thường bao gồm cả 1 phiên bản đồng bộ ([synchronous](https://developer.mozilla.org/en/IndexedDB#Synchronous_API)) nữa để dùng trong web worker nhưng đã bị xóa bỏ bởi vì cộng đồng web không có hứng thú với nó.

IndexedDB thường cạnh tranh với cơ sở dữ liệu WebSQL nhưng nó đã bị hủy bởi W3C. Trong khi cả 2 IndexedDB và WebSQL là các giải pháp lưu trữ, chúng lại không cung cấp cùng tính năng. CSDL WebSQL là 1 hệ truy cập CSDL quan hệ trong khi IndexedDB là hệ bảng đánh số (indexed table).

Đừng bắt đầu với IndexedDB nếu như bạn chỉ nghe nói hoặc giả định rằng nó tốt hơn các loại CSDL khác. Thay vì thế hãy đọc thật kỹ tài liệu của nó. Dưới đây là 1 vài ý tưởng cần thiết mà bạn cần phải biết:

- **CSDL IndexedDB lưu theo cặp key-value**: giá trị có thể là object cấu trúc phức tạp và key có thể là thuộc tính của những object đó. Bạn có thể tạo index dùng bất kỳ thuộc tính nào của object để dễ tìm kiếm cũng như khi cần sắp xếp. Key cũng có thể là object nhị phân.
- **API IndexedDB đa phần là bất đồng bộ**: API không đưa dữ liệu cho bạn bằng cách trả về giá trị. Thay vì thế nó truyền vào 1 hàm callback. Bạn không "lưu" 1 giá trị vào trong CSDL hoặc "lấy" nó ra theo nghĩa đồng bộ. Thay vào đó, bạn "yêu cầu" (request) một hành động trên CSDL. Một sự kiện thông báo cho bạn khi hành động hoàn thành và kiểu sự kiện bạn nhận được nếu như có hành động thành công hay thất bại. Không khác mấy so với cách hoạt động của [XMLHttpRequest](https://developer.mozilla.org/en/DOM/XMLHttpRequest) (hoặc là cả tá thứ khác về Javascript)
- **IndexedDB dùng rất nhiều request**: request là object nhận các sự kiện thành công hay thất bại như đã nói ở trên. Chúng có thuộc tính onsuccess và onerror cũng như readyState, result và errorCode sẽ cho bạn biết về trạng thái của request.
- **IndexedDB hướng đối tượng**: IndexedDB không phải CSDL quan hệ với các bảng thể hiện tập hợp hàng & cột. Điểm khác biệt cơ bản này ảnh hưởng đến giai đoạn thiết kế và xây dựng ứng dụng của bạn.
- **IndexedDB không dùng ngôn ngữ truy vấn cấu trúc (SQL)**: nó dùng kiểu truy vấn trên index để tạo ra con trỏ, chính con trỏ này dùng để lặp xuyên suốt tập kết quả. Nếu bạn không quen với hệ thống NoSQL thì có thể xem thêm [bài này trên Wikipedia](https://en.wikipedia.org/wiki/NoSQL)
- **IndexedDB dùng nguyên tắc cùng origin**: một origin là domain, giao thức tầng ứng dụng và cổng (port) của URL của văn bản là nơi mà code được thực thi. Mỗi origin có 1 tập các CSDL riêng của nó. Mỗi CSDL có 1 cái tên định danh nó trong origin.

## Giới hạn của IndexedDB

IndexedDB được thiết kế để dùng với hầu hết các tình huống cần lưu trữ ở phía client. Nó không được thiết kế cho 1 vài trường hợp dưới đây:

- **Sắp xếp toàn cầu (Internationalized sorting)**: không phải tất cả ngôn ngữ đều sắp xếp array theo cùng 1 cách, vì thế mà Internationalized sorting không được hỗ trợ. CSDL không thể lưu dữ liệu theo 1 thứ tự toàn cầu cụ thể, bạn có thể tự tay sắp xếp dữ liệu đọc từ CSDL ra.
- **Đồng bộ hóa**: API không được thiết kế để thực hiện đồng bộ hóa với CSDL ở phía server. Bạn phải viết code riêng để đồng bộ CSDL IndexedDB ở client với CSDL ở server.
- **Tìm kiếm toàn văn bản (Full text searching )**: API không cung cấp giải pháp tương tự như LIKE trong SQL.

Thêm vào đó, hãy cẩn thận trình duyệt có thể xóa CSDL trong những trường hợp sau đây:

- **User yêu cầu xóa**: nhiều trình duyệt có cài đặt cho phép user xóa tất cả dữ liệu lưu trữ cho 1 website, bao gồm cả cookies, bookmarks, mật khẩu được lưu và dữ liệu IndexedDB.
- **Trình duyệt đang chạy chế độ riêng tư**: một vài trình duyệt có chế độ riêng tư như private browsing (Firefox) hay incognito (Chrome). Tại cuối session, trình duyệt sẽ xóa toàn bộ CSDL.
- **Ổ cứng hoặc giới hạn cho phép bị đầy**
- **Dữ liệu bị hỏng**

Các trường hợp chính xác và khả năng của trình duyệt thay đổi theo thời gian, nhưng nguyên lý chung của các nhà phát triển trình duyệt là tạo ra nỗ lực tốt nhất để lưu giữ dữ liệu khi có thể.

![](https://cdn-images-1.medium.com/max/1000/0*kGDQYE70_z58D7na)

# Lựa chọn API lưu trữ

Như đã đề cập ở trên, sẽ tốt hơn nếu chọn các API được hỗ trợ rộng rãi trong nhiều trình duyệt và cung cấp mô hình gọi bất đồng bộ nhằm nâng tối đa khả năng phản hồi của UI. Như 1 cách tự nhiên, ngữ cảnh như thế này sẽ dẫn đến các lựa chọn công nghệ:

- Với lưu trữ offline, dùng [Cache API](https://developers.google.com/web/fundamentals/instant-and-offline/web-storage/cache-api). API này tồn tại trong các trình duyệt hỗ trợ công nghệ [Service Worker](https://jakearchibald.github.io/isserviceworkerready/), cần thiết để xây dựng app offline.
- Để lưu trữ trạng thái của ứng dụng và các dữ liệu do người dùng tạo ra, sử dụng IndexedDB. Nó cho phép user làm việc offline trên nhiều trình duyệt hơn so với những trình duyệt chỉ hỗ trợ Cache API.

[SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=classes-inheritance-transpiling-outro) sử dụng các API lưu trữ khác nhau. Ví dụ, thư viện tích hợp vào trong webapp của khách hàng dùng cả cookies & session storage. Lý do là thư viện đó cần thu thập các dữ liệu chẳng hạn như các sự kiện, thay đổi trên DOM, dữ liệu mạng, biệt lệ, thông tin debug, vân vân, rồi sau đó gửi về server. Họ thu thập dữ liệu như vậy từ session của người dùng nhưng họ cần 1 cách chính xác để xác định khi nào session của user bắt đầu và kết thúc.

Họ cân nhắc 1 session sẽ là toàn bộ chu kỳ sử dụng webapp từ lúc bắt đầu, bao gồm cả xem trang và điều hướng cho đến khi user đóng trình duyệt hay tab và không quay trở lại trong vài phút, phần này họ dùng 1 sự kết hợp của session storage & logic ở phía server. Còn gì nữa nào, họ cho phép bạn xác định từng người dùng cuối để có thể cung cấp cho bạn dữ liệu người dùng trên mỗi session. Họ dựa vào cookies để làm việc này (giống như các công cụ giám sát/phân tích).

Trong ứng dụng của họ, bạn có thể xem (xem theo yêu cầu hoặc thời gian thực) những sự kiện đã thu tập dưới dạng video được tái tạo lại cách mà user gặp phải các vấn đều, họ sử dụng chủ yếu là cookies bởi vì serivce RESTful của họ về cơ bản thì cần authentication token để authenticate, authorize và xác nhận request.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p16-engine-luu-tru-lua-chon-api-luu-tru-nao-cho-phu-hop</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p16-engine-luu-tru-lua-chon-api-luu-tru-nao-cho-phu-hop</guid>
            <pubDate>Sun, 25 Nov 2018 16:42:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P15: Bên trong Class & Inheritance + Transpiling với Babel & Typescript]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 15 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Ngày nay, cách phổ biến nhất để dựng cấu trúc của bất kỳ dự án phần mềm nào là sử dụng class. Trong bài viết này, chúng ta sẽ cùng khám phá các cách khác nhau để triển khai class trong Javascript và làm thế nào ta có thể xây dựng cây thứ bậc của class (class hierarchy). Chúng ta sẽ bắt đầu bằng cách đào sâu tìm hiểu cách hoạt động của prototype và phân tích những cách để giả lập kế thừa class trong các thư viện nổi tiếng. Tiếp đến ta sẽ xem làm cách nào mà transpiling có thể thêm những tính năng không được hỗ trợ chính thức cho ngôn ngữ và cách mà nó được dùng trong Babel & Typescript để giới thiệu về sự hỗ trợ của class trong ECMAScript 2015\. Cuối cùng, ta sẽ kết thúc với một vài ví dụ về class được triển khai native trong V8.

# Khái quát

Trong Javascript, về bản chất không có kiểu dữ liệu nguyên thủy và mọi thứ tạo ra đều là object. Ví dụ, nếu ta tạo 1 string:

```javascript
const name = "SessionStack";
```

Thì chúng ta có thể gọi nhiều phương thức khác nhau trên object vừa mới được tạo ra:

```javascript
console.log(a.repeat(2)); // SessionStackSessionStack
console.log(a.toLowerCase()); // sessionstack
```

Không giống như các ngôn ngữ khác, trong Javascript, khai báo string hay number sẽ tự động tạo ra một object mà nó sẽ đóng gói giá trị đó và cung cấp nhiều phương thức khác nhau có thể thực thi được kể cả với các kiểu dữ liệu nguyên thủy.

Một sự thật thú vị khác là những kiểu dữ liệu phức tạp, chẳng hạn như array, cũng là object. Nếu bạn nhìn kỹ hơn vào typeof của một array, bạn sẽ thấy nó là object. Số index của mỗi phần tử trong danh sách chính là thuộc tính của object. Vì thế khi bạn truy xuất một phần tử bằng số index trong array, bạn thực ra chỉ truy xuất vào thuộc tính của object array và trả về giá trị của nó. Khi nói về vấn đề lưu trữ dữ liệu thì 2 định nghĩa sau là giống hệt nhau:

```javascript
let names = [“SessionStack”];

let names = {
  “0”: “SessionStack”,
  “length”: 1
}
```

Kết quả là thời gian cần để truy xuất 1 phần tử trong array và 1 thuộc tính của object là như nhau. Thật khó để nhận ra. Trước đây, trong 1 project, tác giả phải thực hiện quá trình tối ưu hóa rất lớn cho một đoạn code quan trọng. Sau khi thử tất cả các lựa chọn dễ, tác giả đã thay thế toàn bộ object được dùng trong project bằng array. Về lý thuyết, truy xuất 1 phần tử trong 1 array thì nhanh hơn truy xuất 1 key trong hash map (bản đồ băm). Tác giả đã ngạc nhiên rằng cách làm này không mang lại một chút hiệu quả hơn với hiệu năng. Trong Javascript, cả array và object đều được triển khai về việc truy xuất 1 key trong hash map và sẽ tốn cùng 1 lượng thời gian như nhau.

# Giả lập class với prototype

Khi nghĩ về object, thứ đầu tiên xuất hiện chính là class. Tất cả chúng ta thông thường đều xây dựng cấu trúc của ứng dụng dựa trên class và các mối quan hệ giữa chúng với nhau. Mặc dù object trong Javascript xuất hiện khắp nơi, ngôn ngữ này lại không sử dụng kiểu kế thừa truyền thống dựa trên class. Thay vào đó nó dùng [prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model).
[![](https://cdn-images-1.medium.com/max/1000/0*SufKRGfPZIDlw1OG)

Trong Javascript, mọi object được kết nối đến object khác - chính là prototype của nó. Khi bạn thử truy xuất 1 thuộc tính hoặc phương thức trên 1 object, quá trình tìm kiếm (thuộc tính/phương thức) sẽ bắt đầu với chính object đó trước. Nếu không tìm thấy thì nó sẽ tiếp tục với prototype của object đó.

Chúng ta sẽ thử với 1 ví dụ đơn giản về định nghĩa constructor cho 1 class:

```javascript
function Component(content) {
  this.content = content;
}

Component.prototype.render = function () {
  console.log(this.content);
};
```

Ta thêm hàm render vào prototype bởi vì chúng ta muốn mỗi instance của Component đều có thể tìm thấy nó. Khi bạn gọi phương thức này trên mỗi instance của class Component, quá trình tìm kiếm đầu tiên sẽ thực hiện trên chính instance đó. Sau đó nó tiếp tục thực hiện tìm trên prototype và tại đây thì phương thức render được tìm thấy.
![](https://cdn-images-1.medium.com/max/1000/0*hZbijxS0vXu8vUmz)

Giờ ta thử mở rộng class Component ra, ta sẽ thêm vào một class con:

```javascript
function InputField(value) {
  this.content = `<input type="text" value="${value}" />`;
}
```

Nếu ta muốn InputField mở rộng chức năng của class Component và có thể gọi phương thức render của nó thì ta cần phải thay đổi prototype. Khi 1 phương thức được gọi trên instance của class con, ta không muốn tìm kiếm trong prototype trống rỗng của nó. Quá trình tìm kiếm sẽ tiếp tục ở class Component.

```javascript
InputField.prototype = Object.create(new Component());
```

Bằng cách này, phương thức render có thể được tìm thấy trong prototype của class Component. Để có thể kế thừa, ta cần kết nối prototype của InputField đến 1 instance của class Component. Nhiều thư viện sử dụng phương thức [Object.setPrototypeOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf) để làm việc này.

![](https://cdn-images-1.medium.com/max/1000/0*avLiOV_zXLxOgBee)

Tuy nhiên đây không phải là việc duy nhất mà ta cần làm. Mỗi khi mở rộng 1 class, ta cần chú ý:

- Đặt prototype của class con là 1 instance của class cha
- Gọi constructor của class cha trong constructor của class con để quá trình khởi tạo logic trong constructor của class cha có thể được thực thi.
- Giới thiệu cách truy xuất phương thức từ class cha. Bạn cần phải làm thế khi muốn ghi đè 1 phương thức và bạn muốn gọi đến phần triển khai gốc trong phương thức ở class cha.

Như bạn thấy thì nếu muốn sử dụng tất cả tính năng của kế thừa dựa trên class thì bạn cần thực thi phần logic phức tạp này mỗi lần kế thừa. Mỗi khi bạn cần tạo ra nhiều class thì tốt nhất là đóng gói mớ logic ấy trong 1 (hoặc vài) hàm để có thể tái sử dụng. Đây là cách mà các developer trước đây giải quyết vấn đề kế thừa dựa trên class - bằng cách giả lập với nhiều thư viện khác nhau. Những giải pháp này trở nên rất phổ biến và rõ ràng là có thiếu sót trong ngôn ngữ Javascript. Đó là lý do mà cú pháp mới để tạo class và hỗ trợ kế thừa class được giới thiệu trong bản sửa đổi lớn đầu tiên của ECMAScript 2015.

# Transpiling class

Khi tính năng mới của ES6 (hay ECMAScript 2015) được đề xuất, cộng đồng Javascript developer không ngồi yên chờ đợi tất cả các engine và trình duyệt bắt đầu hỗ trợ nó. Một cách tốt hơn để đạt được là thông qua transpile. Nó cho phép 1 đoạn code viết trong ECMAScript 2015 được biến đổi thành Javascript mà tất cả trình duyệt đều có thể hiểu. Bao gồm cả khả năng viết class với kế thừa dựa trên class và transpile chúng thành code hoạt động được.
![](https://cdn-images-1.medium.com/max/1000/0*QhRSzkngh6Aty-nD)

Một trong số những transpiler nổi tiếng nhất cho Javascript là Babel. Giờ thì cùng xem transpile hoạt động thế nào, ta sẽ áp dụng nó cho đoạn code về Component viết ở trên nhé:

```javascript
class Component {
  constructor(content) {
    this.content = content;
  }

  render() {
    console.log(this.content);
  }
}

const component = new Component("SessionStack");
component.render();
```

Và đây là những gì Babel transpile ra:

```javascript
var Component = (function () {
  function Component(content) {
    _classCallCheck(this, Component);

    this.content = content;
  }

  _createClass(Component, [
    {
      key: "render",
      value: function render() {
        console.log(this.content);
      },
    },
  ]);

  return Component;
})();
```

Như bạn thấy, code được biến đổi thành ECMAScript 5, loại có thể được thực thi trên bất kỳ môi trường nào. Ngoài ra còn có 1 số hàm được thêm vào. Chúng là 1 phần của thư viện Babel tiêu chuẩn.

Hàm \_classCallCheck và \_createClass có mặt như 1 phần trong kết quả biên dịch. Hàm đầu tiên đảm bảo hàm constructor không bao giờ được gọi như 1 hàm bình thường. Điều này được thực hiện bằng việc kiểm tra có hay không ngữ cảnh mà trong đó hàm được đánh giá là 1 instance của object Component. Code sẽ kiểm tra nếu
nó trỏ đến instance. Hàm thứ 2 \_createClass xử lý việc tạo ra các thuộc tính cho object và được truyền vào dưới dạng danh sách các object với key & value.

Để khám phá về cách kế thừa hoạt động ra sao thì ta cùng phân tích class InputField được kế thừa từ Component

```javascript
class InputField extends Component {
  constructor(value) {
    const content = `<input type="text" value="${value}" />`;
    super(content);
  }
}
```

Kết quả sau khi xử lý transpile với Babel:

```javascript
var InputField = (function (_Component) {
  _inherits(InputField, _Component);

  function InputField(value) {
    _classCallCheck(this, InputField);

    var content = '<input type="text" value="' + value + '" />';
    return _possibleConstructorReturn(
      this,
      (InputField.__proto__ || Object.getPrototypeOf(InputField)).call(this, content)
    );
  }

  return InputField;
})(Component);
```

Trong ví dụ trên, logic kế thừa được đóng gói trong hàm \_inherits. Nó thực hiện cùng y chang hành động mà chúng ta đã mô tả trong phần trước bằng cách cài đặt prototype của class con trở thành 1 instance của class cha.

Để transpile code, Babel thực hiện nhiều quá trình chuyển đổi. Đầu tiên code ECMAScript 2015 được parse và biến đổi thành một dạng thể hiện trung gian, gọi là **Abstract Syntax Tree**, chính là chủ đề ta đã thảo luận ở [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-14---Parsing--Abstract-Syntax-Tree---meo-giam-toi-da-thoi-gian-parse). Sau đó cây này được biến đổi lần nữa thành 1 cây AST khác mà mỗi node của nó được biến đổi thành phần tương ứng trong ECMAScript 5\. Cuối cùng cây AST được chuyển ngược lại thành code.

# AST trong Babel

Một cây AST sẽ có nhiều node, mỗi node chỉ có duy nhất 1 node cha. Trong Babel, tồn tại 1 kiểu cơ bản cho các node. Nó chưa thông tin về loại node và vị trí của chúng trong code. Có nhiều loại node khác nhau, chẳng hạn như Literals thể hiện string, number, null, vân vân. Cũng có cả node Statements dành cho các luồng kiểm soát (if) và vòng lặp (for, while). Có cả node đặc biệt dành cho class. Nó là 1 con (child) của class Node cơ bản. Nó mở rộng bằng cách thêm các trường để lưu tham chiếu đến class cơ bản và body của class như là 1 node riêng biệt.

Giờ ta sẽ biến đổi đoạn code sau thành cây AST

```javascript
class Component {
  constructor(content) {
    this.content = content;
  }

  render() {
    console.log(this.content);
  }
}
```

Đây là kết quả:
![](https://cdn-images-1.medium.com/max/1000/0*-OqUfzpRtgDJQjXY)

Sau khi tạo ra cây AST, mỗi node được biến đổi thành node ECMAScript 5 tương đương với nó và chuyển ngược lại thành code thường theo tiêu chuẩn của ECMAScript 5\. Quá trình này được thực hiện bằng 1 tiến trình tìm kiếm node nằm ở vị trí xa nhất với root node và biến đổi chúng thành code. Sau đó node cha của nó sẽ được biến đổi bằng đoạn code đã sinh ra cho các node con của nó. Quá trình này được gọi là [depth-first traversal](https://en.wikipedia.org/wiki/Depth-first_search)

Trong ví dụ trên, đầu tiên code của 2 node MethodDefinition sẽ được sinh ra, theo sau nó là code của node ClassBody và cuối cùng là node ClassDeclaration

# Transpile với TypeScript

Một framework phổ biến khác hỗ trợ khả năng transpile chính là TypeScript. Nó giới thiệu cú pháp kiểu mới để viết ứng dụng Javascript và được biến đổi thành ECMAScript 5 mà có thể chạy trên bất kỳ trình duyệt hay engine nào. Dưới đây là phần triển khai của class Component trong TypeScript:

```javascript
class Component {
  content: string;
  constructor(content: string) {
    this.content = content;
  }
  render() {
    console.log(this.content);
  }
}
```

Và đây là cây AST được sinh ra:
![](https://cdn-images-1.medium.com/max/1000/0*j3zkSjnrL4fnCK3A)

Nó hỗ trợ kế thừa:

```javascript
class InputField extends Component {
  constructor(value: string) {
    const content = `<input type="text" value="${value}" />`;
    super(content);
  }
}
```

Kết quả transpile ra:

```javascript
var InputField = /** @class */ (function (_super) {
  __extends(InputField, _super);
  function InputField(value) {
    var _this = this;
    var content = '<input type="text" value="' + value + '" />';
    _this = _super.call(this, content) || this;
    return _this;
  }
  return InputField;
})(Component);
```

Kết quả cuối cùng một lần nữa lại là ECMAScript 5 với 1 số hàm thêm vào từ thư viện của TypeScript. Logic được đóng gói trong \_\_extends là giống y hệt như những gì chúng ta đã thảo luận ở phần trước.

Với Babel và TypeScript càng ngày càng được đón nhận nồng nhiệt, class tiêu chuẩn và kế thừa dựa trên class trở thành 1 cách chuẩn của phần cấu trúc những ứng dụng Javascript. Điều này đẩy nhanh tiến độ về native support (hỗ trợ tự nhiên) cho class trên trình duyệt.

# Native support (hỗ trợ tự nhiên)

Vào năm 2014, [native support cho class](https://www.chromestatus.com/feature/4633745457938432) được giới thiệu trong Chrome. Nó cho phép cú pháp khai báo class được thực hiện mà không cần phải dùng đến các thư viện hay transpiler.
![](https://cdn-images-1.medium.com/max/1000/0*jJuHfRMipW8PPcb0)

Quá trình triển khai class một cách tự nhiên được gọi là syntax sugar (cú pháp ngọt ngào). Đây chỉ là 1 cú pháp dễ chịu có thể biên dịch xuống thành cùng loại với kiểu nguyên thủy đang được hỗ trợ mặc định trong ngôn ngữ. Bạn có thể dùng kiểu định nghĩa class mới, dễ dùng hơn, nhưng cuối cùng nó cũng quay về tạo constructor và gán prototypes

![](https://cdn-images-1.medium.com/max/1000/0*c2HpOiUYMimMXHv2)

# Sự hỗ trợ của V8

Cùng xem cách hoạt động của native support cho class trong ECMAScript 2015 trên V8\. Như ta đã thảo luận ở [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-14---Parsing--Abstract-Syntax-Tree---meo-giam-toi-da-thoi-gian-parse), đầu tiên cú pháp mới cần được parse thành code Javascript cũ và thêm vào cây AST. Vì thế kết quả của định nghĩa class là 1 node mới (loại [ClassLiteral](https://github.com/v8/v8/blob/a86fa968136f0ec6237f51a0d535fbd932868d4d/src/ast/ast.h#L2421)) được thêm vào cây.

Node này chứa 1 vài thứ. Đầu tiên, nó giữ constructor ở 1 hàm khác. Nó cũng chứa 1 danh sách các thuộc tính của class. Chúng có thể là phương thức, getter, setter, các trường public hay private. Node này cũng chứa luôn tham chiếu đến class cha mà chính class cha này lại nữa chứa constructor & danh sách các thuộc tính và class cha khác (của nó).

Một khi ClassLiteral này được [chuyển thành code](https://github.com/v8/v8/blob/be3a1df9008ee78d1101855d3044db54a203f515/src/interpreter/bytecode-generator.cc#L1818), nó được dịch 1 lần nữa thành các hàm và prototypes.

Với team tại [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=classes-inheritance-transpiling-outro), tối ưu hóa từng phần nhỏ của code là cực kỳ quan trọng những cũng là 1 công việc rất thách thức. Có 2 lý do cho việc cần thiết phải tối ưu hóa mức độ cao.

Đầu tiên, thư viện của họ sẽ tích hợp với trong webapp, nó thu thập dữ liệu từ phiên làm việc của user, chẳng hạn như sự kiện, thay đổi trên DOM, dữ liệu mạng, biệt lệ, thông báo lỗi, vân vân. Thu thập thông tin mà không làm ảnh hưởng đến hiệu năng của webapp là 1 thách thức khó mà team của tác giả đã giải quyết thành công.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p15-ben-trong-class-inheritance-transpiling-voi-babel-typescript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p15-ben-trong-class-inheritance-transpiling-voi-babel-typescript</guid>
            <pubDate>Sun, 25 Nov 2018 16:37:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P14: Parsing, Abstract Syntax Tree & mẹo giảm tối đa thời gian parse]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 14 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

# Khái quát

Chúng ta đều biết rằng những thứ lộn xộn có thể hợp thành 1 thứ lớn hơn gọi là Javascript. Một đoạn code không chỉ có thể di chuyển qua mạng mà nó còn phải được parse, biên dịch sang bytecode và cuối cùng thực thi. Trong các bài trước, chúng ta đã thảo luận về những thứ chẳng hạn như JS engine, runtime, callstack cũng như engine V8 được dùng chủ yếu trong Chrome và NodeJS. Tất cả đều đóng vai trò quan trọng trong toàn bộ quá trình thực thi của Javascript. Chủ đề mà chúng ta sẽ tìm hiểu hôm nay cũng không kém quan trọng: chúng ta sẽ nghiên cứu xem làm thế nào mà đa số các engine JS parse văn bản thành một thứ gì đó có nghĩa đối với máy móc, những gì xảy ra sau đó và làm thế nào để web developer như chúng ta có thể tận dụng những kiến thức đó làm điểm mạnh.

# Ngôn ngữ lập trình hoạt động như thế nào?

Cùng lùi lại 1 chút và xem xem ngôn ngữ lập trình hoạt động thế nào. Không cần biết là bạn đang xài ngôn ngữ gì, bạn sẽ luôn cần một phần mềm có thể đọc mã nguồn và khiến cho máy tính thực hiện một điều gì đó. Phần mềm này có thể là trình thông dịch hoặc trình biên dịch.

Không cần biết bạn đang xài ngôn ngữ thông dịch (Javascript, Python, Ruby) hay ngôn ngữ biên dịch (C#, Java, Rust), luôn luôn có 1 điểm chung giữa chúng: parse đoạn mã nguồn từ văn bản gốc thành một cấu trúc dữ liệu được gọi là Abstract Syntax Tree (AST).

Các AST không chỉ thể hiện mã nguồn dưới dạng cấu trúc mà chúng còn đóng vai trò quan trọng trong phân tích ngữ nghĩa, chính là nơi mà trình biên dịch xác nhận tính đúng đắn và cách sử dụng phù hợp của chương trình cũng như các phần tử của ngôn ngữ. Về sau, các AST được dùng để sinh ra bytecode hoặc mã máy.

# Các ứng dụng AST

AST không chỉ được dùng trong trình thông dịch và trình biên dịch ngôn ngữ, chúng còn có nhiều ứng dụng trong thế giới máy tính. Một trong số đó là dùng chúng là phân tích code tĩnh. Các nhà phân tích tĩnh không thực thi code, họ cần hiểu cấu trúc của code. Ví dụ: bạn muốn triển khai một công cụ tìm sự giống nhau giữa các kiến trúc code để từ đó bạn có thể refactor nhằm giảm sự trùng lặp. Bạn có thể làm việc này bằng cách so sánh string bình thường nhưng cách triển khai thì khá cơ bản và giới hạn.

Một cách tự nhiên, nếu bạn có hứng thú triển khai một công cụ thì bạn không cần phải viết riêng cho nó 1 cái parser. Có rất nhiều triển khai mã nguồn mở có sẵn có khả năng tương thích toàn diện với thông số kỹ thuật của Ecmascript. Ví dụ: Esprima và Acorn. Cũng có rất nhiều công cụ có thể giúp ta với sản phẩm nhận được từ parser, hay còn gọi là AST. Các AST cũng được dùng nhiều trong phần triển khai của các code transpiler. Ví dụ: bạn cần triển khai một bộ transpiler để chuyển code Python thành Javascript. Ý tưởng cơ bản là ta cần một Python transpiler để sinh ra cây AST - thứ mà ta cần để có thể sinh ra code Javascript sau này.

Bạn có thể tự hỏi, làm sao như vậy được? Điểm mấu chốt là các AST chỉ là một điểm khác biệt về cách thể hiện một vài ngôn ngữ. Trước khi parse, nó thể hiện dưới dạng văn bản đi kèm theo một số quy luật nhất định để hình thành nên 1 ngôn ngữ. Sau khi parse, nó thể hiện dưới dạng một kiến trúc dạng cây chứa chính xác cùng 1 thông tin với văn bản đầu vào. Vì thế, bạn có thể luôn luôn có thể làm ngược lại và go back về dạng biểu diễn văn bản.

# Javascript parsing

Giờ thì cùng tìm hiểu cây AST được xây dựng như thế nào. Đầu tiên ta có một hàm Javascript đơn giản như sau:

```javascript
function foo(x) {
  if (x > 10) {
    var a = 2;
    return a * x;
  }

  return x + 10;
}
```

Parser sẽ sản sinh ra cây AST như sau:
![](https://cdn-images-1.medium.com/max/1000/0*mSOIiWpkctkD0Gfg.)

Lưu ý rằng vì mục đích dễ nhìn và đẹp thì hình trên chỉ là phiên bản tối giản của sản phẩm thực sự từ parser. Cây AST thật sẽ phức tạp hơn rất nhiều. Tuy nhiên, mục đích của chúng ta là có được ý tưởng cơ bản về việc mã nguồn sẽ biến thành cái gì trước khi nó được thực thi. Nếu bạn muốn xem cây AST thứ thiệt trông như thế nào thì bạn có thể [vào đây](https://astexplorer.net/). Đó là 1 công cụ online, bạn chỉ cần nhập code Javascript vào và nó sẽ sinh ra cây AST cho đoạn code đó.

Bạn sẽ tự hỏi tại sao chúng ta cần biết về cách hoạt động của Javascript parser. Sau tất cả thì nó thuộc về trách nhiệm của trình duyệt. Và về mặt nào đó thì đúng là như thế. Tuy nhiên, bạn có thể xem hình bên dưới, đó là đồ thị biểu diễn tổng thời gian phân phối cho từng bước trong quá trình thực thi code Javascript. Hãy nhìn kỹ hơn và thử xem có thấy được gì thú vị không.
![](https://cdn-images-1.medium.com/max/1000/0*eEArxn147Ev8xf5n.)

Bạn có thấy được không? Nhìn kỹ xem. Trung bình thì trình duyệt chiếm khoảng 15-20% tổng thời gian thực thi để parse Javascript. Những con số này không phải là bịa đặt. Chúng là số liệu thống kê từ những ứng dụng và website có thật đang bằng cách này hay cách khác sử dụng Javascript. Giờ thì 15% có vẻ như không nhiều lắm, nhưng tin tôi đi, nó có giá trị đấy. Một app SPA tiêu chuẩn sẽ load khoảng 0.4MB code Javascript và trình duyệt tiêu tốn xấp xỉ 370ms để parse nó.

Thêm một lần nữa, bạn sẽ nói rằng nó chẳng đáng bao nhiêu thời gian cả. Và rõ ràng con số đó quá nhỏ. Tuy nhiên nhớ kỹ rằng đây chỉ là thời gian cần để parse code Javascript thành cây AST. Chưa bao gồm thời gian thực thi chính nó hay bất kỳ tiến trình nào diễn ra trong khi load trang (ví dụ như [CSS & HTML rendering](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-11---Render-engine---meo-toi-uu-hoa-hieu-nang-render)). Và tất cả thông số này mới chỉ thể hiện cho desktop. Khi chúng ta đi sâu hơn trên mobile, mọi thứ sẽ trở nên phức tạp hơn nhiều. **Thời gian dành cho việc parse trên mobile thường có thể nhiều hơn 2-5 lần so với trên desktop.**

![](https://cdn-images-1.medium.com/max/1000/0*3R6-AyKY1831P10d.)

Đồ thị trên thể hiện thời gian parse của 1 gói code Javascript 1MB trên rất nhiều thiết bị mobile & desktop thuộc nhiều phân khúc khác nhau.

Gì nữa nào? Web app đang càng trở nên phức tạp theo từng phút cũng như càng có nhiều business logic phải xử lý ở phía client để có thể mang lại trải nghiệm giống hệt như native app. Bạn có thể dễ dàng hiểu được những điều đó ảnh hưởng như thế nào đến website/wepapp của bạn. Tất cả những gì bạn cần là mở dev tool của trình duyệt lên và để nó đo đạc lượng thời gian dành cho parsing, biên dịch và mọi thứ diễn ra trên trình duyệt cho tới khi trang web được load hoàn toàn.
![](https://cdn-images-1.medium.com/max/1000/0*A5ucCHOZsxXyHMfN.)

Thật không may, không có dev tool nào cho các trình duyệt mobile. Nhưng đừng lo lắng, điều này không có nghĩa rằng bạn không thể làm gì được. Đây là lý do những công cụ như [DeviceTiming](https://github.com/danielmendel/DeviceTiming) tồn tại. Nó có thể giúp bạn đo đạc thời gian parse và thực thi cho các đoạn code trong một môi trường kiểm soát. Nó hoạt động bằng cách gói gọn code local với đoạn code đo lường, vì thế nên mỗi lần trang web của bạn được truy cập từ các thiết bị khác nhau, bạn có thể đo đạc thời gian parse và thực thi.

Điều tốt là engine Javascript đã làm rất nhiều thứ nhằm tránh cách công việc thừa thãi và tối hưu hóa nhiều hơn. Dưới đây là 1 vài thứ mà các engine của những trình duyệt lớn đã làm.

Ví dụ với V8, nó thực hiện script streaming & code caching. Script streaming nghĩa là các đoạn code bất đồng bộ & bị trì hoãn sẽ được parse trong 1 tiến trình riêng ngay khi quá trình download bắt đầu. Nó giúp cho quá trình parsing gần như hoàn thành ngay lập tức sau khi đoạn code (script) được tải xong. Kết quả là các trang sẽ load nhanh hơn khoảng 10%.

Code Javascript thường được biên dịch thành bytecode mỗi khi có một lượt truy cập trang. Tuy nhiên, cục bytecode này lại bị bỏ đi khi người dùng truy cập đến trang khác. Điều này xảy ra vì code được biên dịch phụ thuộc rất nhiều vào trạng thái và ngữ cảnh của máy tại thời điểm biên dịch. Đây là lý do Chrome 42 giới thiệu bytecode caching (bộ đệm bytecode). Đây là một kỹ thuật lưu trữ code đã biên dịch ở local để khi user quay trở lại trang cũ trước đó thì tất cả mọi hoạt động như download, parse, biên dịch... có thể bỏ qua. Nó cho phép Chrome tiết kiệm 40% thời gian parse & thực thi. Thêm nữa, kết quả nó tiết kiệm pin nhiều hơn nếu chạy trên các thiết bị mobile.

Trong Opera, engine [Carakan](https://dev.opera.com/blog/carakan/) có thể dùng lại kết quả biên dịch từ chương trình khác vừa mới được biên dịch gần đây. Không có các yêu cầu cụ thể nào về việc code phải đến từ cùng 1 trang hay domain. Kỹ thuật caching này thực sự rất hữu ích và có thể hoàn toàn bỏ qua bước biên dịch. Nó phụ thuộc vào hành vi tiêu chuẩn của user và ngữ cảnh lươt web: mỗi khi user thực hiện cùng chuỗi hành trình với một user khách trên app/website thì cùng 1 đoạn code Javascript sẽ được tải. Tuy nhiên, Opera đã sớm thay thế Carakan bằng Google V8.

Bộ engine [SpiderMonkey](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey) của Firefox không lưu cache bất kỳ thứ gì. Nó đại khái là chuyển qua dùng một thao tác giám sát để đếm xem 1 đoạn code Javascript được thực thi bao nhiêu lần. Dựa trên số đếm này nó xác định phần nào của code đang hot và cần được tối ưu hóa.

Rõ ràng có một số người lựa chọn không làm gì cả. [Maciej Stachowiak](http://en.wikipedia.org/wiki/Maciej_Stachowiak), lead developer của Safari, chỉ định rằng Safari không thực hiện bất kỳ hoạt động cache nào cho bytecode đã biên dịch. Có vẻ như họ đã có cân nhắc về việc này nhưng không triển khai nó bởi vì nó chỉ nhỏ hơn 2% tổng thời gian thực thi.

Những hoạt động tối ưu hóa không trực tiếp ảnh hưởng đến chuyện parsing của code Javascript nhưng chúng chắc chắn đang làm tốt nhất có thể để bỏ qua nó một cách hoàn toàn. Còn cách tối ưu hóa nào tốt hơn là tối ưu hóa hoàn toàn?

Có nhiều thứ chúng ta có thể làm để cải thiện thời gian load app ban đầu. Ta có thể làm tối giản lượng code Javascript đang sử dụng: ít code, ít parse, ít thực hi. Để làm được điều này, ta cần đưa ra vừa đúng lượng code cần thiết cho một tính năng cụ thể thay vì load 1 cục thiệt to lớn và dùng nó vào mọi thứ. Ví dụ, pattern [PRPL](https://developers.google.com/web/fundamentals/performance/prpl-pattern/) có thuyết giảng về mô hình chuyển giao code như vậy. Nói cách khác, ta có thể kiểm tra các dependency và xem nếu như có gì đó thừa thãi không cần thiết làm chậm code của chúng ta. Về phần này thì hi vọng là sẽ có 1 topic riêng để nói về nó.

Mục đích của bài viết này là để thảo luận chúng ta - những web developer - có thể làm được gì để giúp cho Javascript parser có thể chạy nhanh hơn. Và chính là đây, các Javascript parser hiện đại sử dụng các phỏng đoán để xác định nếu một đoạn code cụ thể nào đó chuẩn bị được thực thi ngay hoặc quá trình thực thi sẽ bị tạm ngưng và dời lại trong một thời điểm khác.

Dựa trên các phỏng đoán, parser sẽ làm hoặc là eager parsing (parse nhanh) hoặc là lazy parsing (parse từ từ). Eager parsing chạy xuyên suốt các hàm nào cần được biên dịch tức thời. Nó thực hiện 3 việc chính: xây dựng cây AST, xây dựng hệ thống cấp bậc (hierarchy) cho scope và tìm tất cả các lỗi cú pháp.

Lazy parsing thì ngược lại, nó chỉ được dùng cho các hàm chưa cần được biên dịch. Nó không xây dựng cây AST và cũng không tìm lỗi cú pháp. Nó chỉ xây dựng hệ thống cấp bậc cho scope và tiết kiệm được một nửa thời gian so với eager.

Rõ ràng đây không phải là ý tưởng mới. Kể cả trình duyệt như IE9 cũng hỗ trợ tối ưu hóa mặc dù nó chạy hơi thô sơ nếu như so với cách mà parser ngày nay hoạt động.

Giờ thì cùng xem một ví dụ về cách nó hoạt động. Giả sử ta có đoạn code sau:

```javascript
function foo() {
  function bar(x) {
    return x + 10;
  }

  function baz(x, y) {
    return x + y;
  }

  console.log(baz(100, 200));
}
```

Giống như ví dụ trước, code được đưa vào parser để phân tích cú pháp và trả ra cây AST. Vậy thì đây là những gì thực hiện theo từng dòng:

Định nghĩa hàm bar nhận 1 biến x và nó có 1 câu lệnh return trả về kết quả của phép tính cộng giữa x và 10.

Định nghĩa hàm baz nhận 2 biến (x và y). Nó có 1 câu lệnh return. Hàm này trả về kết quả của phép tính cộng giữa x và y.

Gọi hàm baz với 2 đối số là 100 và 200.

Tạo ra 1 lời gọi hàm đến console.log với giá trị là kết quả của lời gọi hàm trước đó.

![](https://cdn-images-1.medium.com/max/1000/0*60xiqW7kPsQg5ssn.)

Điều gì vừa xảy ra vậy? Parser thấy có một định nghĩa hàm foo, định nghĩa bar và 1 hàm baz, một lời gọi đến hàm baz, một lời gọi đến hàm console.log. Chờ đã... có một số thứ parser đã làm hoàn toàn không liên quan. Đó là việc parse hàm bar. Tại sao lại không liên quan? Bởi vì hàm bar chưa bao giờ được gọi (ít nhất là cho tới thời điểm này). Đây chỉ là một ví dụ đơn giản và có vẻ như không bình thường nhưng nó xuất hiện trên rất nhiều app thực, có rất nhiều hàm được định nghĩa nhưng không bao giờ dùng đến.

Thay vì parse hàm bar, chúng ta có thể đánh dấu nó đã được khai báo nhưng không chỉ ra cụ thể nó làm gì. Parsing sẽ diễn ra khi cần thiết ngay trước khi hàm được thực thi. Và dĩ nhiên là lazy parsing cũng vẫn cần thiết để tìm toàn bộ body của hàm và tạo một khai báo cho hàm đó. Nó không cần cây cú pháp bởi vì nó vẫn chưa được xử lý. Thêm nữa, bộ nhớ heap vẫn chưa được cấp phát (phần này cũng chiếm 1 lượng tương đối trong tài nguyên hệ thống). Nói ngắn gọn thì bỏ qua một số bước trên sẽ cải thiện đáng kể hiệu năng.

Vậy nên nhìn lại ví dụ trên, ta có cây AST mới sẽ như thế này:
![](https://cdn-images-1.medium.com/max/1000/0*IN688nPbgu8zYETe.)

Lưu ý rằng hàm bar được khai báo và chấp nhận, nhưng chỉ có thế thôi. Chúng ta không làm gì với body của hàm. Trong trường hợp này, body của hàm chỉ có 1 câu lệnh return. Tuy nhiên, trong hầu hết các ứng dụng thực tế, nó có thể lớn hơn rất nhiều, bao gồm nhiều câu lệnh return, điền kiện, vòng lặp, định nghĩa các biến và kể cả các khai báo hàm lồng nhau. Tất cả những thứ này sẽ gây tốn thời gian cũng như tài nguyên hệ thống bởi vì hàm không bao giờ được gọi.

Đây là một ý tưởng cực kỳ đơn giản nhưng trong thực tế công việc thì việc triển khai nó lại không đơn giản. Dưới đây là một ví dụ mà chắc chắn không phải là trường hợp duy nhất. Toàn bộ phương thức sử dụng các hàm, vòng lặp, điều kiện, object, vân vân. Cơ bản là toàn bộ code cần được parse.

Ví dụ một mô hình phổ biến để triển khai Javascript module:

```javascript
var myModule = (function () {
  // toàn bộ logic của module
  // return về module.
})();
```

Mô hình này dễ dàng nhận ra bởi các Javascript parser hiện đại và là một dấu hiệu cho thấy code bên trong có thể dùng eager parsing.

Vậy tại sao parser không mặc định lazy parsing? Nếu có gì đó được parse lazy thì nó phải được thực thi ngay lập tức và điều này thực sự gây ra sự chậm chạp. Một lazy parse được thực hiện và ngay sau đó là eager parse. Kết quả là tốc độ chậm hơn 50% khi so sánh với chỉ dùng 1 eager parse.

Đến lúc này ta đã có kiến thức cơ bản về phía hậu trường, giờ thì thử xem chúng ta có giúp gì cho parser được không. Ta có thể viết code theo cách mà các hàm có thể được parse tại thời điểm phù hợp. Có một pattern được xài chung giữa các parser: đóng gói hàm bên trong dấu ngoặc (). Đây luôn là một dấu hiệu tích cực cho parser hiểu rằng hàm sẽ được thực thi ngay lập tức. Nếu parser bắt gặp một dấu mở ngoặc ( và ngay liền sau đó là một định nghĩa hàm, nó sẽ parse eager hàm đó. Chúng ta có thể giúp parser bằng cách khai báo hàm một cách tường minh như vậy hàm sẽ được thực thi ngay lập tức.

Giả sử ta có hàm Javascript như sau:

```javascript
function foo(x) {
  return x * 10;
}
```

Bởi vì không có dấu hiệu rõ ràng rằng hàm sẽ được thực thi ngay lập tức nên trình duyệt sẽ thực hiện lazy parse. Tuy nhiên, chúng ta biết rằng như vậy là không đúng nên ta có thể làm 2 việc.

Đầu tiên, ta lưu hàm vào trong 1 biến:

```javascript
var foo = function foo(x) {
  return x * 10;
};
```

Lưu ý rằng ta vẫn giữ lại tên hàm foo giữa từ khóa function và dấu mở ngoặc (. Điều này tuy không cần thiết nhưng bạn bên làm vì trong trường hợp xử lý biệt lệ, stacktrace sẽ hiện ra tên cụ thể của hàm thay vì một chữ `<anonymous>` khô khan.

Parser vẫn thực hiện lazy parse. Ta có thể ngăn chặn điều này bằng cách thêm một chi tiết nhỏ: gói hàm đó lại trong dấu ngoặc.

```javascript
var foo = function foo(x) {
  return x * 10;
};
```

Tại thời điểm này, khi parser thấy dấu mở ngoặc ( ngay trước từ khóa function nó sẽ ngay lập tức thực hiện eager parsing.

Sẽ hơi khó để quản lý bởi vì chúng ta sẽ cần phải biết trong trường hợp nào thì parser chọn parse lazy hay eager. Thêm nữa ta cần phải suy nghĩ và tìm hiểu một hàm cụ thể nào đó có được gọi ngay lập tức hay không. Chúng ta chắc chắn không muốn làm vậy. Ít nhất thì nó sẽ làm cho code khó đọc & khó hiểu hơn. Công cụ như Optimize.js có thể giúp ta rất nhiều. Mục đích duy nhất của nó là tối ưu hóa thời gian loaing ban đầu của code Javascript. Chúng thực hiện phân tích code tĩnh và chỉnh sửa lại để đóng gói những hàm nào cần được thực thi bên trong dấu ngoặc (), trình duyệt sẽ có thể parse eager và chuẩn bị chúng sẵn sàng để thực thi.

Chúng ta có thể tiếp tục code bình thường và có đc đoạn code sau:

```javascript
(function () {
  console.log("Hello, World!");
})();
```

Mọi thứ có vẻ tốt, hoạt động đúng như mong đợi và nhanh nữa. Bởi vì có dấu mở ngoặc ( trước khi khai báo hàm. Rất tuyệt. Dĩ nhiên rồi, trước khi đưa lên production ta cần minify để tiết kiệm dung lượng. Đoạn code sau là sản phẩm cuối cùng:

```javascript
!(function () {
  console.log("Hello, World!");
})();
```

Một lần nữa, chúng có vẻ tốt phải không? Code hoạt động y như cũ. Nhưng có gì đó thiếu thiếu. Trình minify đã gỡ dấu ngoặc đóng gói bên ngoài hàm và thay vào đó thêm 1 dấu chấm than ! ngay trước hàm. Điều này nghĩa là parser sẽ bỏ qua nó và thực hiện lazy parse. Trên hết thì để có thể thực thi hàm nó sẽ thực hiện eager parse ngay sau khi lazy parse. Vậy thì lại làm code chạy chậm hơn. May mắn thay, chúng ta có những công cụ như Optimize.js giúp ta trong những trường hợp này. Truyền đoạn code đã minify vào Optimize.js và đây là kết quả đầu ra:

```javascript
!(function () {
  console.log("Hello, World!");
})();
```

Giờ thì ta đã có thành phẩm tốt nhất: code được minify và parser dễ dàng xác định được những hàm nào cần parse eager hàm nào cần parse lazy.

# Biên dịch trước (Pre-compilation)

Vậy tại sao ta không thực hiện toàn bộ các bước này ở phía server. Dĩ nhiên thì sẽ tốt hơn nếu chúng ta thực hiện 1 lần rồi triển khai kết quả cho tất cả client, thay vì bắt mỗi client phải thực hiện nó mỗi lần chạy. Thật ra thì có những thảo luận về việc engine nên cung cấp một cách để thực thi những đoạn code đã được biên dịch trước để đỡ tốn thời gian cho trình duyệt.

Về bản chất thì ý tưởng chính là có một công cụ ở phía server có thể sinh ra bytecode rồi truyền trực tiếp về phía client và thực thi. Nếu thực sự được như vậy thì thời gian khởi động app phía client sẽ được cải thiện đáng kể. Nghe rất hấp dẫn, nhưng mọi việc không đơn giản như vậy.

Điều này có thể gây ra hiệu ứng ngược lại, hiệu ứng lớn là đằng khác, vì hầu hết code có thể sẽ cần phải được ký & xử lý vì những lý do bảo mật. Đội ngũ V8 đang làm việc nội bộ với nhau để tránh re-parsing để quá trình biên dịch trước sẽ có lợi ích như thế.

# Một vài mẹo vặt bạn có thể thực hiện để app chạy nhanh hơn

- Kiểm tra các dependency. Loại bỏ những thứ không cần thiết.
- Chia nhỏ code thành nhiều phần nhỏ hơn thay vì load nguyên 1 cục bự.
- Trì hoãn quá trình load Javascript nếu có thể. Bạn chỉ cần load phần code nào cần thiết dựa trên route hiện tại mà thôi.
- Dùng dev tool & DeviceTiming để tìm hiểu phần nào đang bị thắt cổ chai.
- Dùng công cụ như Optimize.js để giúp parser quyết định khi nào nên parse eager & lazy.

SessionStack là công cụ hỗ trợ tái tạo lại mọi thứ xảy ra đối với người dùng cuối tại thời điểm họ gặp phải vấn đề khi đang tương tác với webapp. Công cụ này không dựng lại phiên làm việc đó thành 1 video thật mà chỉ giả lập tất cả các sự kiện trong một môi trường sandbox trên trình duyệt. Điều này có ý nghĩa nhất định, ví dụ trong trường hợp codebase của page hiện tại lớn và phức tạp.

Những kỹ thuật trên là những thứ mà team tác giả gần đây kết hợp trong quá trình phát triển SessionStack. Những tối ưu hóa đó cho phép họ load SessionStack nhanh hơn. SessionStack chạy càng nhanh nó càng có thể giải phóng tài nguyên của trình duyệt nhanh hơn và mang lại trải nghiệm một cách liên tục & tự nhiên cho người dùng khi họ load & xem lại các session làm việc.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p14-parsing-abstract-syntax-tree-meo-giam-toi-da-thoi-gian-parse</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p14-parsing-abstract-syntax-tree-meo-giam-toi-da-thoi-gian-parse</guid>
            <pubDate>Sun, 25 Nov 2018 16:32:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P13: Bên trong CSS & JS animation & các giải pháp tối ưu hiệu năng của nó]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 13 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

# Khái quát

Mọi người đã biết rõ animation đóng vai trò cần thiết trong việc tạo ra các webapp hấp dẫn. Khi người dùng dần dần chuyển sự chú ý của họ sang UX và các doanh nghiệp bắt đầu nhận ra sự quan trọng của trải nghiệm người dùng thú vị & hoàn hảo thì các ứng dụng web dần trở nên nặng nề hơn & cần thể hiện nhiều UI động hơn. Tất cả những thứ này cần đến các animation phức tạp để tạo ra các chuyển dịch trạng thái mượt mà xuyên suốt hành trình trải nghiệm của người dùng. Giờ đây thì điều đó không còn là thứ gì đặc biệt nữa. User càng lúc càng giỏi và họ mong đợi ở những giao diện người dùng có tính tương tác và phản hồi cao.

Tuy nhiên animating giao diện không nhất thiết phải đơn giản, minh bạch. Thứ gì cần được animated, khi nào và cảm giác mà một animation mang lại, đó mới là những câu hỏi khó trả lời.

# So sánh Javascript & CSS animation

Có 2 phương pháp chính để tạo web animation là dùng Javascript hoặc CSS. Không có lựa chọn nào đúng hay sai cả, tất cả tùy thuộc vào thứ mà bạn muốn đạt được.

## Animate với CSS

Animating với CSS là cách đơn giản nhất để làm một thứ gì đó chuyển động trên màn hình.

Chúng ta sẽ bắt đầu với một ví dụ nhanh về việc di chuyển một phần tử 50px theo cả 2 trục X và Y. Có thể thực hiện bằng cách đặt một CSS transition với thời gian 1000ms.

```css
.box {
  -webkit-transform: translate(0, 0);
  -webkit-transition: -webkit-transform 1000ms;

  transform: translate(0, 0);
  transition: transform 1000ms;
}

.box.move {
  -webkit-transform: translate(50px, 50px);
  transform: translate(50px, 50px);
}
```

Khi class move được thêm vào, giá trị transform bị thay đổi và transition bắt đầu.

Bên cạnh transition duration (thời gian dịch chuyển), có những tùy chọn cho **easing**, về bản chất thì đây là cảm giác của animation. Chúng ta sẽ tìm hiểu easing chi tiết hơn trong các phần sau của bài viết này.

Nếu như trong đoạn code trên, bạn tạo ra những class CSS riêng biệt để quản lý animation thì bạn có thể dùng Javascript để tắt/mở mỗi animation.

Nếu như bạn có phần tử sau:

```html
<div class="box">Sample content.</div>
```

Bạn có thể dùng Javascript để tắt/mở animation của nó:

```javascript
var boxElements = document.getElementsByClassName("box"),
  boxElementsLength = boxElements.length,
  i;

for (i = 0; i < boxElementsLength; i++) {
  boxElements[i].classList.add("move");
}
```

Đoạn code trên lấy tất cả những phần tử có class box và thêm class move vào để trigger animation.

Làm như thế này tạo sự cân bằng cho app của bạn. Bạn có thể tập trung vào quản lý trạng thái với Javascript và chỉ cần đơn giản đặt những class thích hợp vào phần tử cần phải đặt, để cho trình duyệt xử lý các animation. Nếu bạn tiếp tục tìm hiểu theo hướng này, bạn có thể listen sự kiện transitioned trên mỗi phần tử, nhưng chỉ nếu như bạn phải support cho mấy phiên bản cũ của IE:

![](https://cdn-images-1.medium.com/max/1000/1*Qm9OFPq3siW0tCKfa03DqQ.png)

Listen sự kiện transitioned (được bắn ra tại cuối thời điểm transition) giống như thế này:

```javascript
var boxElement = document.querySelector(".box"); // Lấy phần tử đầu tiên có class `box`
boxElement.addEventListener("transitionend", onTransitionEnd, false);

function onTransitionEnd() {
  // Xử lý sự kiện transition đã hoàn thành.
}
```

Thêm nữa, khi sử dụng CSS transition, bạn có thể dùng CSS animation, nó cho phép bạn có quyền nhiều hơn để kiểm soát mỗi animation keyframe, duration và iteration.

> Keyframes được dùng để hướng dẫn chỉ định trình duyệt những giá trị của thuộc tính CSS cần phải có tại mỗi thời điểm nhất định và nó sẽ giúp xử lý phần còn lại.

Ví dụ:

```javascript
/**
 * Đây là phiên bản đơn giản, không có
 * tiền tố vendor. Nếu có thêm chúng thì
 * sẽ còn dài dòng hơn nữa.
 */
.box {
  /* Chọn animation */
  animation-name: movingBox;

  /* duration của animation */
  animation-duration: 2300ms;

  /* số lần mà ta muốn animation chạy */
  animation-iteration-count: infinite;

  /* làm cho animation đảo ngược vào mỗi vòng lặp lẻ */
  animation-direction: alternate;
}

@keyframes movingBox {
  0% {
    transform: translate(0, 0);
    opacity: 0.4;
  }

  25% {
    opacity: 0.9;
  }

  50% {
    transform: translate(150px, 200px);
    opacity: 0.2;
  }

  100% {
    transform: translate(40px, 30px);
    opacity: 0.8;
  }
}
```

Animation trông như thế này đây: [https://sessionstack.github.io/blog/demos/keyframes/](https://sessionstack.github.io/blog/demos/keyframes/)

Với CSS animation, bạn định nghĩa chính animation độc lập với phần tử đích và sử dụng thuộc tính animation-name để chọn animation được yêu cầu.

Các CSS animation phần nào được đặt sẵn tiền tố vender, với -webkit- đang được sử dụng trong Safari, Safari Mobile và Android. Chrome, Opera, Internet Explorer và Firefox tất cả đều không có sẵn tiền tố. Nhiều công cụ có thể giúp bạn thêm phiên bản tiền tố của CSS mà bạn cần, cho phép bạn viết code mà không cần phải thêm tiền tố.

## Animate với Javascript

Tạo animation với Javascript phức tạp hơn nhiều so với sử dụng CSS transition hay animation nhưng thường thì nó cung cấp cho developer nhiều sức mạnh đáng kể.

Javascript animation được viết nội tuyến như là 1 phần của code. Bạn cũng có thể đóng gói nó bên trong các object. Bên dưới là code Javascript mà bạn cần để viết lại đoạn CSS transition ở phần trên:

```javascript
var boxElement = document.querySelector(".box");
var animation = boxElement.animate(
  [{ transform: "translate(0)" }, { transform: "translate(150px, 200px)" }],
  500
);
animation.addEventListener("finish", function () {
  boxElement.style.transform = "translate(150px, 200px)";
});
```

Mặc định thì Web Animation chỉ chỉnh sửa phần trình bày của một phần tử. Nếu như bạn muốn object của mình vẫn giữ nguyên vị trí lúc nó được di chuyển tới thì bạn nên sửa lại style của nó khi animation kết thúc. Đây là lý do tại sao chúng ta listen sự kiện finish trong code trên, đặt thuộc tính box.style.transform bằng giá trị translate(150px, 200px) thì nó sẽ thể hiện giống như trường hợp transform thứ 2 trong CSS animation ở trên.

Với Javascript animation, bạn hoàn toàn kiểm soát style của phần tử tại thời điểm bất kỳ. Nghĩa là bạn có thể làm animation chậm lại, tạm ngưng, dừng hẳn, đảo ngược và điều khiển phần tử cho tới khi phù hợp. Điều này cực kỳ hữu ích nếu bạn muốn xây dựng các ứng dụng hướng đối tượng phức tạp bởi vì bạn có thể đóng gói các hành vi của app một cách chính xác.

# Easing là gì?

Chuyển động tự nhiên làm cho user cảm thấy dễ chịu hơn với webapp của bạn và mang đến trải nghiệm UX tốt hơn.

Một cách tự nhiên, không có thứ gì di chuyển theo đường thẳng từ điểm này đến điểm khác. Thật ra thì mọi thứ đều có xu hướng tăng tốc và giảm tốc khi chúng di chuyển trong thế giới vật lý của chúng ta và có rất nhiều yếu tố khác nhau ảnh hưởng. Bộ não con người được thiết kế bẩm sinh để cảm nhận những chuyển động nên khi bạn thực hiện animation trên webapp hãy nhớ những kiến thức này.

Một vài thuật ngữ bạn cần hiểu:

- **ease in**: là khi chuyển động bắt đầu chậm và tăng tốc dần lên.
- **ease out**: chuyển động bắt đầu nhanh và giảm tốc dần.

Easing cho phép bạn tạo các animation cho cảm giác tự nhiên hơn.

## Các từ khóa cho easing

CSS transition và animation cho phép bạn chọn loại easing mà bạn muốn. Có nhiều từ khóa khác nhau ảnh hưởng đến easing của animation. Bạn cũng có thể tạo ra easing hoàn toàn của riêng bạn.

Dưới đây là 1 số từ khóa bạn có thể dùng trong CSS để điều khiển easing:

- linear
- ease-in
- ease-out
- ease-in-out

Giờ thì cùng tìm hiểu về chúng nào.

## Linear animation

Các animation không có bất cứ kiểu easing nào thì được gọi là **linear** (thẳng hàng, còn hàn lâm hơn thì "Tuyến tính").
Đồ thị thể hiện một linear animation:

![](https://cdn-images-1.medium.com/max/1000/1*M5htfOGgza04ISv_l-69zg.png)

Thời gian càng tăng thì giá trị cũng tăng với lượng tương ứng. Với chuyển động linear, mọi thứ có xu hướng thiếu tự nhiên. Nói chung bạn nên tránh sử dụng chuyển động linear.

Đây là cách triển khai một linear animation đơn giản:

```css
transition: transform 500ms linear;
```

## Ease-out animation

Như đã nói ở trên, ease out làm cho animation bắt đầu nhanh hơn so với kiểu linear trong khi đó nó lại chậm dần khi kết thúc. Đồ thị trông như thế này:
![](https://cdn-images-1.medium.com/max/1000/1*VDWQl67cmbyAFC5xL9Og4g.png)

Nhìn chung, ease out là sự lựa chọn tốt nhất cho UI bởi vì khởi động nhanh làm cho animation của bạn có cảm giác phản hồi tốt trong khi chậm dần khi kết thúc mang lại cảm giác tự nhiên do sự chuyển động không đồng nhất.

Có nhiều cách để triển khai hiệu ứng ease out nhưng cách đơn giản nhất là từ khóa ease-out trong CSS:

```css
transition: transform 500ms ease-out;
```

## Ease-in animation

Đây là kiểu đối lập lại với ease-out animation: bắt đầu chậm chạp và kết thúc nhanh. Đồ thị mô tả:

![](https://cdn-images-1.medium.com/max/1000/1*rWh8YlBn8SypiMduLiYDhA.png)

So với ease-out animation thì ease-in có hơi không bình thường vì chúng tạo ra cảm giác thiếu sự phản hồi, bởi vì chúng khởi động chậm. Kết thúc nhanh có thể cũng tạo ra cảm giác lạ tương tự, toàn bộ animation đều tăng tốc trong khi đối tượng ở thế giới thực có xu hướng giảm tốc khi dừng lại đột ngột.

Để dùng ease-in animation thì bạn có thể dùng từ khóa tương tự như trên:

```css
transition: transform 500ms ease-in;
```

## Ease-in-out animation

Đây là animation kết hợp của ease-in và ease-out. Đồ thị:

![](https://cdn-images-1.medium.com/max/1000/1*tGXhNroe8KxGN7r4UTVSHw.png)

Không nên sử dụng anmation-duration quá lâu bởi vì nó mang lại cảm giác rằng UI của bạn thiếu sự phản hồi.

Cách sử dụng ease-in-out animation:

```css
transition: transform 500ms ease-in-out;
```

## Tùy biến easing

Bạn có thể định nghĩa đường cung easing cho riêng bạn để có thể kiểm soát nhiều hơn những cảm giác mà animation có thể tạo ra.

Trên thực tế, các từ khóa ease-in, ease-out, liner, ease được nối với những đường cung Bezier ([Bézier curves](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)) đã định nghĩa sẵn, bạn có thể xem chi tiết ở [Thông số kỹ thuật của CSS transition](http://www.w3.org/TR/css3-transitions/) hoặc của [Web Animation](https://w3c.github.io/web-animations/#scaling-using-a-cubic-bezier-curve)

## Đường cung Bezier

Cùng tìm hiểu về cách hoạt động của đường cung Bezier nào.
Một cung Bezier nhận 4 giá trị, hoặc nói rõ hơn thì nó nhận vào 2 cặp số. Mỗi cặp định nghĩa tọa độ X và Y của 1 điểm kiểm soát thuộc khối cung Bezier. Điểm bắt đầu của cung Bezier có tọa độ (0, 0) và kết thúc là ở (1, 1). Bạn có thể đặt cả 2 cặp số. Giá trị X cho 2 kiểm kiểm soát phải nằm trong khoảng [0, 1] còn giá trị của Y thì có thể vượt quá giới hạn [0, 1], mặc dù thông số kỹ thuật không nói rõ là bao nhiêu.

Kể cả những thay đổi nhỏ trong giá trị X và Y của mỗi điểm kiểm soát mang đến cho bạn một cung hoàn toàn khác biệt. Ở 2 đồ thị bên dưới, cung Bezier có các điểm gần nhau nhưng khác tọa độ.

![](https://cdn-images-1.medium.com/max/1000/1*2v7G1ZJ1C-y_mWHOYQfQKQ.png)

và

![](https://cdn-images-1.medium.com/max/1000/1*P5nzyldL4rg36dZmt2RViQ.png)

Như bạn thấy thì đồ thị khá là khác nhau. Điểm kiểm soát đầu tiên có vector với giá trị sai khác là (0.045, 0.183) còn điểm thứ 2 là (-0.427, -0.054)

Còn đây là phần CSS cho đường cung thứ 2:

```css
transition: transform 500ms cubic-bezier(0.465, 0.183, 0.153, 0.946);
```

2 số đầu tiên là tọa độ X và Y của điểm kiểm soát thứ nhất, 2 số tiếp theo là của điểm kiểm soát thứ 2.

# Tối ưu hóa hiệu năng

Bạn cần phải duy trì 60 khung hình/giây (60 fps - game thủ hiểu cái này lắm nè :D) khi làm animation nếu không thì nó sẽ ảnh hưởng tiêu cực đến UX.

Và như 1 lẽ dĩ nhiên thì animation không hề miễn phí. Không phải là chuyện tiền nong, mà là hiệu năng. Animate một vài thuộc tính có thể không tốn kém như một số khác. Ví dụ: animate width và height của 1 phần tử sẽ thay đổi trạng thái hình học của nó và là nguyên nhân ảnh hưởng đến các phần tử khác trên trang bị thay đổi vị trí hoặc kích thước. Quá trình này được gọi là layout. Chúng ta cũng đã thảo luận chi tiết về layout và rendering trong [bài trước rồi](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-11---Render-engine---meo-toi-uu-hoa-hieu-nang-render).

Nói chung, bạn cần tránh animate những thuộc tính nào có thể trigger quá trình layout hoặc tô màu (paint). Với đa số các trình duyệt hiện đại thì điều này nghĩa là hạn chế animation với opacity và transform

## Will-change

Bạn có thể dùng [will-change](https://dev.w3.org/csswg/css-will-change/) để thông báo cho trình duyệt biết bạn có ý định thay đổi thuộc tính của 1 phần tử. Nó cho phép trình duyệt cài đặt sẵn sàng trước những tối hưu hóa thích hợp nhất khi bạn cần thay đổi. Tuy nhiên cũng đừng lạm dụng will-change, bởi vì làm như thế có thể làm cho trình duyệt hao tốn tài nguyên và quay ngược lại gây ra nhiều vấn đề hơn về hiệu năng.

Cách để thêm will-change cho transform và opacity:

```css
.box {
  will-change: transform, opacity;
}
```

Trình duyệt hỗ trợ:
![](https://cdn-images-1.medium.com/max/1000/1*eyaMLcORDVsCFIf5h_ygjA.png)

## Chọn Javascript hay CSS

Có lẽ bạn cũng đã thấy rằng không có câu trả lời đúng cho câu hỏi này, tùy thuộc vào nhiều yếu tố, dưới đây là những thứ bạn cần cân nhắc mỗi khi lựa chọn:

- Các animation dựa trên CSS và Web Animation được hỗ trợ native và được xử lý trong tiến trình gọi là "tiến trình tổng hợp" (compositor thread). Khác với "tiến trình chính" của trình duyệt, nơi mà styling, layout, painting và code Javascript được thực thi. Nghĩa là nếu như trình duyệt đang bận xử lý 1 số tác vụ nặng ký trên tiến trình chính thì những animation đó vẫn có thể tiếp tục thực hiện mà không bị can thiệp.
- Trong một vài trường hợp. các thay đổi đối với transform và opacity có thể được xử lý bởi tiến trình tổng hợp.
- Nếu animation trigger paint, layout hoặc cả 2 thì tiến trình chính sẽ cần phải tham gia xử lý. Trường hợp này xảy ra cho cả CSS và Javascript animation, và dĩ nhiên là việc thực hiện layout hoặc paint như vậy sẽ làm chậm bất kỳ tác vụ nào liên quan đến thực thi CSS hay Javascript

## Chọn đúng thứ để animate

Những animation tuyệt vời thường tạo nên sự thích thú và gắn kết giữa project của bạn với người dùng. Bạn có thể animate bất cứ thứ gì bạn muốn, dù là width, height, position, color, background, vân vân, nhưng cần phải chú ý đến những nút thắt cổ chai tiềm tàng về hiệu năng. Những animation được chọn lựa 1 cách bất cẩn có thể ảnh hưởng tiêu cực đến UX, vì vậy animation cần phải vừa phù hợp vừa tốt cho hiệu năng. Animate càng ít càng tốt, chỉ nên animate khi bạn cần UX trở nên tự nhiên hơn nhưng đừng lạm dụng nó.

## Dùng animation để hỗ trợ tương tác

Không nên animate chỉ vì bạn thích thế. Thay vì vậy, sử dụng animation tại những vị trí chiến lược để _củng cố_ thêm về tương tác người dùng. Tránh animation làm ngắt quãng hoặc cản trở một cách không cần thiết các hoạt động của user

## Tránh animate những thuộc tính phức tạp

Chỉ có duy nhất 1 thứ tệ hơn cả animation đặt sai chỗ chính là những animation làm cho trang web bị lag. Kiểu animation này làm cho user cảm thấy bực bội và chán nản.

Team tác giả sử dụng animation khá dễ dàng với [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=js-series-rendering-engine-outro). Nói chung, họ theo sát những nguyên tắc đã nêu ở trên nhưng cũng có một số trường hợp mà họ phải dùng animation vì sự phức tạp của UI. SessionStack phải tái tạo lại dưới dạng video toàn bộ những thứ xảy ra với người dùng cuối tại thời điểm họ gặp phải vấn đề khi đang lướt web hay dùng webapp. Để làm được điều này SessionStack tận dụng duy nhất những dữ liệu thu thập được xuyên suốt phiên làm việc: sự kiện từ user, thay đổi trên DOM, request mạng, biệt lệ, thông báo debug, vân vân. Trình chơi của họ được tối ưu hóa khá tốt để có thể render một cách chính xác và sử dụng toàn bộ dữ liệu thu thập được để giả lập chính xác đến từng pixel trình duyệt của người dùng và những thứ xảy ra trên nó, cả về khía cạnh nhìn thấy được và góc nhìn kỹ thuật.

Để đảm bảo quá trình tái tạo diễn ra một cách tự nhiên, đặc biệt với những phiên làm việc kéo dài và nặng dữ liệu, team tác giả sử dụng các animation để chỉ định chính xác hoạt động loading/buffering và bám sát các nguyên tắc tốt nhất để triển khai chúng, do đó họ không cần quá nhiều CPU và vẫn có thể để cho event loop được rảnh tay render các session.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p13-ben-trong-css-js-animation-cac-giai-phap-toi-uu-hieu-nang-cua-no</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p13-ben-trong-css-js-animation-cac-giai-phap-toi-uu-hieu-nang-cua-no</guid>
            <pubDate>Sun, 25 Nov 2018 16:11:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P12: Bên trong lớp Network + Làm sao để tối ưu hóa hiệu năng và bảo mật Javascript]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 12 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Như đã nói trong bài trước về [render engine](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-11---Render-engine---meo-toi-uu-hoa-hieu-nang-render), tác giả bài viết tin rằng sự khác biệt giữa một Javascript developer tốt (good) và tuyệt vời (great) là dev tuyệt vời không những hiểu về các thành phần cơ bản của một ngôn ngữ mà còn cả phần cốt lõi cũng như môi trường xung quanh nó.

# Nhắc sơ qua về lịch sử một chút

49 năm trước, một thứ gọi là ARPAnet được tạo ra. Nó chính là một [mạng chuyển đổi gói tin sớm](https://en.wikipedia.org/wiki/Packet_switching) và cũng là [mạng đầu tiên triển khai bộ TCP/IP](https://en.wikipedia.org/wiki/Internet_protocol_suite). Mạng này cài đặt một liên kết giữa trường đại học California và Học viện nghiên cứu Stanford. 20 năm sau, Tim Berners-Lee phát hành một lời đề nghị cho "Mesh" - thứ mà sau này được biết đến là World Wide Web. Trong 49 năm đó, internet đã đi được một quãng đường dài, bắt đầu chỉ với 2 máy tính trao đổi các gói dữ liệu và giờ đạt tới hơn 75 triệu server, 3.8 tỉ người dùng internet và 1.3 tỉ websites.

![](https://cdn-images-1.medium.com/max/1000/1*x8P3OcgcgKrEEDpgT2IKkQ.jpeg)

Trong bài này, chúng ta sẽ thử phân tích những kỹ thuật nào trình duyệt hiện đại sử dụng để tự động đẩy mạnh hiệu năng (thậm chí bạn không biết đến điều đó), và chúng ta sẽ đặc biệt soi kỹ vào lớp networking của trình duyệt. Ở cuối bài, tác giả sẽ cung cấp một số ý tưởng làm thế nào để giúp trình duyệt đẩy mạnh hơn nữa hiệu năng của webapp của bạn.

# Khái quát

Trình duyệt web hiện đại được thiết kế đặc trị cho việc truyền tải webapp/website một cách nhanh chóng, hiệu quả và an toàn bảo mật. Với hàng trăm component cùng hoạt động trên nhiều layer khác nhau, từ quản lý tiến trình và bảo mật sandbox đến các GPU pipeline, audio và video, và còn nhiều thứ khác nữa, trình duyệt trông giống như một hệ điều hành hơn là một phần mềm bình thường.

Hiệu năng tổng quát của trình duyệt được xác định bằng một cơ số các component lớn: parsing (phân giải), layout, tính toán style, quá trình thực thi Javascript & WebAssembly, rendering và dĩ nhiên là cả **networking stack** (ngăn xếp mạng).

Các kỹ sư thường nghĩ rằng networking stack là một nút cổ chai. Điều này xảy ra thường xuyên vì tất cả các tài nguyên đều cần phải được lấy về từ internet trước khi các bước còn lại được thực hiện. Với networking layer, để hoạt động hiệu quả nó cần phải đóng vai trò nhiều hơn là một bộ quản lý socket đơn giản. Với chúng ta, nó như một thứ núp dưới dạng một cơ chế rất đơn giản để kéo tài nguyên về nhưng đó thực sự là một nền tảng (platform) đầy đủ với các tiêu chí tối ưu hóa, APIs và service của riêng nó.

![](https://cdn-images-1.medium.com/max/1000/1*WqInzMPQGGcMX9AOONN76g.jpeg)

Là web developer, chúng ta không cần phải lo nghĩ về từng gói tin TCP hay UDP, định dạng request, caching và tất cả những thứ liên quan. Toàn bộ sự phức tạp này được trình duyệt gánh dùm nên ta chỉ cần tập trung vào ứng dụng mà chúng ta đang tạo ra. Tuy nhiên, hiểu rõ điều gì thực sự đang diễn ra bên trong có thể giúp chúng ta tạo ra app nhanh hơn và bảo mật tốt hơn.

Về bản chất thì dưới đây là những gì xảy ra khi user bắt đầu tương tác với trình duyệt:

- User nhập một URL vào thanh địa chỉ trên trình duyệt
- Giả sử URL đó chỉ đến 1 tài nguyên trên mạng, trình duyệt sẽ bắt đầu kiểm tra local cache và cache của ứng dụng và cố thử sử dụng một phải copy có sẵn ở local để đáp ứng request.
- Nếu cache không dùng được, tình duyệt sẽ lấy tên miền từ URL và yêu cầu địa chỉ IP của server từ một [DNS](https://en.wikipedia.org/wiki/Domain_Name_System). Nếu tên miền đã được cache sẵn thì không cần truy vấn đến DNS.
- Trình duyệt tạo ra một gói tin HTTP nói rằng nó yêu cầu một trang web đang cư trú tại một server từ xa.
- Gói tin được gửi đến TCP layer, layer này sẽ thêm thông tin của chính nó vào vị trí trên cùng của gói tin HTTP. Thông tin này cần thiết để duy trì phiên khởi động.
- Gói tin sau đó được trao cho IP layer với công việc chính là tìm hiểu một cách để gửi gói tin từ user đến server từ xa. Thông tin này cũng được lưu vào vị trí trên cùng của gói tin.
- Gói tin được gửi đến server từ xa.
- Khi đã nhận gói tin, một phản hồi được gửi ngược lại theo cách thức tương tự.

[Đặc tính kỹ thuật của Navigation Timing](http://www.w3.org/TR/navigation-timing/) từ W3C cung cấp một API trình duyệt cũng như khả năng hiển thị dữ liệu về thời gian và hiệu năng đằng sau mỗi request trên trình duyệt. Giờ thì cùng quan sát các component, mỗi phần sẽ đóng một vai trò quan trọng trong việc cung cấp các trải nghiệm người dùng (UX) tối ưu:

![](https://cdn-images-1.medium.com/max/1000/1*rjBdCBwOx5Gp_A6b6FQgfw.png)

Toàn bộ tiến trình networking rất phức tạp và có nhiều layer khác nhau có thể trở thành một nút cổ chai. Đây là lý do các trình duyệt cố gắng phấn đấu để cải thiện hiệu năng bản thân bằng cách sử dụng rất nhiều kỹ thuật đa dạng để giảm thiểu tối đa sự ảnh hưởng của toàn bộ giao tiếp network.

# Quản lý socket

Cùng khởi động với một số thuật ngữ nào:

- **Origin**: một bộ 3 chứa các giao thức ứng dụng, tên miền và số port (ví dụ: https, [www.example.com](http://www.example.com), 443)
- **Socket pool**: một nhóm các socket thuộc về cùng origin (tất cả các trình duyệt lớn đều giới hạn pool size lớn nhất là 6 socket).

Javascript và WebAssembly **không cho phép** chúng ta quản lý vòng đời của các network socket riêng tư, và dĩ nhiên như vậy là tốt! Điều này không những giúp chúng ta dễ dàng hơn mà còn cho phép trình duyệt tự động thực hiện rất nhiều tối ưu hóa hiệu năng, một trong số đó bao gồm: sử dụng lại socket, yêu cầu sự ưu tiên và ràng buộc muộn (late binding), giao dịch giao thức, ép buộc giới hạn kết nối, vân vân.

Thật ra các trình duyệt hiện đại đã làm tốt trong việc chia tách vòng quản lý request khỏi phần quản lý socket. Các socket được tổ chức trong các pool và được nhóm lại theo origin, mỗi pool bắt buộc phải giới hạn kết nối và các ràng buộc bảo mật. Các request chờ được xếp vào trong hàng đợi, đánh thứ tự ưu tiên và sau đó gắn kết với những socket riêng tư trong pool. Trừ khi server có ý định đóng kết nối thì cùng một socket có thể được sử dụng lại một cách tự động xuyên suốt nhiều request.

![](https://cdn-images-1.medium.com/max/1000/1*0e8X3UTBpsiBSZKa3l1hXA.png)

Bởi vì mở mới 1 kết nối TCP thường kèm theo chi phí tốn kém cho nên tái sử dụng lại các kết nối cũ sẽ đảm bảo hiệu năng tốt hơn nhiều. Mặc định thì trình duyệt sử dụng cơ chế gọi là "keepalive" (giữ cho sống) để tiết kiệm thời gian từ việc mở mới kết nối đến server khi có request được tạo ra. Thời gian trung bình để mở 1 kết nối TCP là:

- Request đến máy local: 23ms
- Request trong nội bộ châu lục: 120ms
- Request giữa các châu lục với nhau: 225ms

Kiểu kiến trúc này mở ra cánh cửa đến với rất nhiều cơ hội để tối ưu hóa. Request có thể được thực thi với những thứ tự khác nhau tùy thuộc vào độ ưu tiên của nó. Trình duyệt có thể tối ưu hóa sự phân chia băng thông giữa toàn bộ các socket hoặc là nó có thể mở socket khi dự đoán trước về một request.

Như đã nói trước đó, toàn bộ đều được quản lý bởi trình duyệt và không yêu cầu chúng ta giúp bất cứ thứ gì. Nhưng nó không nhất thiết nghĩa là chúng ta không thể làm gì. Chọn lựa đúng pattern về giao tiếp mạng, loại và tần suất transfer, lựa chọn các giao thức và tinh chỉnh/tối ưu hóa server stack có thể đóng vai trò rất lớn trong việc cải thiện hiệu năng tổng thể của ứng dụng.

Một vài trình duyệt thậm chí còn đi xa hơn. Ví dụ, Chrome có thể tự dạy cho chính nó hoạt động nhanh hơn khi bạn sử dụng nó. Nó học hỏi dựa trên những trang bạn đã ghé thăm và kiểu duyệt web điển hình cho nên nó có thể dự đoán hành vi người dùng có khả năng và thực hiện hành động trước khi user làm gì đó. Ví dụ đơn giản nhất là tự động render trước nội dung của trang khi user rê chuột lên 1 link. Nếu bạn thấy hứng thú về chủ đề tối ưu hóa của Chrome thì có thể đọc thêm chương này [https://www.igvita.com/posa/high-performance-networking-in-google-chrome/](https://www.igvita.com/posa/high-performance-networking-in-google-chrome/) nằm trong quyển sách [High-Performance Browser Networking](https://hpbn.co/)

# Bảo mật mạng và đóng gói sandbox

Cho phép trình duyệt quản lý các socket riêng biệt có một ý nghĩa rất quan trọng: bằng cách này trình duyệt cho phép áp đặt một hệ thống đồng nhất các ràng buộc về chính sách và bảo mật lên những nguồn tài nguyên ứng dụng không đáng tin cậy. Ví dụ như trình duyệt sẽ không chấp nhận API truy xuất trực tiếp vào network socket thô vì như vậy có thể cho phép các ứng dụng độc hại tạo kết nối tùy tiện đến bất cứ host nào. Trình duyệt cũng áp đặt các giới hạn kết nối để bảo vệ server cũng như client khỏi cạn kiệt tài nguyên.

Trình duyệt định dạng tất cả các request đi ra để áp đặt sự đồng nhất và các ngữ nghĩa giao thức tốt để bảo vệ server. Tương tự, giải mã response được thực hiện một cách tự động để bảo vệ user từ những server độc hại.

## Trao đổi TLS

[Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security) là một giao thức mật mã cung cấp giao tiếp bảo mật trong mạng máy tính. Nó được sử dụng rộng rãi trong nhiều ứng dụng, một trong số đó là trình duyệt web. Website có thể dùng TLS để bảo đảm an ninh cho tất cả các giao tiếp giữa server và trình duyệt web.

Toàn bộ quá trình bắt tay TLS bao gồm các bước sau:

1.  Client gửi một lời nhắn "Client hello" đến server, cùng với một giá trị ngẫu nhiên của client và bộ mã hóa được hỗ trợ.
2.  Server trả lời bằng cách gửi lời nhắn "Server hello" về cho client, cùng với giá trị ngẫu nhiên của server.
3.  Server gửi chứng chỉ xác thực của nó về cho client và có thể yêu cầu một chứng chỉ tương tự từ phía client. Server gửi lời nhắn "Server hello done".
4.  Nếu server đã yêu cầu một chứng chỉ từ client thì client phải gửi nó.
5.  Client tạo ra một Pre-Master Secret ngẫu nhiên và mã hóa nó với public key từ chứng chỉ của server, gửi Pre-Master Secret đã được mã hóa về cho server.
6.  Server nhận Pre-Master Secret. Server và client mỗi bên sẽ sinh ra Master Secret và session key (chìa khóa phiên) dựa trên Pre-Master Secret.
7.  Client gửi thông báo "Change cipher spec" đến server để xác định rằng client sẽ bắt đầu sử dụng session key mới để băm và mã hóa message. Client cũng đồng thời gửi tin nhắn "Client finished".
8.  Server nhận "Change cipher spec" và chuyển đổi trạng thái bảo mật của record layer của nó sang trạng thái bảo mật mã hóa đối xứng bằng session key. Server gửi lời nhắn "server finished" về cho client.
9.  Client và server giờ có thể trao đổi dữ liệu ứng dụng thông qua kênh bảo mật mà chúng đã thiết lập. Tất cả message được gửi từ client đến server và ngược lại đều được mã hóa bằng session key.

User được cảnh báo trong trường hợp một trong số xác thực nào đó bị sai, ví dụ: server đang dùng một chứng chỉ tự cấp.

## Chính sách cùng origin

Hai trang có cùng origin nếu như giao thức, cổng (nếu được chỉ định) và host đều giống nhau giữa 2 trang

Dưới đây là một vài ví dụ về các tài nguyên có thể được nhúng cross-origin (xuyên origin):

- Javascript với code `<script src="…"></script>`. Thông báo lỗi cú pháp chỉ tồn tại cho những đoạn script cùng origin.
- CSS với `<link rel="stylesheet" href="…">`. Do quy tắc cú pháp thoải mái của CSS nên CSS cross-origin cần một header Content-Type đúng loại. Sự hạn chế thì tùy thuộc vào trình duyệt.
- Hình ảnh với thẻ `<img />`
- File đa phương tiện với `<video>` và `<audio>`
- Plug in với `<object>`, `<embed>` and `<applet>`
- Fonts với @font-face. Vài trình duyệt cho phép các font cross-origin, một số khác thì yêu cầu fonts trong cùng origin.
- Bất cứ thứ gì với `<frame>` và `<iframe>`. Một trang có thể sử dụng header X-Frame-Options để ngăn chặn trường hợp tương tác cross-origin này.

Danh sách trên vẫn còn thiếu sót nhiều, mục đích của nó là làm nổi bật nguyên tắc "quyền hạn tối thiểu" (least privilege). Trình duyệt chỉ phô ra những API và tài nguyên cần thiết cho code của chương trình: ứng dụng hỗ trợ dữ liệu và URL, trình duyệt định dạng các request và xử lý toàn bộ vòng đời của mỗi kết nối.

Rất đáng để lưu tâm rằng hoàn toàn không có một concept cụ thể nào của "chính sách cùng origin" (same-origin policy). Thay vào đó, chỉ có 1 bộ cơ chế liên quan áp đặt các ràng buộc lên việc truy xuất DOM, cookie và quản lý trạng thái của session, mạng và các thành phần khác của trình duyệt.

# Lưu đệm tài nguyên và trạng thái của client

Request nhanh nhất và tốt nhất chính là không gọi request nào cả. Trước khi điều phối một request, trình duyệt tự động kiểm tra bộ đệm tài nguyên của nó, thực hiện các kiểm tra xác nhận cần thiết và trả về một bản copy local của tài nguyên đó nếu phù hợp với những điều kiện cụ thể. Nếu tài nguyên ở local không tồn tại trong cache thì request lên mạng được gọi và response sẽ được chèn tự động vào trong cache để cho lần truy cập tiếp theo nếu được phép.

- Trình duyệt tự động đánh giá các chỉ thị lưu đệm (cache directives) cho mỗi tài nguyên.
- Trình duyệt tự động xác nhận lại các tài nguyên hết hạn khi nó có thể.
- Trình duyệt tự động quản lý kích cỡ của bộ đệm và thu hồi tài nguyên.

Quản lý bộ đệm tài nguyên một cách hiệu quả và tối ưu là rất khó. Ơn trời trình duyệt đã xử lý toàn bộ những thứ phức tạp ấy giúp chúng ta rồi, tất cả những gì ta cần làm là đảm bảo server của mình trả về cache directive phù hợp, để hiểu rõ hơn thì bạn có thể đọc bài [Cache Resources on the Client](https://hpbn.co/optimizing-application-delivery/#cache-resources-on-the-client). Bạn cung cấp các response headers như Cache-Control, ETag và Last-Modified cho tất cả nguồn tài nguyên trên trang của bạn, phải không?

Cuối cùng, một chức năng thường bị bỏ quả nhưng khá quan trọng của trình duyệt chính là nhiệm vụ cung cấp xác thực, session và quản lý cookie. Trình duyệt duy trì các gói cookie (cookie jars - tác giả chơi chữ "cookie - bánh quy") riêng biệt cho mỗi origin, cung cấp các ứng dụng cần thiết và server APIs để đọc/ghi cookie, session và dữ liệu xác thực mới, tự động nối & xử lý các header HTTP phù hợp để tự động hóa toàn bộ quá trình thay cho chúng ta.

Ví dụ:
Một ví dụ đơn giản nhưng dễ minh họa nhất về sự tiện dụng của việc hoãn quản lý trạng thái session với trình duyệt: một session đã được xác thực có thể chia sẻ giữa nhiều tab với nhau hoặc nhiều cửa sổ trình duyệt và ngược lại; một hành động đăng xuất (sign-out) ở 1 tab sẽ vô hiệu hóa các session đang mở ở toàn bộ các cửa sổ đang mở khác.

# Các API ứng dụng và giao thức

Càng đi sâu tìm hiểu về các dịch vụ network sẵn có thì cuối cùng chúng ta cũng đã tiến đến các API ứng dụng và giao thức (Application APIs & Protocols). Như ta đã biết, những layer thấp thì cung cấp một mảng rộng các dịch vụ quan trọng: quản lý socket & kết nối, xử lý request & response, áp đặt nhiều chính sách bảo mật, lưu đệm & còn nhiều nữa. Mỗi khi chúng ta khởi tạo HTTP hay XMLHttpRequest, sự kiện long-lived Server-Sent hay WebSocket session, hoặc mở kết nối WebRTC... chúng ta đang tương tác với một hoặc nhiều các dịch vụ đó.

Không có giao thức hay API nào tốt nhất. Mỗi ứng dụng phức tạp sẽ cần một tổ hợp các giao vận (transports) khác nhau dựa trên sự đa dạng của các yêu cầu: giao tiếp với bộ đệm trình duyệt, protocol overhead (metadata hoặc thông tin điều hướng mạng được gửi bởi ứng dụng), độ trễ của message, độ tin cậy, kiểu truyền tải dữ liệu, vân vân. Một số giao thức có thể đáp ứng với độ trễ thấp (ví dụ: Server-Sent Events, WebSocket), nhưng không yêu cầu các tiêu chí quan trọng khác, chẳng hạn như khả năng tận dụng bộ đệm trình duyệt hoặc hỗ trợ truyền tải nhị phân hiệu quả trong mọi trường hợp.

# Một vài thứ bạn có thể làm để cải thiện hiệu năng và bảo mật của Webapp

- Luôn luôn sử dụng header `Connection: Keep-Alive` trong các request. Trình duyệt đã mặc định sẵn rồi. Đảm bảo server sử dụng cơ chế tương tự.
- Sử dụng header Cache-Control, Etag và Last-Modified phù hợp để tiết kiệm thời gian download cho trình duyệt.
- Dành thời gian để tinh chỉnh và tối ưu hóa web server, phép màu sẽ xảy ra! Nhớ rằng quá trình này rất cụ thể cho từng loại webapp và kiểu dữ liệu mà bạn trao đổi.
- Luôn luôn dùng TLS! Đặc biệt nếu như bạn có bất kỳ xác thực nào trong ứng dụng của bạn.
- Nghiên cứu trình duyệt cung cấp các chính sách bảo mật nào và áp đặt chúng vào trong ứng dụng của bạn.

Hiệu năng và bảo mật là ưu tiên hàng đầu trong [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=js-series-networking-layer-outro). Lý do tại sao team tác giả không thể nghiêng về một bên nào hơn là bởi vì một khi đã tích hợp SessionStack vào webapp, nó bắt đầu giám sát mọi thứ từ thay đổi trên DOM, tương tác người dùng đến request mạng, biệt lệ và thông báo debug. Tất cả thông tin này được truyền về server theo thời gian thực và cho phép user có thể chạy lại các vấn đề đã xảy ra dưới dạng video & xem mọi thứ xảy ra với người dùng của bạn. Tất cả hoạt động này được thực hiện với độ trễ tối thiểu và không ảnh hưởng tới hiệu năng của app của bạn.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p12-ben-trong-lop-network-lam-sao-de-toi-uu-hoa-hieu-nang-va-bao-mat-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p12-ben-trong-lop-network-lam-sao-de-toi-uu-hoa-hieu-nang-va-bao-mat-javascript</guid>
            <pubDate>Sun, 25 Nov 2018 16:06:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P11: Render engine & mẹo tối ưu hóa hiệu năng render]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 11 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Trong những bài trước của series "Đục khoét Javascript", chúng ta đã tập trung vào tìm hiểu **ngôn ngữ** Javascript, các tính năng của nó, cách chúng được thực thi trên trình duyệt, làm thế nào để tối ưu hóa, vân vân.

Tuy nhiên, khi bạn xây dựng webapp, bạn không chỉ viết code Javascript. Code của bạn còn tương tác với môi trường. Thấu hiểu môi trường, cách nó hoạt động cũng như các thành phần của nó sẽ cho phép bạn xây dựng app tốt hơn và có nền tảng chuẩn bị tốt để đề phòng những nguy cơ tiềm tàng có thể xảy đến bất cứ lúc nào khi lên production.

![](https://cdn-images-1.medium.com/max/1000/1*lMBu87MtEsVFqqbfMum-kA.png)

Các thành phần chính của trình duyệt:

- **Giao diện (User interface)**: phần này bao gồm thanh địa chỉ (address bar), nút back & forward, menu bookmark, vân vân. Về bản chất, đây là những phần thuộc về trình duyệt hiển thị lên cho bạn thấy, ngoại trừ khung hiển thị trang web.
- **Engine trình duyệt (Browser engine)**: nó xử lý các giao tiếp giữa user interface và rendering engine
- **Engine dựng hình (Rendering engine)**: chịu trách nhiệm hiển thị trang web. Rendering engine sẽ phân giải HTML & CSS và hiển thị nội dung đó lên màn hình.
- **Mạng (Networking)**: đây là những lời gọi mạng chẳng hạn như XHR request, chúng được tạo ra bằng cách sử dụng nhiều triển khai khác nhau cho nhiều nền tảng khác nhau nằm phía sau một interface độc lập nền tảng (platform-independent interface). Chúng ta sẽ thảo luận về lớp network chi tiết hơn ở bài tiếp theo (số 12) trong series này nhé.
- **Giao diện ở backend (UI Backend)**: dùng để vẽ nên các thành phần cốt lõi, ví dụ như checkbox hay cửa sổ. Phần này thể hiện một interface chung không phụ thuộc hay đặc trưng cho nền tảng. Nó sử dụng các phương thức về UI của hệ điều hành.
- **Javascript engine**: Chúng ta đã tìm hiểu về phần này trong [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-2---Ben-trong-engine-V8---5-meo-de-toi-uu-hoa-code). Về cơ bản, đây là nơi code Javascript được thực thi.
- **Cố định dữ liệu (Data persistence)**: app của bạn có thể cần lưu trữ dữ liệu ở phía local. Các loại kiến trúc lưu trữ được hỗ trợ ở đây gồm có [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), [indexDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API), [WebSQL](https://en.wikipedia.org/wiki/Web_SQL_Database) và [FileSystem](https://developer.mozilla.org/en-US/docs/Web/API/FileSystem)

Trong bài này, chúng ta sẽ tập trung vào rendering engine (engine dựng hình), bởi vì nó xử lý quá trình phân giải và hình ảnh hóa (visualization) code HTML & CSS, là phần mà đa số app Javascript cần tương tác liên tục.

# Khái quát về rendering engine

Công việc chính của rendering engine là hiển thị trang được yêu cầu lên màn hình của trình duyệt.

Rendering engine có thể hiển thị HTML, văn bản XML và ảnh. Nếu bạn sử dụng thêm plugin ở ngoài thì engine có thể hiển thị các loại văn bản khác, chẳng hạn như PDF.

# Rendering engines

Tương tự như Javascript engine, trình duyệt khác nhau cũng sử dụng các rendering engine khác nhau. Một vài bộ engine nổi tiếng:

- **Gecko** — Firefox
- **WebKit** — Safari
- **Blink** — Chrome, Opera (từ phiên bản 15 trở đi)

# Quá trình render

Rendering engine nhận nội dung của văn bản được yêu cầu từ lớp networking.

![](https://cdn-images-1.medium.com/max/1000/1*9b1uEMcZLWuGPuYcIn7ZXQ.png)

# Xây dựng DOM tree

Bước đầu tiên của công cuộc rendering là phân giải văn bản HTML và chuyển những phần tử đã phân giải thành những DOM node thực sự trong DOM tree.

Giả sử bạn có đoạn input như sau:

```html
<html>
  <head>
    <meta charset="UTF-8" />
    <link rel="stylesheet" type="text/css" href="theme.css" />
  </head>
  <body>
    <p>Hello, <span> friend! </span></p>
    <div>
      <img src="smiley.gif" alt="Smiley face" height="42" width="42" />
    </div>
  </body>
</html>
```

DOM tree của đoạn HTML trên sẽ giống như sau:
![](https://cdn-images-1.medium.com/max/1000/1*ezFoXqgf91umls9FqO0HsQ.png)

Về cơ bản thì mỗi phần tử được thể hiện như là một node cha của tất cả các element khác nằm trực tiếp ngay bên dưới (bên trong) nó. Nguyên tắc này được áp dụng một cách đệ quy.

# Xây dựng CSSOM tree

CSSOM viết tắt của **CSS Object Model**. Trong khi trình duyệt đang xây dựng DOM, nó bắt gặp một thẻ link trong phần head và dẫn tới một file CSS tên là theme.css ở bên ngoài. Dự đoán rằng nó có thể cần đến tài nguyên này để render trang, ngay lập tức nó điều phối 1 request đến. Giả sử file theme.css có nội dung như sau:

```css
body {
  font-size: 16px;
}

p {
  font-weight: bold;
}

span {
  color: red;
}

p span {
  display: none;
}

img {
  float: right;
}
```

Tương tự HTML, engine cần chuyển tất cả CSS sang một thứ gì đó mà trình duyệt có thể xử lý, chính là CSSOM. Dưới đây là mô phỏng của CSSOM tree:

![](https://cdn-images-1.medium.com/max/1000/1*5YU1su2mdzHEQ5iDisKUyw.png)

Bạn có tự hỏi tại sao CSSOM lại có cấu trúc dạng cây (tree)? Khi tính toán bộ style cuối cùng cho mỗi object tren trang, trình duyệt sẽ bắt đầu với rule áp dụng toàn cục nhất cho node đó (ví dụ: nếu nó là con của phần tử body thì áp dụng tất cả style của body) và tinh chỉnh một cách đệ quy những style đã được tính toán bằng cách áp dụng các rule cụ thể hơn.

Với ví dụ ở trên, bất kỳ text nào nằm bên trong thẻ span mà span nằm trong phần tử body thì đều có font-size 16 và màu đỏ. Những style này được kế thừa từ phần tử body. Nếu như span là con của phần tử p thì nội dung của nó sẽ bị ẩn bởi vì có style khác cụ thể hơn đã được áp dụng cho nó (ở đây là display: none).

Thêm nữa, lưu ý rằng tree ở trên chưa phải là CSSOM tree hoàn chỉnh và chỉ thể hiện những style mà ta đã ghi đè trong style sheet. Mỗi trình duyệt cung cấp 1 bộ style mặc định, còn được biết tới là **user agent styles** - đây chính những gì ta thấy nếu như không cung cấp style cụ thể. Style của chúng ta thêm vào chỉ đơn giản là ghi đè lại những phần mặc định này.

# Xây dựng render tree

Cùng với phần thể hiện trực quan trong HTML kết hợp với dữ liệu style từ CSSOM tree là chúng ta đã có đủ nguyên liệu để tạo ra render tree.

Bạn sẽ thắc mắc "render tree" là gì? Nó là 1 cây (tree) của các phần tử trực quan được xây dựng theo thứ tự trong đó chúng được hiển thị trên màn hình. Đó là sự thể hiện 1 cách trực quan của HTML cùng với CSS tương ứng. Mục đích của cây này là cho phép tô màu nội dung theo đúng thứ tự.

Mỗi node trong render tree được gọi là 1 renderer hoặc render object trong Webkit.

Dưới đây là cách mà render tree của DOM & CSSOM ở trên thể hiện:

![](https://cdn-images-1.medium.com/max/1000/1*WHR_08AD8APDITQ-4CFDgg.png)

Để xây dựng render tree, trình duyệt về cơ bản sẽ làm những bước sau đây:

- Bắt đầu từ root của DOM tree, nó sẽ đi qua mỗi **node thấy được**. Vài node có thể bị ẩn đi (ví dụ như tag script, meta, vân vân) hoặc bỏ qua bởi vì chúng không phản chiếu trong kết quả render đầu ra. Vài node bị ẩn bởi CSS và cũng bị bỏ qua khỏi render tree. Ví dụ như node span trong ví dụ trên thì nó sẽ không có mặt trong render tree vì đã được set style display: none rồi.
- Với mỗi node thấy được, trình duyệt sẽ tìm các rule CSSOM phù hợp và khớp với nó rồi áp dụng vào.
- Trình duyệt sẽ xuất ra các node thấy được với nội dung và style tương ứng.

Bạn có thể xem qua source code của RenderObject (WebKit) ở đây: [https://github.com/WebKit/webkit/blob/fde57e46b1f8d7dde4b2006aaf7ebe5a09a6984b/Source/WebCore/rendering/RenderObject.h](https://github.com/WebKit/webkit/blob/fde57e46b1f8d7dde4b2006aaf7ebe5a09a6984b/Source/WebCore/rendering/RenderObject.h)

Cùng nghía qua một vài dòng cốt lõi trong class này nhé:

```javascript
class RenderObject : public CachedImageClient {
  // Tô màu lại toàn bộ object. Nó sẽ được gọi khi border color thay đổi hoặc
  // border style thay đổi.

  Node* node() const { ... }

  RenderStyle* style;  // the computed style
  const RenderStyle& style() const;

  ...
}
```

Mỗi renderer thể hiện một khu vực hình chữ nhật tương ứng với CSS box của một node. Nó bao gồm cả thông tin hình học như độ rộng (width), chiều cao (height) hay vị trí (position).

# Cách bố trí của render tree

Khi renderer được tạo ra và thêm vào tree, nó không có thông tin vị trí hay kích thước, phần tính toán các giá trị này được gọi là layout.

HTML sử dụng mô hình layout theo dòng (flow-based layout), nghĩa là hầu như toàn bộ thời gian nó có thể tính toán thông số hình học chỉ trong 1 lần duyệt. Hệ thống tọa độ có liên quan đến root renderer. Thông số tọa độ top và left được sử dụng.

Layout là 1 quá trình đệ quy, nó bắt đầu ở root renderer, chính là thứ tương ứng với phần tử `<html>` trong văn bản HTML. Layout tiếp tục duyệt đệ quy qua một hoặc toàn bộ cây cấp bậc(hierarchy) renderer, tính toán các thông tin hình học cần thiết cho mỗi renderer.

Vị trí của root renderer là 0,0 và kích thước của nó bằng phần nhìn thấy được của cửa sổ hiển thị trên trình duyệt (còn gọi là viewport).

Bắt đầu quá trình tạo layout chính là truyền đạt lại cho mỗi node tọa độ chính xác mà nó cần phải xuất hiện trên màn hình là ở đâu.

# Tô màu cho render tree

Trong giai đoạn này, renderer tree đã được duyệt qua và phương thức paint() của renderer được gọi để hiển thị nội dung lên màn hình.

Tô màu có thể theo cách global hoặc incremantal tương tự như layout):

- **Global (toàn cục)**: toàn bộ tree được lên màu.
- **Incremental (gia tăng)**: chỉ có một vài renderer thay đổi theo cách không ảnh hưởng đến toàn bộ tree. Renderer vô hiệu hóa khung chữ nhật của chính nó trên màn hình. Điều này làm cho OS (hệ điều thành) hiểu rằng vùng đó cần phải được tô màu lại và sinh ra một paint event. OS thực hiện điều đó một cách thông minh bằng cách gộp nhiều vùng thành một.

Về tổng quát thì quan trọng là cần phải hiểu rằng tô màu là quá trình diễn ra từ từ. Để có UX tốt hơn, render engine sẽ cố hiển thị nội dung trên màn hình ngay khi có thể. Nó sẽ không ngồi yên đợi cho tới khi toàn bộ HTML được parse để bắt đầu xây dựng và bố trí render tree. Từng phần của nội dung sẽ được parse và hiển thị lên trong khi tiến trình tiếp tục với những item nội dung tiếp theo đang được truyền về trên mạng.

# Thứ tự xử lý script và style

Các script được parse và thực thi ngay lập tức khi parser vừa gặp thẻ `<script>`. Quá trình parse của toàn bộ văn bản sẽ tạm dừng cho đến khi script thực thi xong. Nghĩa là tiến trình này diễn ra đồng bộ.

Nếu như script là file ở ngoài thì việc đầu tiên nó cần phải được lấy về từ mạng (bất đồng bộ). Tất cả công việc parse sẽ dừng lại cho đến khi lấy xong file.

HTML5 có thêm 1 tùy chọn để đánh dấu script là bất đồng bộ, do đó nó có thể được parse và thực thi trong 1 tiến trình khác.

# Tối ưu hóa hiệu suất render

Nếu bạn muốn tối ưu hóa app thì có 5 điểm chính mà bạn cần tập trung vào dưới đây:

1.  **Javascript** - trong các bài trước chúng ta đã nghiên cứu về chủ đề viết code tối ưu và có hiệu quả bộ nhớ cao mà không làm ảnh hưởng đến UI. Với trường hợp của render, chúng ta cần phải suy nghĩ về cách mà code Javascript sẽ tương tác với các phần tử DOM trên trang. Javascript có thể tạo ra rất nhiều thay đổi với UI, đặc biệt là các app SPA.
2.  **Tính toán Style** - đây là tiến trình xác định CSS rule nào sẽ áp dụng vào phần tử nào dựa trên các selector. Một khi các rule đã được định nghĩa, chúng sẽ được áp dụng và tính toán style cuối cùng cho mỗi phần tử.
3.  **Layout** - khi trình duyệt biết rule nào áp dụng cho phần tử nào, nó có thể bắt đầu tính toán bao nhiêu không gian một phần tử sẽ chiếm dụng và vị trí của nó sẽ nằm ở đâu trên màn hình của trình duyệt. Mô hình layout của trang web xác định một phần tử có thể gây ảnh hưởng đến phần tử khác. Ví dụ, độ rộng của `<body>` có thể ảnh hưởng độ rộng của phần tử con của nó. Điều này nghĩa là quá trình layout sẽ là quá trình nặng về tính toán số học. Phần "vẽ" được thực hiện trong nhiều layer khác nhau.
4.  **Tô màu** - đây là lúc mà các pixel thực sự được lên màu. Tiến trình bao gồm cả phần vẽ các câu chữ, màu sắc, hình ảnh, viền, đổ bóng, vấn vân, từng phần nhìn thấy được của từng phần tử.
5.  **Kết hợp (Compositing)** - Bởi vì các phần nhỏ của webpage được vẽ vào trong nhiều lớp khác nhau, chúng cần được kết hợp vào một màn hình theo đúng thứ tự để page có thể render một cách chính xác. Điều này rất quan trọng, đặc biệt là với các phần tử chồng nhau.

# Tối ưu hóa JavaScript

Javascript thường trigger những thay đổi nhìn thấy được trên trình duyệt. Và những tác vụ đó nhân lên nhiều lần khi xây dựng ứng dụng SPA.

Dưới đây là 1 số mẹo nhỏ để bạn biết nên tối ưu phần nào của code Javascript nhằm cải thiện render:

- Tránh sử dụng setTimeout và setInterval đối với những cập nhật nhìn thấy được. Hai hàm này sẽ gọi callback tại 1 thời điểm nào đó trong frame, có thể là cuối frame. Thứ chúng ta cần là trigger thay đổi ngay khi bắt đầu frame để tránh bị sót.
- Đưa những tính toán Javascript phức tạp và tốn thời gian vào trong Web Workers như chúng ta đã thảo luận ở [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-7---Thanh-phan-cua-WebWorker---5-truong-hop-su-dung).
- Sử dụng các tác vụ siêu nhỏ (micro-tasks) để thông báo sự thay đổi của DOM với nhiều frame. Dùng trong trường hợp các tác vụ cần truy xuất vào DOM, điều này Web Workers không làm được. Về cơ bản thì nó nghĩa là bạn cần chia nhỏ 1 tác vụ lớn thành nhiều phần nhỏ hơn và chạy chúng bên trong các hàm requestAnimationFrame, setTimeout, setInterval tùy thuộc vào đặc tính của mỗi tác vụ.

# Tối ưu hóa CSS

Chỉnh sửa DOM bằng cách thêm bớt các phần tử, thay đổi các thuộc tính... sẽ làm cho trình duyệt phải tính toán lại style của phần tử và trong nhiều trường hợp, là phải tính lại layout của toàn bộ trang hoặc 1 phần của trang.

Để tối ưu quá trình render, bạn cần cân nhắc những điều sau:

- Giảm thiểu sự phức tạp trong các selector. Sự phức tạp của selector có thể chiếm đến hơn 50% thời gian cần thiết để tính toán style cho 1 phần tử (phần còn lại là thời gian để xây dựng style).
- Giảm số lượng phần tử cần được tính toán style. Về bản chất thì thay đổi style trực tiếp cho 1 vài phần tử thì tốt hơn là vô hiệu toàn bộ page.

# Tối ưu hóa layout

Tính toán lại layout có thể ngốn nhiều tài nguyên của trình duyệt nên bạn cần cân nhắc những điều sau:

- Giảm số lượng layout bất cứ khi nào có thể. Khi bạn thay đổi style thì trình duyệt kiểm tra để xem thử có thay đổi nào cần layout phải được tính toán lại không. Các thay đổi về property như width, height, left, top và trên hết là những property nào liên quan đến hình học, cần có layout. Vì thế tránh thay đổi chúng hết mức có thể.
- Dùng flexbox bất cứ khi nào có thể dùng. Nó chạy nhanh hơn và có thể cải thiện hiệu năng một cách đáng kể.
- Tránh ép buộc layout đồng bộ. Nhớ rằng khi Javascript chạy, tất cả giá trị của layout cũ từ frame trước đó được xác định và sẵn sàng cho bạn truy vấn. Không vấn đề gì nếu như bạn muốn truy xuất box.offsetHeight. Tuy nhiên, nếu bạn thay đổi style của box trước khi nó được truy xuất (ví dụ: cố tình thêm CSS class vào 1 phần tử), trình duyệt đầu tiên sẽ áp dụng thay đổi của style rồi sau đó mới chạy đến phần layout. Điều có có thể gây tốn thời gian và làm ảnh hưởng nặng đến tài nguyên máy tính, vì thế nên tránh càng xa nó càng tốt.

# Tối ưu hóa tô màu

Đây thường là tác vụ chạy lâu nhất trong số các tác vụ nên quan trọng là tránh mặt nó càng xa càng tốt. Những gì bạn có thể làm:

- Thay đổi bất kỳ property nào khác ngoài transform hay opacity sẽ trigger tác vụ tô màu. Nhớ sử dụng tiết kiệm nhé.
- Nếu bạn trigger một layout, bạn cũng sẽ trigger luôn tác vụ tô màu bởi vì thay đổi về kích thước hình học cũng sẽ thay đổi phần nhìn thấy được của phần tử.
- Giảm diện tích tô màu thông qua thăng cấp layer và dàn dựng các animation.

Render là một khía cạnh quan trọng trong cách thức hoạt động của [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=js-series-rendering-engine-outro). SessionStack phải tái tạo lại một video về mọi thứ đã diễn ra với user tại thời điểm họ trải nghiệm qua một vấn đề khi đang lướt webapp của bạn. Để làm được điều này, SessionStack chỉ xử lý duy nhất những dữ liệu mà thư viện của nó thu thập được: các sự kiện từ user, thay đổi trên DOM, request lên mạng, biệt lệ, thông báo debug, vân vân. Trình phát video được tối ưu hóa tối đa để có thể render một cách chính xác và sử dụng toàn bộ những dữ liệu thu thập được để có thể đưa ra một bản giả lập trình duyệt của user hoàn-hảo-đến-từng-pixel cũng như những gì đã xảy ra trên đó, cả về mặt kỹ thuật lẫn quan sát.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p11-render-engine-meo-toi-uu-hoa-hieu-nang-render</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p11-render-engine-meo-toi-uu-hoa-hieu-nang-render</guid>
            <pubDate>Sun, 25 Nov 2018 15:29:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P10: Quan sát thay đổi trên DOM bằng MutationObserver]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 10 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

![](https://cdn-images-1.medium.com/max/1000/0*mPXf5zRCdEQ42Hn0.)

Webapp càng ngày càng nặng hơn ở phía client bởi vì nhiều lý do đại loại như UI phải "phì nhiêu" để chứa đựng những thứ logic phức tạp bên trong bao gồm cả tính toán theo thời gian thực (real-time), và nhiều nhiều thứ khác nữa.

Sự phức tạp gia tăng làm cho chúng ta khó nắm bắt chính xác trạng thái của UI tại mỗi thời điểm trong vòng đời của webapp.

Điều này càng khó hơn nữa nếu chúng ta xây dựng một vài thứ chẳng hạn như library hay framework mà cần phải phản ứng cũng như xử lý những hành động dựa trên DOM.

# Khái quát

[MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) (tạm dịch: Người quan sát sự biến đổi) là một WebAPI được các trình duyệt hiện đại cung cấp để phát hiện các thay đổi trên DOM. Với API này một người có thể listen các node mới được thêm vào hoặc gỡ ra, thuộc tính thay đổi hoặc những thay đổi về nội dung văn bản trong một text node.

Tại sao phải cần làm thế?

Có một số ít trường hợp trong đó MutationObserver API thực sự hữu ích. Ví dụ:

- Bạn muốn thông báo cho người dùng webapp rằng một vài sự thay đổi đã xảy ra trên trang mà người đó đang sử dụng.
- Bạn đang làm việc với 1 Javascript framework sang chảnh mới, nó cần load rất nhiều JS module một cách tự động dựa trên sự thay đổi của DOM.
- Bạn đang làm việc với bộ soạn thảo WYSIWYG và thử triển khai tính năng undo/redo. Bằng cách tận dụng MutationObserver API, bất kỳ lúc nào bạn cũng có thể biết phần nào đã thay đổi và dễ dàng undo chúng.

![](https://cdn-images-1.medium.com/max/1000/1*48tGIboHxgLeKEjMTGkUGg.png)

Trên đây chỉ là 1 số ví dụ về lợi ích của MutationObserver.

# Cách sử dụng MutationObserver

Triển khai MutationObserver khá dễ dàng. Bạn cần tạo 1 instance MutationObserver bằng cách truyền cho nó 1 hàm và hàm này được gọi mỗi khi 1 sự thay đổi xảy ra. Đối số đầu tiên của hàm là 1 tập hợp tất cả các sự thay đổi xảy ra trên 1 khối duy nhất. Mỗi sự thay đổi cung cấp thông tin về loại của nó cũng như thay đổi nào đã xảy ra.

```javascript
var mutationObserver = new MutationObserver(function (mutations) {
  mutations.forEach(function (mutation) {
    console.log(mutation);
  });
});
```

Object tạo ra có 3 phương thức:

- **observe**: bắt đầu lắng nghe sự thay đổi. Nó nhận 2 đối số: DOM node mà bạn muốn quan sát và một object chưa các thiết lập.
- **disconnect**: dừng quá trình lắng nghe thay đổi.
- **takeRecords**: trả về khối thay đổi cuối cùng trước khi callback được kích hoạt.

Đoạn code sau thể hiện quá trình quan sát (observing) diễn ra:

```javascript
// Bắt đầu lắng nghe thay đổi trong root HTML của trang.
mutationObserver.observe(document.documentElement, {
  attributes: true,
  characterData: true,
  childList: true,
  subtree: true,
  attributeOldValue: true,
  characterDataOldValue: true,
});
```

Giờ giả sử ta có 1 div cực kỳ đơn giản trong DOM:

```javascript
<div id="sample-div" class="test">
  {" "}
  Simple div{" "}
</div>
```

Sử dụng jQuery, bạn có thể xóa thuộc tính class từ div đó:

```javascript
$("#sample-div").removeAttr("class");
```

Khi đã bắt đầu quan sát, sau khi gọi hàm mutationObserver.observe(...) ta có thể xem thông tin log được in ra trong console của [MutationRecord](https://developer.mozilla.org/en-US/docs/Web/API/MutationRecord).

![](https://cdn-images-1.medium.com/max/1000/1*UxkSstuyCvmKkBTnjbezNw.png)

Đây là sự biến đổi tạo ra bởi ta đã xóa thuộc tính class.

Cuối cùng, để dừng sự quan sát DOM sau khi đã xong việc, ta làm như sau:

```javascript
// Dừng MutationObserver, không lắng nghe thay đổi nữa.
mutationObserver.disconnect();
```

Ngày nay MutationObserver được hỗ trợ khá tốt:

![](https://cdn-images-1.medium.com/max/1000/0*nlOmrsfy-Y1XoR8B.)

# Giải pháp thay thế

Tuy nhiên, MutationObserver cũng chỉ mới xuất hiện chưa lâu. Vậy thì trước khi có nó, các developer dùng cái gì?

Dưới đây là 1 vài lựa chọn:

- **Polling**
- **MutationEvents**
- **CSS animations**

## Polling

Giải pháp đơn giản nhất và kém tinh tế nhất là polling (bỏ phiếu bình chọn). Sử dụng WebAPI setInterval bạn có thể thiết lập 1 tác vụ kiểm tra sự thay đổi theo chu kỳ nhất định. Dĩ nhiên thì cách này làm giảm hiệu năng của webapp 1 cách đáng sợ.

## MutationEvents

[MutationEvents API](https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Mutation_events) được giới thiệu vào năm 2000\. Mặc dù nó có ích, các sự kiện thay đổi (mutation events) được bắn ra mỗi khi có 1 sự thay đổi bất kỳ trên DOM và một lần nữa làm ảnh hưởng đến hiệu năng. Ngày nay thì MutationEvents API đã bị hủy bỏ và những trình duyệt hiện đại sẽ sớm ngừng hỗ trợ nó.

Danh mục trình duyệt hỗ trợ cho MutationEvents:

![](https://cdn-images-1.medium.com/max/1000/0*l-QdpBfjwNfPDTyh.)

## CSS animations

Một giải pháp thay thế hơi kỳ cục đó là dựa trên [CSS Animations](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations). Nghe có vẻ bối rối nhỉ. Về cơ bản thì ý tưởng của nó là tạo ra 1 animation có thể được trigger khi có một element được thêm vào DOM. Khoảnh khắc animation bắt đầu, sự kiện animationstart sẽ được bắn ra: nếu bạn đã gắn 1 event handler vào sự kiện đó thì bạn sẽ biết 1 cách chính xác khi nào element được thêm vào DOM. Thời gian thực hiện của animation phải cực nhỏ để cho nó dường như vô hình trước con mắt user.

Đầu tiên ta cần một element cha, bên trong nó ta sẽ listen sự kiện chèn node:

```javascript
<div id=”container-element”></div>
```

Để có thể xử lý khi có node chèn vào, ta cần thiết lập một chuỗi các [keyframe](https://www.w3schools.com/cssref/css3_pr_animation-keyframes.asp) animation khởi động khi node được thêm vào:

```javascript
@keyframes nodeInserted {
 from { opacity: 0.99; }
 to { opacity: 1; }
}
```

Với keyframe được tạo ra đó, animation cần phải được áp dụng vào các element mà ta muốn lắng nghe. Lưu ý là thời gian duration rất nhỏ, mục đích là để kéo dãn dấu vết của animation trên trình duyệt:

```javascript
#container-element * {
 animation-duration: 0.001s;
 animation-name: nodeInserted;
}
```

Bước thiết lập này sẽ thêm animation vào tất cả các node con của container-element. Khi animation kết thúc (sau 0.001s như trên), sự kiện chèn node sẽ được bắn ra.

Ta cần một hàm event listener Javascript. Trong hàm đó ta phải gọi event.animationName để đảm bảo đó chính là animation mà ta cần.

```javascript
var insertionListener = function (event) {
  // Đảm bảo đây là animation mà ta cần xử lý.
  if (event.animationName === "nodeInserted") {
    console.log("Node has been inserted: " + event.target);
  }
};
```

Giờ thì thêm event listener vào node cha:

```javascript
document.addEventListener(“animationstart”, insertionListener, false); // standard + firefox
document.addEventListener(“MSAnimationStart”, insertionListener, false); // IE
document.addEventListener(“webkitAnimationStart”, insertionListener, false); // Chrome + Safari
```

Trình duyệt hỗ trợ CSS animation:

![](https://cdn-images-1.medium.com/max/1000/0*W4wHvVAeUmc45vA2.)

MutationObserver cung cấp một số tính năng nâng cao hơn tất cả 3 giải pháp trên. Về bản chất, nó bao phủ toàn bộ mỗi thay đổi có thể diễn ra trên DOM và nó được tối ưu hóa khi bắn ra các thay đổi trong 1 chuỗi hàng loạt. Trên hết MutationObserver được hỗ trợ bởi tất cả các trình duyệt hiện đại đi kèm với 1 số polyfills để dùng MutationEvents

MutationObserver chiếm giữ một vị trí trung tâm trong thư viện của [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=mutation-observer-post).

Khi bạn đã tích hợp thư viện của SessionStack vào webapp, nó bắt đầu thu thập các thông tin chẳng hạn như thay đổi trên DOM, request mạng, biệt lệ, thông báo debug, vân vân, và gửi chúng về server. SessionStack dùng chính những dữ liệu này để tái tạo lại mọi thứ đã xảy ra với user của bạn và hiển thị các vấn đề của sản phẩm trong cùng 1 tình huống mà nó diễn ra với user. Khá nhiều người nghĩ rằng SessionStack ghi lại video, nhưng không phải vậy. Ghi video rất tốn kém, mặt khác lượng dữ liệu thu thập được lại rất nhẹ và không ảnh hưởng đến UX cũng như hiệu năng của webapp của bạn.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p10-quan-sat-thay-doi-tren-dom-bang-mutationobserver</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p10-quan-sat-thay-doi-tren-dom-bang-mutationobserver</guid>
            <pubDate>Sun, 25 Nov 2018 15:24:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P9: Cấu tạo của Web Push Notifications]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 9 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Hôm nay chúng ta sẽ chuyển hướng sự chú ý qua **web push notifications** (tạm dịch: thông báo đẩy trên trang web): chúng ta sẽ tìm hiểu về thành phần của nó, khám phá các quy trình gửi/nhận thông báo phía sau và cuối bài sẽ cùng tìm hiểu làm sao SessionStack sử dụng chúng để xây dựng chức năng của sản phẩm.

Push Notifications rất phổ biến trong thế giới của điện thoại. Vì lý do này hay lý do khác, chúng bước chân vào thế giới web lại khá muộn mặc dù nó là tính năng rất được các developer ưa chuộng và đề xuất.

# Khái quát

Web Push Notifications cho phép user tham gia vào các cập nhật theo thời gian từ webapp nhằm mục đích thu hút người dùng dựa trên nội dung thú vị, quan trọng và đúng lúc đối với họ.

Push dựa trên Service Workers - chính là chủ đề mà chúng ta đã [thảo luận ở bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-8---Service-Workers--vong-doi-va-cac-truong-hop-su-dung).

Lý do lựa chọn dùng Service Workers trong trường hợp này là vì chúng hoạt động trong background. Rất phù hợp cho Push Notifications vì như vậy nghĩa là code chỉ được thực thi khi user tương tác với chính notification đó.

# Push & notification

Push và notification là 2 API khác nhau.

- [Push](https://developer.mozilla.org/en-US/docs/Web/API/Push_API): được gọi khi server cung cấp thông tin cho Server Worker
- [Notification](https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API): hành động của Service Worker hoặc một đoạn script trên webapp nhằm hiển thị thông tin đến user.

# Push

Có 3 bước cơ bản để triển khai 1 push:

- **Giao diện (UI)**: thêm vào những logic cần thiết ở phía client để đăng ký user với push. Đây là phần logic Javascript mà UI của webapp cần để cho phép user đăng ký vào push message.
- **Gửi push message**: triển khai lời gọi API trên server để trigger một push message tới thiết bị của user.
- **Nhận push message**: xử lý push message một khi nó về tới trình duyệt.

Giờ thì chúng ta sẽ tìm hiểu toàn bộ quá trình một cách chi tiết hơn.

# Xác nhận hỗ trợ từ trình duyệt

Đầu tiên là cần phải kiểm tra xem trình duyệt bạn đang dùng có hỗ trợ cho push message hay không. Chúng ta có 2 bài check đơn giản:

- Kiểm tra serviceWorker trong object navigator
- Kiểm tra PushManager trong object window

Code kiểm tra:

```javascript
if (!("serviceWorker" in navigator)) {
  // Service Worker không được hỗ trợ, vô hiệu hóa hoặc ẩn UI đi.
  return;
}

if (!("PushManager" in window)) {
  // Push không được hỗ trợ, vô hiệu hóa hoặc ẩn UI đi.
  return;
}
```

# Đăng ký một Service Worker

Tại thời điểm này, ta đã biết các chức năng đều được hỗ trợ. Bước tiếp theo sẽ là đăng ký Service Worker.

Đăng ký một Service Worker như thế nào thì bạn cũng đã quen với những diễn giải từ [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-8---Service-Workers--vong-doi-va-cac-truong-hop-su-dung) rồi.

# Yêu cầu được cấp quyền

Xong phần với Service Worker thì ta có thể đi tiếp đến phần đăng ký user. Bạn cần phải có quyền của user thì mới gửi push message đến họ được.

API dùng để lấy quyền (permission) cũng tương đổi đơn giản, tuy nhiên điểm bất lợi là API đã thay đổi từ việc dùng callback sang trả về Promise. Nó sinh ra vấn đề khác: chúng ta không thể biết version của API đã được triển khai trên trình duyệt hiện tại, vì thế chúng ta phải xử lý cả 2 trường hợp.

Nó trông như thế này đây:

```javascript
function requestPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      // Xử lý phiên bản cũ với callback.
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== "granted") {
      throw new Error("Permission not granted.");
    }
  });
}
```

Lời gọi đến Notification.requestPermission() sẽ hiển thị 1 bảng thông báo nhỏ:

![](https://cdn-images-1.medium.com/max/1000/1*xhB8ceUNM6vb8s0ZQKMHNg.png)

Một khi quyền đã được cấp, được đóng hoặc block thì chúng ta cũng nhận được những kết quả tương tự dưới dạng string: granted, default, denied.

Nhớ rằng nếu user click chuột vào nút Block thì webapp của bạn sẽ không thể hỏi user về chuyện cấp quyền một lần nữa, cho tới khi user tự "unblock" app của bạn bằng cách thay đổi trạng thái của quyền. Tùy chọn này được giấu trong bảng cài đặt.

# Đăng ký một user với PushManager

Khi Service Worker đã được đăng ký và chúng ta được user cấp quyền, ta có thể subscribe 1 user bằng cách gọi registration.pushManager.subscribe() khi đăng ký Service Worker của bạn.

Toàn bộ đoạn code như sau (bao gồm cả phần đăng ký Service Worker):

```javascript
function subscribeUserToPush() {
  return navigator.serviceWorker
    .register("service-worker.js")
    .then(function (registration) {
      var subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: btoa(
          "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U"
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log("PushSubscription: ", JSON.stringify(pushSubscription));
      return pushSubscription;
    });
}
```

registration.pushManager.subscribe(options) nhận một object options gồm 1 param bắt buộc và 1 param tùy chọn:

- **userVisibleOnly**: một boolean chỉ định push subscription trả về sẽ chỉ được dùng cho message mà hiệu ứng của message đó user có thể nhìn thấy được. Nó phải được gán bằng true nếu không thì sẽ lỗi (Có cả 1 quá khứ lịch sử về nó).
- **applicationServerKey**: một DOMString hoặc ArrayBufffer chứa public key được mã hóa thành Base64 mà server push sẽ dùng để xác thực server của app.

Server của bạn cần sinh ra một cặp server key cho app, chúng còn được biết đến là key VAPID duy nhất cho server. Đây là 1 cặp public-private key. Private key thì được giữ một cách bí mật ở phía bạn trong khi public key được trao đổi với client. Những key này cho phép push service biết app server nào đã đăng ký user và đảm bảo đó chính là server trigger các push message đến người dùng cụ thể.

Bạn chỉ cần tạo ra cặp private/public key 1 lần duy nhất cho ứng dụng. Có 1 cách làm nhanh đó là dùng trang này [https://web-push-codelab.glitch.me/](https://web-push-codelab.glitch.me/)

Trình duyệt truyền applicationServerKey (public key) lên một push server khi đăng ký user, nghĩa là push server có thể liên kết public key của app bạn với PushSubscription của user.

Đây là những gì diễn ra:

- Webapp của bạn được load xong và bạn gọi subscribe(), truyền server key vào.
- Trình duyệt tạo 1 request lên mạng đến một push service để sinh ra một endpoint, sau đó liên kết endpoint này với key và trả về cho trình duyệt.
- Trình duyệt sẽ thêm endpoint này vào trong object PushSubscription, chính là object được trả về từ subscribe() promise.

Về sau, cứ mỗi khi bạn muốn gửi 1 push message, bạn chỉ cần tạo một **Authorization header** có chưa thông tin đã ký (signed) với private key từ server ứng dụng của bạn. Khi push service nhận request để gửi một push message, nó sẽ xác minh header bằng cách tìm public key đã liên kết với endpoint cụ thể đó (ở bước thứ 2)

# Object PushSubscription

Một PushSubscription chứa những thông tin cần thiết để gửi push message đến thiết bị của user:

```javascript
{
  "endpoint": "https://domain.pushservice.com/some-id",
  "keys": {
    "p256dh":
"BIPUL12DLfytvTajnryr3PJdAgXS3HGMlLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WArAPIxr4gK0_dQds4yiI=",
    "auth":"FPssMOQPmLmXWmdSTdbKVw=="
  }
}
```

endpoint ở đây là URL của push service. Để trigger một push mesage ta cần tạo request POST đến URL này.
Object keys chứa giá trị dùng để mã hóa dữ liệu thông tin được gửi đi với push message.
Một khi user đã được đăng ký và bạn có PushSubscription thì bạn cần gửi nó về cho server. Tại đây (trên server) bạn sẽ lưu thông tin tham gia của user vào database và kể từ bây giờ sẽ dùng nó để gửi push message về cho user đó.

![](https://cdn-images-1.medium.com/max/1000/1*hTMGxzZrOmxxIfaQU7nKig.png)

# Gửi push message

Khi bạn cần gửi một push message cho nhiều user, điều đầu tiên bạn cần là push service. Bạn đang chỉ bảo cho push service (thông qua API) dữ liệu để gửi, gửi đến ai và các tình huống về việc làm thế nào để gửi message. Thông thường, lời gọi API này sẽ được thực hiện trên server.

# Push Services

Push service là thứ dùng để nhận các request, xác nhận chúng và chuyển giao push message cho trình duyệt phù hợp.

Lưu ý rằng bạn không quản lý push service, nó là 1 dịch vụ của bên thứ 3\. Server của bạn giao tiếp với push service thông qua API. Một ví dụ về push service chính là [Google's FCM](https://firebase.google.com/docs/cloud-messaging/)

Push service xử lý tất cả những việc nặng nhọc. Ví dụ: Nếu như trình duyệt đang offline, push service sẽ xếp message vào hàng đợi và chờ cho đến khi trình duyệt online lại trước khi gửi message đi 1 cách tuần tự.

Mỗi tình duyệt có thể dùng bất kỳ push service nào và điều này vượt ngoài khả năng kiểm soát của developer.

Tuy nhiên tất cả các push service có chung API nên việc này không làm cho quá trình triển khai trở nên khó khăn.

Để lấy được URL xử lý các request cho push message, bạn cần phải kiểm tra giá trị của endpoint trong object PushSubscription.

# Push Service API

Push Service API cung cấp 1 cách để gửi message đến cho user. API là 1 [Web Push Protocol](https://tools.ietf.org/html/draft-ietf-webpush-protocol-12) theo tiêu chuẩn IETF định nghĩa cách ta gọi API đến một push service

Dữ liệu bạn gửi với push message phải được mã hóa. Bằng cách này, bạn ngăn chặn push service đọc dữ liệu gửi đi. Điều này rất quan trọng vì trình duyệt chính là người quyết định nên dùng push service nào (có thể đó là push service không đáng tin cậy và bảo mật kém)

Với mỗi push message, bạn có thể đưa ra hướng dẫn như sau:

- **TTL**: định nghĩa một message nên chờ bao lâu trong hàng đợi trước khi nó bị gỡ ra và không được chuyển đi.
- **Mức độ ưu tiên (priority)**: định nghĩa mức độ ưu tiên của mỗi message, cách này giúp cho push service chỉ gửi những thông tin có mức độ ưu tiên cao, ví dụ trong trường hợp pin thiết bị của người dùng sắp cạn.
- **Chủ đề (topic)**: cung cấp cho push message một tên chủ đề sẽ thay thế message đang chờ xử lý (pending) có cùng chủ đề để khi thiết bị đang hoạt động, user sẽ không nhận thông tin cũ, lỗi thời.

![](https://cdn-images-1.medium.com/max/1000/1*PgclyCPqxWc1rENfAOesag.png)

# Sự kiện Push trên trình duyệt

Một khi bạn gửi message đến push service như giải thích ở trên, message sẽ chuyển sang trạng thái chờ (pending) cho đến khi 1 trong số những điều sau đây xảy ra:

- Thiết bị online
- Message hết hạn trên hàng đợi do TTL.

Khi push service truyền một message, trình duyệt sẽ nhận nó, giải mã và điều phối một sự kiện push trong Service Worker của bạn.

Điều tuyệt vời là trình duyệt thực thi code Service Worker của bạn thậm chí cả khi web page chưa mở lên:

- Push message được gửi tới trình duyệt và được giải mã.
- Trình duyệt đánh thức Service Worker
- Một sự kiện push được phân phối đến Service Worker

Code để cài đặt một listener cho push even cũng khá tương đồng với các loại event listener khác trong Javascript:

```javascript
self.addEventListener("push", function (event) {
  if (event.data) {
    console.log("This push event has data: ", event.data.text());
  } else {
    console.log("This push event has no data.");
  }
});
```

Một điều cần phải hiểu về Service Worker là bạn có ít quyền kiểm soát về thời gian chạy của code Service Worker. Trình duyệt quyết định khi nào thì đánh thức nó dậy và khi nào thì hủy nó.

Trong Service Worker, event.waitUntil(promise) cho trình duyệt biết công việc vẫn đang thực hiện cho tới khi promise được giải quyết xong và trình duyệt sẽ không hủy service worker nếu nó cần quá trình đó hoàn thành.

Dưới đây là 1 ví dụ về xử lý sự kiện push:

```javascript
self.addEventListener("push", function (event) {
  var promise = self.registration.showNotification("Push notification!");

  event.waitUntil(promise);
});
```

Gọi self.registration.showNotification() hiển thị một thông báo đến user và nó trả về promise, promise này được resolve khi thông báo đã được hiển thị lên.

Phương thức showNotification(title, options) có thể được chỉnh sửa để phù hợp với nhu cầu. Param title là 1 string, còn options là object như dưới đây:

```javascript
{
  "//": "Visual Options",
  "body": "<String>",
  "icon": "<URL String>",
  "image": "<URL String>",
  "badge": "<URL String>",
  "vibrate": "<Array of Integers>",
  "sound": "<URL String>",
  "dir": "<String of 'auto' | 'ltr' | 'rtl'>",

  "//": "Behavioural Options",
  "tag": "<String>",
  "data": "<Anything>",
  "requireInteraction": "<boolean>",
  "renotify": "<Boolean>",
  "silent": "<Boolean>",

  "//": "Both Visual & Behavioural Options",
  "actions": "<Array of Strings>",

  "//": "Information Option. No visual affect.",
  "timestamp": "<Long>"
}
```

Bạn có thể tìm hiểu chi tiết về mỗi options ở đây: [https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification)

Push Notification là một cách tuyệt vời để thu thập sự chú ý của user những khi có thông tin gấp, quan trọng hoặc cần thời điểm nhạy cảm mà bạn muốn chia sẻ với họ.

Team SessionStack thực hiện push notifications để báo cho user biết khi có crash, vấn đề hoặc điều gì đó bất thường trong sản phẩm của họ. Việc này giúp cho user biết ngay lập tức nếu có gì không đúng đang xảy ra. Sau đó họ có thể replay lại issue đó dưới dạng video và xem mọi thứ diễn ra với người dùng cuối của họ bằng cách tận dụng dữ liệu được thu thập với thư viện của SessionStack, chẳng hạn như thay đổi trên DOM, tương tác người dùng, request mạng, biệt lệ không được xử lý và các thông báo lỗi.

Tính năng này không chỉ sẽ giúp user sử dụng SessionStack hiểu và tái hiện lại bất kỳ vấn đề nào mà nó còn cho phép họ nhận được thông báo ngay khi nó xuất hiện.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p9-cau-tao-cua-web-push-notifications</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p9-cau-tao-cua-web-push-notifications</guid>
            <pubDate>Sat, 24 Nov 2018 22:51:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P8: Service Workers, vòng đời và các trường hợp sử dụng]]></title>
            <description><![CDATA[
Bạn có lẽ đã biết rằng [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/) chỉ có thể phổ biến hơn khi chúng hướng tới trải nghiệm người dùng (UX) mượt mà hơn, giống như là tạo 1 native app hơn là một trải nghiệm mang phong cách trình duyệt.

Một trong số những yêu cầu khi xây dựng PWA là làm nó cực kỳ đáng tin cậy ở khoản loading: nó có thể chạy kể cả trong tình trạng internet không ổn định hoặc rớt mạng.

Trong bài này, chúng ta sẽ đào sâu vào Service Workers: cách chúng hoạt động và chúng ta nên quan tâm đến đâu. Cuối bài, team tác giả có một số lợi ích độc đáo của Service Workers mà chúng ta nên dùng đồng thời chia sẻ kinh nghiệm của họ tại [SessionStack](https://www.sessionstack.com/).

# Khái quát

Nếu bạn muốn hiểu rõ mọi thứ về Service Workers, bạn cần phải bắt đầu với bài viết trước về [Web Workers](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-7---Thanh-phan-cua-WebWorker---5-truong-hop-su-dung).

Về cơ bản, Service Worker chỉ là 1 loại của Web Worker và cụ thể hơn là nó giống như 1 [Shared Worker](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker):

- Service Worker chạy trong global context của chính nó
- Nó không thể gắn kết với 1 trang cụ thể
- Không thể truy cập vào DOM

Một trong những lý do tại sao Service Worker API rất tuyệt vời là chúng cho phép webapp hỗ trợ trải nghiệm khi offline, cho phép developer hoàn toàn điều khiển luồng sử dụng.

# Vòng đời của Service Worker

Vòng đời của một service worker là hoàn toàn tách biệt với web page. Nó bao gồm các giai đoạn sau:

- Tải về (Download)
- Cài đặt (Installation)
- Kích hoạt (Activation)

## Download

Đây là khi trình duyệt tải file .js chứa Service Worker

## Cài đặt

Để cài đặt một Service Worker cho webapp của bạn thì bạn cần phải đăng ký nó trước trong code Javascript. Khi Service Worker đã đăng ký xong, nó sẽ nhắc nhở tình duyệt khởi động một bước cài đặt chạy nền Service Worker.

Bằng cách đăng ký Service Worker, bạn đã thông báo cho trình duyệt file Javascript của worker nằm ở đâu. Cùng xem ví dụ bên dưới:

```javascript
if ("serviceWorker" in navigator) {
  window.addEventListener("load", function () {
    navigator.serviceWorker.register("/sw.js").then(
      function (registration) {
        // Đăng ký thành công
        console.log("ServiceWorker registration successful");
      },
      function (err) {
        // Đăng ký thất bại
        console.log("ServiceWorker registration failed: ", err);
      }
    );
  });
}
```

Code sẽ kiểm tra nếu môi trường hiện tại có support Service Worker hay không. Nếu như có thì file /sw.js sẽ được đăng ký.

Bạn có thể gọi phương thức register() mỗi khi một trang load lên mà không phải lo lắng gì, trình duyệt sẽ sẽ tự kiểm tra nếu service worker đã được đăng ký hay chưa và tự xử lý một cách phù hợp.

Một điểm quan trọng ở phương thức register() là vị trí của file service worker. Trong trường hợp này bạn có thể thấy rằng file service worker đang ở root của domain. Nghĩa là phạm vi (scope) của service worker sẽ bao hàm toàn bộ origin. Nói cách khác, service worker này sẽ nhận các sự kiện fetch (mà chúng ta sẽ thảo luận sau) cho mọi thứ trên domain này. Nếu ta đăng ký file service worker ở /example/sw.js thì service worker chỉ có thể thấy các sự kiện fetch cho trang có URL bắt đầu với /example/ (ví dụ: /example/page/1, /example/page/2)

Trong giai đoạn cài đặt, tốt nhất ta nên load và cache những tài nguyên dạng tĩnh (static asset). Một khi các tài nguyên đã được cache thành công thì quá trình cài đặt Service Worker cũng hoàn thành. Nếu không (load fail), Service Worker sẽ thử lại (retry). Một khi đã thành công, bạn sẽ biết các static asset đang nằm trong cache.

Bạn sẽ tự hỏi nếu như quá tình đăng ký diễn ra sau sự kiện load thì được không. Điều này không bắt buộc, nhưng đó là cách tốt nhất và được đề nghị làm theo.

Tại sao? Giả sử một user lần đầu tiên ghé thăm webapp của bạn. Không có service worker nào cả và trình duyệt không có cách nào để biết trước có hay không một service worker cần được cài đặt. Nếu như Service Worker đã được cài đặt, trình duyệt sẽ dành ra 1 lượng CPU và bộ nhớ cho tiến trình đó, ngược lại thì trình duyệt sẽ dành toàn bộ cho quá trình render web page.

Điểm mấu chốt là nếu bạn chỉ cài đặt Service Worker trên trang của bạn thì bạn đang mạo hiểm về độ delay của quá trình loading & render chứ không phải đang làm cho trang có thể sẵn sàng cho người dùng một cách nhanh nhất có thể.

Lưu ý rằng điều này chỉ quan trọng cho lần đầu tiên ghé thăm trang. Những lần ghé thăm sau thì không bị ảnh hưởng với quá trình cài đặt Service Worker. Một khi Service Worker đã được kích hoạt trong lần đầu ghé thăm trang, nó có thể xử lý các sự kiện loading/caching cho những lần ghé thăm kế tiếp. Điều này rất có ý nghĩa bởi vì nó cần phải sẵn sàng để xử lý trường hợp kết nối mạng bị hạn chế.

## Kích hoạt

Sau khi Service Worker cài đặt, bước tiếp theo là kích hoạt nó. Bước này là cơ hội tuyệt vời để quản lý cache trước đó.

Một khi đã kích hoạt, Service Worker sẽ bắt đầu kiểm soát toàn trang nằm trong phạm vi của nó. Một sự thật rất thú vị: page nào đăng ký Service Worker lần đầu tiên sẽ không bị điều khiển cho đến khi nó load lại. Một khi Service Worker kiểm soát, nó sẽ có những trạng thái sau:

- Nó sẽ xử lý các sự kiện fetch & message diễn ra khi một request mạng hoặc message được tạo ra từ page.
- Nó sẽ bị hủy bỏ để giải phóng bộ nhớ.

Dưới đây là vòng đời của nó:

![](https://cdn-images-1.medium.com/max/1000/1*mVOrpKC9pFTMg4EXPozoog.png)

# Xử lý quá trình cài đặt bên trong Service Worker

Sau khi page xoay vòng quá trình đăng ký, ta cùng tìm hiểu điều gì diễn ra bên trong script của Service Worker, code này xử lý sự kiện cài đặt bằng cách thêm một event listener vào instance của Service Worker.

Đây là những bước cần thiết khi xử lý sự kiện cài đặt

- Mở cache
- Cache các file
- Xác nhận tất cả các asset cần thiết đều đã được cache.

Dưới đây là quá trình cài đặt đơn giản bên trong Service Worker:

```javascript
var CACHE_NAME = "my-web-app-cache";
var urlsToCache = ["/", "/styles/main.css", "/scripts/app.js", "/scripts/lib.js"];

self.addEventListener("install", function (event) {
  // event.waitUntil nhận một promise để biết quá trình
  // cài đặt mất bao lâu và có thành công hay không.
  event.waitUntil(
    caches.open(CACHE_NAME).then(function (cache) {
      console.log("Opened cache");
      return cache.addAll(urlsToCache);
    })
  );
});
```

Nếu tất cả các file đều đã được lưu cache thành công thì service worker sẽ được cài đặt. Nếu một file nào đó không download được thì bước cài đặt sẽ bị fail. Vì thế hãy cẩn thận với những file bạn truyền vào.

Xử lý sự kiện cài đặt hoàn toàn không bắt buộc và bạn có thể bỏ qua, trong trường hợp đó bạn không cần phải thực hiện thêm bước nào nữa.

# Cache request trong quá trình thực thi (runtime)

Phần này thực sự thú vị một cách xuất sắc. Đây là nơi bạn sẽ biết làm thế nào để can thiệp request và trả về cache đã được tạo (và tạo mới).

Sau khi Service Worker cài đặt xong và user điều hướng đến page khác hoặc refresh lại page hiện tại, Service Worker sẽ nhận được sự kiện fetch. Đây là một ví dụ thể hiện làm thế nào để trả về những asset đã cache hoặc thực hiện một request mới và cache kết quả:

```javascript
self.addEventListener("fetch", function (event) {
  event.respondWith(
    // Phương thức này xem xét request và tìm xem có
    // kết quả nào đã được cache từ tất cả các cache
    // mà Service Worker đã tạo.
    caches.match(event.request).then(function (response) {
      // Nếu tìm thấy cache thì trả về response.
      if (response) {
        return response;
      }

      // Nhân bản request. Một request là 1 stream và chỉ có thể sử dụng 1 lần.
      // Bởi vì chúng ta đang xài 1 cái cho cache và 1 cái cho trình duyệt để fetch,
      // nến ta cần phải nhân bản request.
      var fetchRequest = event.request.clone();

      // Cache không tìm thấy nên ta cần thực hiện fetch
      // để tạo request tới mạng và trả về dữ liệu nếu tìm thấy
      // thứ gì đó.
      return fetch(fetchRequest).then(function (response) {
        // Kiểm tra nếu ta nhận được response hợp lệ.
        if (!response || response.status !== 200 || response.type !== "basic") {
          return response;
        }

        // Nhân bản response bởi vì nó cũng không phải là 1 stream.
        // Bởi vì chúng ta muốn trình duyệt sử dụng response cũng như
        // cache sử dụng response, ta cần nhân bản nó thành 2 stream.
        var responseToCache = response.clone();

        caches.open(CACHE_NAME).then(function (cache) {
          // Thêm request vào cache phục vụ sau này
          cache.put(event.request, responseToCache);
        });

        return response;
      });
    })
  );
});
```

Tóm gọn lại thì đây là những điều đã diễn ra:

- event.respondWith() sẽ xác định làm thế nào chúng ta phản hồi với sự kiện fetch. Ta truyền một promise từ caches.match(), hàm đang kiểm tra request và tìm kiếm nếu có bất kỳ kết quả đã được cache sẵn nào từ những cache đã được tạo trước đó.
- Nếu có cache, response được lấy ra.
- Ngược lại, fetch được thực thi.
- Kiểm tra nếu trạng thái là 200\. Chúng ta sẽ kiểm tra kiểu response là cơ bản, nghĩa là nó sẽ chỉ ra request từ origin của chúng ta. Request đến các asset của bên thứ 3 không thể cache được trong trường hợp này.
- Response được thêm vào cache.

Request và response phải được nhân bản (clone) vì chúng là [stream](https://streams.spec.whatwg.org/). Thân (body) của một stream chỉ có thể sử dụng 1 lần. Và khi ta cần dùng nó, ta phải nhân bản nó bởi vì trình duyệt cũng cần sử dụng nó nữa.

# Cập nhật Service Worker

Khi một user ghé thăm webapp của bạn, trình duyệt sẽ thử download lại file .js chứa code Service Worker. Tác vụ này sẽ được chạy nền.

Nếu có một chút khác biệt dù chỉ một byte giữa file Service Worker mới download về và file cũ thì trình duyệt cũng sẽ giả định rằng có sự thay đổi và Service Worker mới phải khởi tạo lại.

Service Worker mới sẽ bắt đầu khởi tạo và cài đặt. Tuy nhiên vào thời điểm này, Service Worker cũ vẫn đang kiểm soát page trên webapp của bạn, nghĩa là Service Worker mới sẽ nằm trong trạng thái chờ đợi.

Một khi trang đang mở được đóng lại, Service Worker cũ sẽ bị hủy bởi trình duyệt và Service Worker mới cài đặt sẽ chiếm quyền kiểm soát toàn bộ. Đây là khi sự kiện kích hoạt của nó được kích hoạt.

Tại sao lại cần phải làm tất cả điều này? Là để tránh vấn đề khi có 2 phiên bản webapp chạy đồng thời trong các tab khác nhau. Việc này diễn ra một cách rất phổ biến và có thể tạo ra những lỗi tồi tệ (ví dụ: bạn có schema khác nhau trong khi lưu trữ dữ liệu local trên trình duyệt).

# Xóa dữ liệu trong cache

Bước phổ biến nhất trong callback kích hoạt là quản lý cache. Bạn sẽ cần phải làm điều này ngay bởi vì nếu bạn dọn dẹp cache cũ trong bước cài đặt, Service Worker cũ sẽ dừng lại một cách đột ngột và không thể phân phối các file từ cache đó nữa.

Dưới đây là ví dụ cách bạn có thể xóa vài file không nằm trong danh sách an toàn trong cache (trong trương hợp này là có chữ page-1 và page-2 trong tên của nó)

```javascript
self.addEventListener("activate", function (event) {
  var cacheWhitelist = ["page-1", "page-2"];

  event.waitUntil(
    // Lấy tất cả key từ cache.
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        // Lặp qua mảng các file.
        cacheNames.map(function (cacheName) {
          // Nếu file trong cache không nằm trong danh sách an toàn
          // thì nó sẽ bị xóa.
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});
```

# Yêu cầu HTTPS

Khi xây dựng webapp, bạn có thể sử dụng Service Worker qua localhost nhưng một khi đã deploy nó lên production, bạn cần chuẩn bị HTTPS (và đó cũng là lý do cuối cùng bạn cần đến HTTPS).

Sử dụng Service Worker, bạn có thể chiếm quyền kết nối và ngụy tạo response. Nếu không dùng HTTPS, webapp của bạn trở thành đối tượng của cách tấn công [kẻ-trung-gian](https://en.wikipedia.org/wiki/Man-in-the-middle_attack) (man-in-the-middle).

Để an toàn hơn, bạn cần phải đăng ký Service Worker với page được phân phối qua HTTPS để bạn biết được Service Worker nào trình duyệt nhận về mà không bị thay đổi khi lưu thông qua mạng.

# Các trình duyệt hỗ trợ

Sự hỗ trợ cho Service Worker ngày càng được cải thiện:

![](https://cdn-images-1.medium.com/max/1000/1*6o2TRDmrJlS97vh1wEjLYw.png)

Bạn có thể theo dõi tiến độ cho tất cả các trình duyệt tại đây: [https://jakearchibald.github.io/isserviceworkerready/](https://jakearchibald.github.io/isserviceworkerready/)

# Service Workers mở ra chân trời mới

Một số tính năng độc đáo mà Service Worker cung cấp:

- **Push notifications **: cho phép user tham gia vào lắng nghe cập nhật theo thời gian
- **Đồng bộ dưới nền (background sync)**: cho phép bạn tạm hoãn các hành động cho tới khi user có kết nối ổn định. Bằng cách này bạn có thể đảm bảo rằng bất kỳ thứ gì mà user cần gửi thì chắc chắn nó sẽ được gửi đi.
- **Đồng bộ định kỳ (periodic sync - tương lai)**: API cung cấp khả năng quản lý đồng bộ dưới nền theo chu kỳ.
- **Ranh giới ảo (Geofencing - tương lai)**: bạn có thể định nghĩa params, còn gọi là những geofence bao quanh một khu vực. Webapp sẽ nhận thông báo khi có một thiết bị vượt qua geofence, điều này cho phép bạn cung cấp trả nghiệm có ích dựa trên vị trí địa lý của user.

Mỗi mục này sẽ được thảo luận chi tiết hơn trong các bài viết khác.

Team tác giả đang nỗ lực không ngừng để mang lại trải nghiệm UX mượt mà nhất có thể cho SessionStack, tối ưu hóa thời gian tải trang và thời gian phản hồi.

Khi bạn replay lại 1 session của user trên [SessionStack](https://www.sessionstack.com/) (hoặc xem nó trong thời gian thực), phần SessionStack front-end sẽ không ngừng lấy dữ liệu từ server về để tạo ra một trải nghiệm liền mạch như lưu trong buffer. Một khi bạn đã tích hợp thư viện của SessionStack vào trong webapp, nó sẽ bắt đầu thu thập dữ liệu liên tục về thay đổi trên DOM, tương tác người dùng, request mạng, biệt lệ không được xử lý và thông báo lỗi.

Khi một phiên làm việc được replay hoặc stream theo thời gian thực thì SessionStack phục vụ tất cả dữ liệu cho phép bạn thấy mọi thứ về trải nghiệm người dùng ở góc độ trình duyệt của user (cả về mặt kỹ thuật lẫn hình ảnh). Những công việc này cần phải được thực hiện cực nhanh để không làm cho user phải chờ đợi.

Bởi vì dữ liệu được front-end kéo về nên đây là một sàn diễn tuyệt vời cho Service Worker có thể "tỏa sáng" mà xử lý những trường hợp như reload player và stream mọi thứ thêm vài lần nữa. Xử lý kết nối mạng bị chậm cũng cực kỳ quan trọng.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p8-service-workers-vong-doi-va-cac-truong-hop-su-dung</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p8-service-workers-vong-doi-va-cac-truong-hop-su-dung</guid>
            <pubDate>Sat, 24 Nov 2018 22:04:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P7: Thành phần của WebWorker + 5 trường hợp sử dụng]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 7 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Trong bài này chúng ta sẽ tìm hiểu về Web Workers: một cái nhìn tổng quan, thảo luận về các loại worker khách nhau, các thành phần của nó hoạt động với nhau như thế nào và những điểm mạnh cũng như điểm yếu của nó trong các ngữ cảnh khác nhau. Cuối cùng, team tác giả sẽ cung cấp 5 trường hợp mà trong đó Web Worker là sự lựa chọn đúng đắn.

Bạn đã quen với sự thật rằng Javascript chạy đơn luồng như chúng ta đã [thảo luận chi tiết ở bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-1---Khai-quat-ve-engine--runtime-va-callstack). JS cũng giúp các developer viết code bất đồng bộ.

# Những hạn chế của lập trình bất đồng bộ

Chúng ta đã thảo luận ở [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-4---Event-loop--lap-trinh-bat-dong-bo---5-meo-cai-thien-Async-Await) về lập trình bất đồng bộ và khi nào thì nên dùng.

Lập trình bất đồng bộ cho phép UI của app trở nên mượt mà, bằng cách "lên lịch" cho từng phần của code được thực thi ở thời gian phù hợp trong event loop, do đó nó cho phép render UI được thực hiện trước.

Một trường hợp tốt để dùng lập trình bất đồng bộ là khi ta gọi Ajax request. Bởi vì request có thể tốn nhiều thời gian nên có thể để cho nó chạy bất đồng bộ và trong khi client chờ kết quả trả về, những code khác vẫn được thực thi.

```javascript
// Giả sử bạn dùng jQuery
jQuery.ajax({
  url: "https://api.example.com/endpoint",
  success: function (response) {
    // code được thực thi khi response trả về
  },
});
```

Nhưng điều này lại gây ra vấn đề khác: request được xử lý bởi Web API của trình duyệt, nhưng làm thế nào mà code khác có thể chạy bất đồng bộ? Ví dụ nếu như code bên trong một success callback lại chạy ngốn rất nhiều CPU:

```javascript
var result = performCPUIntensiveCalculation();
```

Nếu như performCPUIntensiveCalculation không phải là một request HTTP nhưng lại block code xử lý (ví dụ: 1 vòng lặp rất lớn), không có cách nào để giải phóng event loop và unblock cho UI trình duyệt, nó sẽ đóng băng và không phản hồi lại với user.

Nghĩa là trong Javascript, những hàm bất đồng bộ chỉ giải quyết vấn đề nhỏ của hạn chế ở đơn luồng.

Trong những trường hợp đó, bạn có thể làm cho unblock UI khỏi quá trình tính toán quá lâu bằng cách sử dụng setTimeout. Ví dụ, tách một chuỗi xử lý tính toán phức tạp vào trong nhiều lời gọi setTimeout, bằng cách đó bạn có thể đặt chúng vào những "vị trí" khác nhau trong event loop và cách này có thể giúp cho render UI được tốt hơn.

Cùng xem một ví dụ đơn giản về tính toán số trung bình của 1 mảng số nguyên:

```javascript
function average(numbers) {
  var len = numbers.length,
    sum = 0,
    i;

  if (len === 0) {
    return 0;
  }

  for (i = 0; i < len; i++) {
    sum += numbers[i];
  }

  return sum / len;
}
```

Dưới đây là cách ta viết lại code trên và "giả lập" trường hợp bất đồng bộ:

```javascript
function averageAsync(numbers, callback) {
  var len = numbers.length,
    sum = 0;

  if (len === 0) {
    return 0;
  }

  function calculateSumAsync(i) {
    if (i < len) {
      // Đưa hàm tiếp theo vào event loop
      setTimeout(function () {
        sum += numbers[i];
        calculateSumAsync(i + 1);
      }, 0);
    } else {
      // hết mảng, gọi callback
      callback(sum / len);
    }
  }

  calculateSumAsync(0);
}
```

Cách này sẽ dùng setTimeout để thêm mỗi bước thực hiện tính toán vào trong event loop. Giữa mỗi lần tính toán sẽ có đủ thời gian cho các tính toán được thêm vào và giải phóng trình duyệt khỏi bị đóng băng.

# Web Workers đến giải cứu

HTML5 mang đến cho chúng ta rất nhiều thứ tuyệt vời:

- SSE (đã thảo luận và so sánh với WebSocket ở [bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-5---Dao-sau-WebSocket---HTTP-2-voi-SSE---Hay-chon-gia-dung))
- Geolocation
- Application cache
- Local Storage
- Drag and Drop
- **Web Workers**

Web Workers là tiến trình trong trình duyệt nhưng có thể được dùng để thực thi Javascript code mà không cản trở event loop

Điều này thực sự kỳ diệu. Toàn bộ mô hình của Javascript dựa trên ý tưởng về môi trường đơn luồng nhưng giờ đây là có Web Workers và nó gỡ bỏ (1 phần nào) sự hạn chế đó.

Web Workers cho phép developer đặt những công việc có thời gian chạy dài và những công việc nặng về xử lý tính toán trong background mà không gây trở ngại đến UI, làm app của bạn mượt mà hơn. Ngoài ra, không cần phải xài trick với setTimeout để đánh lừa event loop nữa.

[Ở đây](http://afshinm.github.io/50k/) có một demo mẫu thể hiện sự khác nhau khi thực hiện sắp xếp mảng dùng và không dùng Web Workers.

# Khái quát về Web Workers

Web Workers cho phép bạn làm những việc như thực thi các đoạn code xử lý tốn thời gian để tính toán các phép tính hao tổn nheiefu CPU nhưng không làm cản trở UI. Thực ra, nó sẽ chạy song song. Web Workers là đa luồng.

Bạn sẽ thắc mắc: "Chứ không phải Javascript là ngôn ngữ đơn luồng à?"

Đây là lúc mà bạn sẽ thốt lên _aha_ ngạc nhiên khi nhận ra Javascript là một ngôn ngữ không định nghĩa mô hình tiến trình. **Web Workers không phải là một phần của Javascript, nó là tính năng của trình duyệt mà có thể truy xuất thông qua Javascript**. Đa số các trình duyệt có lịch sử về đơn tiến trình (giờ thì thay đổi rồi), và đa số các triển khai của Javascript đều diễn ra trên trình duyệt. Web Workers không được triển khai trên Node.js, nó có khái niệm hơi khác một chút về cluster hay child_process.

Có 3 loại Web Workers được đề cập đến trong [thông số kỹ thuật](http://www.whatwg.org/specs/web-workers/current-work/):

- [Dedicated Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers)
- [Shared Workers](https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker)
- [Service workers](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker_API)

# Dedicated Workers (Worker chuyên dụng)

Dedicated Web Workers được khởi tạo bởi tiến trình chính và chỉ có thể giao tiếp với tiến trình đó.

![](https://cdn-images-1.medium.com/max/1000/1*ya4zMDfbNUflXhzKz9EBIw.png)

# Shared Workers (Worker chia sẻ)

Shared Workers có thể được truy cập bởi tất cả các tiến trình chạy trên cùng origin (khác tab trình duyệt, iframe hoặc là các shared worker khác)

![](https://cdn-images-1.medium.com/max/1000/1*lzOIevUBVy5eWyf2kHf--w.png)

Nếu bạn muốn dùng thử SessionStack để hiểu và khám phá lại những vấn đề kỹ thuật cũng như UX trên webapp của bạn, team SessionStack đang có bản dùng thử miễn phí, [ở đây nhé](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=Post-5-websockets-getStarted).

# Service Workers (Worker dịch vụ)

Một Service Worker là worker hướng sự kiện (event-driven) được đăng ký với origin và path. Nó có thể điều khiển web page/site mà nó liên kết, can thiệp và chỉnh sửa sự điều hướng và các yêu cầu tài nguyên, lưu đệm tài nguyên với phong cách rất chi tiết để cho phép bạn có toàn quyền điều khiển về việc app của bạn xử lý như thế nào trong từng trường hợp cụ thể (ví dụ như khi rớt mạng)

![](https://cdn-images-1.medium.com/max/1000/1*6o2TRDmrJlS97vh1wEjLYw.png)

Trong bài này chúng ta sẽ tập trung vào **Dedicated Worker** và chỉ gọi nó dưới cái tên **Web Workers** hoặc **Worker**

# Web Workers hoạt động như thế nào?

Web Workers được triển khai dưới dạng đuôi .js và được đính kèm theo request HTTP bất đồng bộ trong web của bạn. Những request này được ẩn hoàn toàn bởi [Web Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)

Workers sử dụng message kiểu tiến trình để thực hiện quá trình hoạt động song song. Chúng có thể giữ cho UI được cập nhật mới nhất, có thể tương tác và mượt mà với người dùng một cách hoàn hảo.

Web Workers chạy trong một tiến trình cô lập trong trình duyệt. **Do đó là code chúng thực thi cần phải đặt trong 1 file riêng biệt**. Điều này rất quan trọng nhé.

Cách tạo worker cơ bản

```javascript
var worker = new Worker("task.js");
```

Nếu task.js tồn tại và có thể truy cập được, trình duyệt sẽ thiết lập một tiến trình mới để tải file bất đồng bộ. Sau khi quá trình tải file hoàn tất, nó sẽ thực thi code trong đó và worker bắt đầu làm việc.

Trong trường hợp file lỗi không load được thì trả về 404 và worker sẽ dừng lại một cách yên lặng như chưa có gì xảy ra.

Để bắt đầu tạo worker, bạn cần gọi phương thức postMessage:

```javascript
worker.postMessage();
```

# Giao tiếp của Web Worker

Để giao tiếp giữa một Web Worker và trang của bạn thì bạn cần phải sử dụng phương thức postMessage hoặc [kênh phát sóng](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) (Broadcast channel).

# Phương thức postMessage

Các trình duyệt mới hỗ trợ object JSON như là param đầu tiên của phương thức trong khi các trình duyệt cũ hơn thì chọn string

Dưới đây là ví dụ về một page có worker có thể giao tiếp qua lại với nó như thế nào bằng cách truyền một object JSON. Truyền string cũng tương tự:

```javascript
<button onclick="startComputation()">Start computation</button>

<script>
  function startComputation() {
    worker.postMessage({'cmd': 'average', 'data': [1, 2, 3, 4]});
  }
  var worker = new Worker('doWork.js');
  worker.addEventListener('message', function(e) {
    console.log(e.data);
  }, false);

</script>
```

Và đoạn code của worker:

```javascript
self.addEventListener(
  "message",
  function (e) {
    var data = e.data;
    switch (data.cmd) {
      case "average":
        var result = calculateAverage(data); // Tính trung bình cộng từ một array
        self.postMessage(result);
        break;
      default:
        self.postMessage("Unknown command");
    }
  },
  false
);
```

Khi click vào button, trang chính sẽ gọi tới postMessage. Dòng worker.postMessage truyền một object JSON vào worker, object chứa thông tin là cmd và data. Worker sẽ xử lý message thông qua một message handler đã được định nghĩa.

Khi message đến, các thao tác tính toán thực sự sẽ được thực hiện trong worker mà không cản trở event loop. Worker kiểm tra event e được truyền vào và thực thi giống như một hàm Javascript bình thường. Khi xong việc kết quả sẽ được trả ngược lại cho trang chính.

Trong ngữ cảnh của worker, cả self và this đều đang tham chiếu đến global scope.

> Có 2 cách để dừng worker: gọi hàm worker.terminate() từ ngoài trang chính hoặc gọi self.close() bên trong worker.

# Kênh phát sóng (Broadcast Channel)

[Broadcast Channel](https://developer.mozilla.org/en-US/docs/Web/API/BroadcastChannel) giống như một API giao tiếp tổng quát. Nó cho phép chúng ta broadcast message tới tất cả các ngữ cảnh cùng chia sẻ chung origin. Tất cả các tab trình duyệt, iframe hoặc worker phục vụ chung origin có thể phát và nhận message.

```javascript
// Kết nối đến một broadcast channel
var bc = new BroadcastChannel("test_channel");

// Ví dụ gửi một message đơn giản
bc.postMessage("This is a test message.");

// Ví dụ về một event handler có chức
// năng in message ra console
bc.onmessage = function (e) {
  console.log(e.data);
};

// Ngắt kết nối
bc.close();
```

Xem hình minh họa thì bạn sẽ hiểu cách hoạt động của Broadcast Channel rõ ràng hơn:

![](https://cdn-images-1.medium.com/max/1000/1*NVT6WbNrH_mQL64--b-l1Q.png)

Broadcast Channel bị hạn chế hỗ trợ từ các trình duyệt:

![](https://cdn-images-1.medium.com/max/1000/1*81mCsOzyJj-HfQ1lP_033w.png)

# Kích thước message

Có 2 cách để gửi message trong Web Workers:

- **Sao chép message**: message được serialized, sao chép, gửi đi và được de-serialized ở đầu kia. Trang web và worker không dùng chung instance, vì thế cuối cùng là kết quả sẽ bị trùng lặp ở cả 2 phía. Đa số các trình duyệt triển khai tính năng này bằng cách encoding/decoding giá trị ở cả 2 phía thành JSON một cách tự động. Đúng như dự đoán thì các hoạt động dữ liệu như thế này bổ sung thêm chi phí đáng kể vào việc truyền tải message. Message càng lớn thì thời gian gửi càng lâu.

- **Truyền tải message**: điều này nghĩa là bên gửi sẽ không thể sử dụng nó một khi đã gửi đi. Truyền tải dữ liệu gần như tức thời. Hạn chế là chỉ duy nhất [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) là có thể gửi được.

# Tính năng có sẵn của Web Workers

Web Workder chỉ có truy xuất tới một tập hợp nhỏ các tính năng của Javascript bởi vì bản chất đa luồng của nó, dưới đây là danh sách các tính năng:

- Object navigator
- Object location (chỉ đọc - read only)
- XMLHttpRequest
- setTimeout()/clearTimeout() và setInterval()/clearInterval()
- Bộ đệm ứng dụng ([Application Cache](https://www.html5rocks.com/tutorials/appcache/beginner/))
- Import script bên ngoài thông qua importScripts()
- [Tạo các web worker khác](https://www.html5rocks.com/en/tutorials/workers/basics/#toc-enviornment-subworkers)

# Hạn chế của Web Workers

Hơi buồn là Web Worker không có quyền truy cập đến một số tính năng quan trọng của Javascript:

- DOM (not thread-safe)
- Object window
- Object document
- Object parent

Điều này nghĩa là Web Worker không thể thay đổi DOM (và UI). Nó có thể hơi khó khăn, nhưng nếu bạn đã quen với viêc sử dụng Web Worker đúng cách thì bạn sẽ bắt đầu sử dụng khả năng "tính toán độc lập" của nó trong khi các code thay đổi UI đang được xử lý và hoạt động. Worker sẽ chăm sóc tất cả những phần nặng nhọc cho bạn và khi đã xong viêc thì bạn chỉ cần gửi kết quả ra màn hình để cập nhật UI cho phù hợp.

# Xử lý lỗi

Giống như code Javascript khác, bạn sẽ cần xử lý lỗi khi Web Worker bắn ra. Nếu có lỗi xảy ra trong quá trình worker thực thi, ErrorEvent sẽ được bắn. Interface này sẽ bao gồm 3 thuộc tính hữu ích cho việc tìm ra bạn đang sai chỗ nào:

- **filename**: tên của worker script gây ra lỗi
- **lineno**: số của dòng gây ra lỗi
- **message**: mô tả lỗi

Ví dụ:

```javascript
function onError(e) {
  console.log('Line: ' + e.lineno);
  console.log('In: ' + e.filename);
  console.log('Message: ' + e.message);
}

var worker = new Worker('workerWithError.js');
worker.addEventListener('error', onError, false);
worker.postMessage(); // Khởi tạo worker mà không truyền messageself.addEventListener('message', function(e) {
  postMessage(x * 2); // Intentional error. 'x' is not defined.
};
```

Ở đây bạn thấy rằng chúng ta tạo worker và bắt đầu listen sự kiện error.

Bên trong worker (file workerWithError.js) chúng ta cố tình tạo một exception bằng cách nhân x với 2 trong khi x không hề tồn tại trong scope đó. Exception được bắn ra khi khởi tạo script và hàm onError được gọi với thông tin về lỗi.

# Trường hợp nên sử dụng Web Workers

Cho đến bây giờ thì chúng ta đã nghiên cứu về điểm mạnh và hạn chế của Web Workers. Cùng xem những trường hơp nào thì dùng chúng là tốt nhất:

- **Dò tia (Ray tracing)**: ray tracing là một kỹ thuật [render](https://en.wikipedia.org/wiki/Rendering_%28computer_graphics%29) để sinh ra những hình ảnh bằng cách dò theo vết đường đi của ánh sáng theo dạng pixel. Ray traycing sử dụng rất nhiều phép tính toán học có ảnh hướng lớn đến CPU để giả lập đường đi của ánh sáng. Ý tưởng về giả lập những hiệu ứng như phản chiếu (reflection), khúc xạ (refraction), vật liệu, vân vân. Tất cả các logic tính toán như vậy đều có thể đưa vào Web Worker để tránh gây trở ngại với UI thread. Thậm chí có thể tốt hơn nếu bạn có thể chia nhỏ quá trình render hình ảnh ra nhiều worker (và chia ra nhiều CPU). Đây là 1 minh họa đơn giản của ray tracing sử dụng Web Workers:  [https://nerget.com/rayjs-mt/rayjs.html](https://nerget.com/rayjs-mt/rayjs.html)
- **Mã hóa (Encryption)**: Mã hóa end-to-end (E2EE) càng ngày càng phổ biến do sự gia tăng khắt khe về các quy định của dữ liệu nhạy cảm & cá nhân. Mã hóa có thể khá tốn thời gian, đặc biệt nếu có rất nhiều dữ liệu cần được mã hóa thường xuyên (trước khi gửi về server chẳng hạn). Đây là một trường hợp trong đó Web Worker là lựa chọn rất tốt vì nó không yêu cầu truy xuất đến DOM hay các thứ khác, chỉ thuần túy là thuật toán mã hóa. Một khi đã được đẩy vào worker xử lý, nó sẽ hoạt động rất trơn tru và không ảnh hưởng đến trải nghiệm của người dùng.
- **Tải trước dữ liệu**: Để tối ưu website hoặc webapp và cải thiện thời gian loading, bạn có thể nhờ vả Web Workers để load và lưu dữ liệu trước và sử dụng chúng về sau khi cần đến. Web Workers rất tốt trong trường hợp này vì nó không ảnh hướng đến UI, không giống như khi ta dùng mà không có workers.
- **Progressive Web Apps**: Chúng cần được load thật nhanh kể cả khi kết nối mạng không ổn định. Nghĩa là dữ liệu cần phải được lưu trên trình duyệt. IndexDB hoặc những API tương tự hỗ trợ tốt khoản này. Về cơ bản thì lưu trữ ở phía client là cần thiết. Để có thể sử dụng mà không gây cản trở đến UI, công việc cần phải được hoàn thành trong Web Workers. Trong trường hợp của IndexDB, có một API bất đồng bộ cho phép bạn làm việc này mà không dùng workers, tuy nhiên cũng có một API đồng bộ trước đây (có thể sẽ được giới thiệu lại) chỉ được phép chạy bên trong workers.
- **Kiểm tra chính tả (Spell checking)**: một bộ spell checker cơ bản hoạt động như sau: chương trình sẽ đọc một file từ điển với danh sách các từ đúng chính tả. Từ điển sẽ được parse thành cây tìm kiếm (search tree) để có thể tìm kiếm văn bản hiệu quả. Khi một từ được đưa vào checker, chương trình sẽ kiểm tra nếu nó tồn tại trong cây tìm kiếm. Nếu từ đó không tồn tại, chương trình sẽ cung cấp từ thay thế bằng cách thay đổi ký tự thay thế và kiểm tra nếu đó là 1 từ hợp lệ nếu nó là từ mà user muốn viết ra. Tất cả quá trình này có thể dễ dàng giảm tải cho hệ thống bằng Web Workers và user có thể gõ chữ, viết câu mà không gây cản trở với UI trong khi worker thực thi tất cả các phần tìm kiếm và đưa ra đề xuất.

Hiệu năng và độ tin cậy là rất quan trọng đối với team SessionStack. Lý do là vì một khi đã tích hợp SessionStack vào web app của bạn, chương trình sẽ bắt đầu ghi lại mọi thứ từ thay đổi trên DOM và tương tác người dùng đến các request mạng, exception không được xử lý và các thông báo lỗi. Tất cả dữ liệu được truyền về cho server của chương trình trong **thời gian thực** để có thể cho phép bạn chạy lại những issue từ webapp dưới dạng video và xem thử điều gì đang diễn ra với user. Tất cả điều này được thực hiện với độ trễ tối thiểu và không có ảnh hưởng đến hiệu năng của app của bạn.

Đây là lý do mà team tác giả đã đưa toàn bộ logic (phần nào có thể) từ cả thư viện điều hành & phần player vào Web Worker để xử lý các công viêc nặng tải với CPU như băm để xác nhận tính toàn vẹn dữ liệu, render, vân vân.

Công nghệ web liên tục thay đổi và phát triển vì thế team tác giả đã đi thêm 1 chặng đường dài để đảm bảo SessionStack thật nhẹ và không gây ảnh hưởng đến hiệu năng của người dùng.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p7-thanh-phan-cua-webworker-5-truong-hop-su-dung</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p7-thanh-phan-cua-webworker-5-truong-hop-su-dung</guid>
            <pubDate>Fri, 16 Nov 2018 07:27:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P6: So sánh với WebAssembly + Một số trường hợp tốt hơn nên sử dụng]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 6 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Lần này chúng ta sẽ khám phá về WebAssembly và phân tích cách hoạt động của nó, quan trọng hơn là những điểm vượt trội hơn so với Javascript về mặt hiệu năng: thời gian tải, tốc độ thực thi, dọn rác (GC), sử dụng bộ nhớ, truy cập API, debugging, đa luồng và tính di động (portability).

Cách chúng ta xây dựng web app trên bờ vực cách mạng - vẫn đang trong những ngày đầu nhưng cách chúng ta suy nghĩ về web app đang dần thay đổi.

# Cùng xem WebAssembly có thể làm gì

WebAssembly (gọi tắt **wasm**) là một loại bytecode cấp độ thấp và hiệu quả cho web.

WASM cho phép bạn sử dụng ngôn ngữ khác Javascript (như C, C++, Rust...), viết chương trình với những ngôn ngữ đó, và biên dịch trước (ahead of time) sang WebAssembly.

Kết quả là webapp sẽ load và thực thi rất nhanh.

# Thời gian tải (loading time)

Để load Javascript, trình duyệt phải load tất cả file .js đúng nguyên văn bản.

WebAssembly load nhanh hơn trong trình duyệt bởi vì chỉ có những file wasm **đã được biên dịch** là được truyền tải qua internet. Và bởi vì wasm là ngôn ngữ bậc thấp gần giống assembly có format nhị phân rất nhỏ gọn.

# Thực thi (execution)

Wasm chạy chậm hơn 20% **so với native code**. Dù gì đi nữa thì đây là một kết quả đáng kinh ngạc. Nó là một định dạng được biên dịch sang môi trường sandbox và chạy cùng rất nhiều ràng buộc để đảm bảo nó không có những điểm yếu bảo mật hoặc rất khó để chống lại. Tốc độ chậm là không đáng kể khi so với native code. Hơn nữa, nó sẽ được cải thiện chạy nhanh hơn trong tương lai.

Ngoài ra, khả năng tương thích rất tốt với trình duyệt là điểm mạnh, tất cả những engine lớn đều có hỗ trợ WebAssembly và đều đưa ra thời gian thực thi tương đương nhau.

Để hiểu WebAssembly thực thi nhanh như thế nào so với Javascript, bạn nên [đọc bài trước trong series Đục khoét Javascript](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-2---Ben-trong-engine-V8---5-meo-de-toi-uu-hoa-code)

Cùng xem điều gì xảy ra trong V8:
![](https://cdn-images-1.medium.com/max/1000/0*bN9YVBLw_tT1Xvte.)

Cách tiếp cận của V8: biên dịch chậm

Ở bên trái, chúng ta có Javascript source, bao gồm các hàm. Đầu tiên thì nó cần phải được parse (phân tích cú pháp) để chuyển tất cả string sang token và sinh ra [Abstract Syntax Tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) (AST - Cây cú pháp trừu tượng, chúng ta sẽ có một bài viết về nó sau). Cây AST là đại diện biểu thị logic của chương trình JS trong bộ nhớ. Một khi nó được sinh ra, V8 sẽ đi thẳng đến mã máy. Về cơ bản thì bạn sẽ duyệt qua cây đó, tạo ra mã máy và hàm của bạn đã được biên dịch. Không có tiến trình nào cố gắng tăng tốc nó.

Giờ thì lướt qua xem V8 pipeline làm gì tiếp theo:

![](https://cdn-images-1.medium.com/max/1000/0*wzuQ9LYv7CAUICOC.)

Chúng ta có [TurboFan](https://github.com/v8/v8/wiki/TurboFan), 1 trong những trình biên dịch tối ưu hóa của V8\. Trong khi app Javascript đang chạy thì còn có rất nhiều code khác chạy trong V8\. TurboFan thực hiện điều hành, nếu có gì chạy chậm bất kể là đang nghẽn cổ chai (bottleneck) hay những điểm nóng (hot spots), thì sẽ được tối ưu hóa. Nó đẩy phần code đang ngốn tài nguyên CPU đó qua một bộ [JIT](https://en.wikipedia.org/wiki/Just-in-time_compilation) tối ưu để tạo ra code nhanh hơn nhiều.

Nó giải quyết vấn đề, nhưng bên cạnh đó quá trình phân tích code và quyết định nên tối ưu như thế nào cũng làm tốn tài nguyên CPU. Điều này, làm hao tổn thời lượng pin nhiều hơn, đặc biệt là trên các thiết bị di động.

Chà, wasm thì không cần. Nó đi thẳng vào quá trình làm việc như dưới đây:

![](https://cdn-images-1.medium.com/max/1000/0*GDU4GguTzk8cSAYk.)

Wasm đã duyệt qua quá trình tối ưu hóa ngay trong giai đoạn biên dịch. Trên hết thì parsing đã không còn cần thiết nữa. Bạn có mã nhị phân tối ưu có thể gắn trực tiếp vào bộ phận backend để sinh ra mã máy. Tất cả các sự tối ưu hóa đã được hoàn thành bởi trình biên dịch ở frontend.

Điều này làm cho quá trình thực thi wasm trở nên hiệu quả hơn rất nhiều bởi vì ta có thể bỏ qua 1 số bước trong khi xử lý.

# Mô hình bộ nhớ

![](https://cdn-images-1.medium.com/max/1000/0*QphcOVaiVC2YL7Jd.)

Bộ nhớ của 1 chương trình C++ là chuỗi liền kề các block nhớ không có "lỗ". Một trong số các tính năng của wasm giúp đẩy mạnh sự bảo mật là ý tưởng về stack thực thi đặt riêng biệt với bộ nhớ thẳng hàng (linear). Trong C++ ta có heap, cấp phát từ đáy của heap và phát triển stack ở đỉnh heap. Ta có thể lấy con trỏ và tìm kiếm trong bộ nhớ stack để chơi đùa với những biến mà chúng ta còn không đụng tới.

Đây là một điểm cạm bẫy mà rất nhiều malware khai thác.

WebAssembly sử dụng một mô hình hoàn toàn khác. Stack thực thi tách biệt với chương trình chính WebAssembly nên không có cách nào bạn có thể chỉnh sửa và thay đổi những biến bên trong nó. Thêm nữa là các hàm có offset là số nguyên chứ ko dùng contror. Hàm trỏ vào một bảng chức năng vô hướng. Sau đó, các con số được tính toán trực tiếp này được đưa vào bên trong module. Nó được xây dựng theo cách này để có thể load nhiều wasm cùng lần, đánh offset tất cả các index và nó sẽ chạy tốt.

Để tìm hiểu sâu hơn về mô hình bộ nhớ và các cách quản lý trong Javascript, bạn có thể [xem lại bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-3---Quan-ly-bo-nho---4-truong-hop-ro-ri-pho-bien).

# Dọn rác (GC)

Chúng ta đã biết quản lý bộ nhớ của Javascript có bao gồm cả xử lý dọn rác Garbage Collector.

Đối với WebAssembly thì hơi khác một chút. Nó hỗ trợ những ngôn ngữ quản lý bộ nhớ thủ công. Bạn có thể sử dụng GC của chính bạn với các wasm module, nhưng công việc đó hơi phức tạp.

Hiện tại, WebAssembly được thiết kế xoay quanh các trường hợp sử dụng của C++ và RUST. Bởi vì wasm là ngôn ngữ thấp nên sẽ dễ hiểu hơn nếu sử dụng những ngôn ngữ lập trình gần gũi & dễ biên dịch ra ngôn ngữ assembly. C có thể sử dụng malloc thường, C++ có thể dùng con trỏ thông minh. Rust dùng một mô hình khác hoàn toàn (nhưng là 1 chủ đề khác nhé). Những ngôn ngữ này không dùng GC, do đó chúng không cần các tác vụ runtime để theo dõi bộ nhớ. WebAssembly phù hợp với chúng.

Thêm nữa, những ngôn ngữ này không phải được thiết kế 100% cho việc truy vấn những thứ phức tạp thuộc về Javascript, ví dụ như thay đổi DOM. Nó khá vô nghĩa khi phải viết toàn bộ app HTML trên nền C++ bởi vì C++ không được thiết kế với mục đích làm webapp. Đa số các trường hợp các kỹ sư dùng C++ hoặc Rust, họ hướng tới WebGL hoặc những thư viện có tính tối ưu hóa cao. (Ví dụ: phép tính toán học khó và phức tạp)

Tuy nhiên, trong tương lai WebAssembly sẽ hỗ trợ những ngôn ngữ có sẵn GC.

# Truy xuất Platform API

Tùy thuộc vào môi trường runtime thực thi Javascript, quyền truy xuất vào những API đang tồn tại đặc trưng cho platform có thể được truy cập trực tiếp thông qua app JS của bạn. Ví dụ: bạn chạy JS code trên trình duyệt, bạn có 1 cục các Web API mà webapp có thể gọi và điều khiển trình duyệt hoặc chức năng thiết bị và có quyền truy xuất vào DOM, CSSOM, WebGL, IndexedDB, Web Audio API, vân vân.

WebAssembly module không có quyền truy cập vào platform API. Mọi thứ đều trung gian qua Javascript. Nếu bạn muốn truy xuất vào một số API đặc trưng cho platform bên trong module WebAssembly thì bạn phải gọi nó thông qua Javascript.

Ví dụ, nếu muốn dùng console.log, bạn gọi nó thông qua JS thay vì C++. Và dĩ nhiên là sẽ có những hạn chế về JS mà ta phải chấp nhận.

Nhưng trường hợp này sẽ sớm được khắc phục khi mà đặc điểm kỹ thuật sẽ cung cấp các platform API cho wasm trong tương lai, bạn sẽ có thể sớm phát triển app mà không cần Javascript.

# Ánh xạ mã nguồn (Source map)

Khi bạn làm tối giản code JS, bạn cần đảm bảo có thể debug nó. Đó là khi mà ta cần đến [Source Map](https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/).

Về cơ bản, Source Map là 1 cách để map một file tối giản về với trạng thái ban đầu của nó. Khi bạn build sản phẩm cho môi trường production, cùng với file JS đã kết hợp & tối gian, bạn sẽ sinh ra 1 file source map chứa thông tin về file JS gốc. Khi bạn query một dòng cụ thể với số cột nào đó file JS, bạn có thể tra cứu trong source map để tìm ra vị trí gốc ban đầu của nó.

WebAssembly không hỗ trợ source map vì nó chưa có mô tả kỹ thuật cho phần này nhưng hi vọng là tương lai gần sẽ hỗ trợ.

Khi bạn đặt breakpoint trong code C++, bạn sẽ thấy code C++ thay vì WebAssembly, ít nhất là vẫn còn có ích.

# Đa luồng (Multithreading)

Ai cũng biết Javascript là đơn luồng. Có nhiều cách để cải thiện Event Loop và nâng cấp phần lập trình bất đồng bộ mà chúng tôi đã [giới thiệu trong bài trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-4---Event-loop--lap-trinh-bat-dong-bo---5-meo-cai-thien-Async-Await).

Javascript có thể dùng Web Workers nhưng nó rất hạn chế trường hợp. Về cơ bản, bất kỳ tính toán nào ảnh hưởng nặng đến CPU và block luồng xử UI đều có thể được đẩy ra load riêng với WebWorker. Tuy nhiên, WebWorker lại không truy xuất được vào DOM.

WebAssembly hiện tại không hỗ trợ đa luồng. Tuy nhiên, điều này chắc chắn sẽ được thay đổi. Wasm đang tiến gần tới những tiến trình native (ví dụ: luồng kiểu C++). Có những luồng "thực" sẽ tạo ra rất nhiều cơ hội mới trên trình duyệt. Và lẽ dĩ nhiên, nó cũng sẽ bị lạm dụng nhiều hơn.

# Tính di động (Portability)

Ngày nay Javascript có thể chạy ở bất kỳ đâu, từ trình duyệt đến server, kể cả trong các hệ thống nhúng.

WebAssembly được thiết kế để an toàn và linh động. Như Javascript, nó chạy trên nhiều môi trường hỗ trợ wasm (ví dụ: mọi trình duyệt)

WebAssembly có cùng mục tiêu di động như cách mà Java đang cố thực hiện trong những ngày đầu với Applets.

# Khi nào thì dùng WebAssembly tốt hơn JavaScript?

Trong các phiên bản đầu của WebAssembly, chức năng chính chỉ tập trung vào các phép tính nặng tải trên CPU (các bài toán phức tạp chẳng hạn). Ứng dụng chủ yếu nhất khi nghĩ đến là games - có cả hàng tấn pixel cần thao tác xử lý trên màn hình. Bạn có thể viết app bằng ngôn ngữ mà bạn quen thuộc như C++/Rust bằng OpenGL sao đó biên dịch sang wasm và nó sẽ chạy trên trình duyệt.

Bạn có thể xem ví dụ sau (tốt nhất là dùng Firefox): [http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html](http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html). Nó chạy trên nền [Unreal engine](https://www.unrealengine.com/en-US/what-is-unreal-engine-4).

Một trường hợp khác tiêu biểu cho viêc sử dụng WebAssembly (về mặt hiệu năng) là triển khai một số thư viện chạy các tác vụ nặng với CPU, ví dụ như xử lý ảnh.

Như đã nói ở trước, wasm có thể giảm khá nhiều lượng tiêu thụ pin trên các thiết bị di động (phụ thuộc vào engine), bởi vì đa số các bước xử lý đều đã được hoàn thành trước trong khi biên dịch.

Trong tương lai, bạn sẽ có thể sử dụng code WASM nhị phân kể cả khi bạn không thực sự viết code có thể biên dịch ra nó. Bạn có thể tìm vài projects trên NPM đang bắt đầu triển khai theo hướng này.

Với trường hợp thay đổi DOM và sử dụng nhiều platform API thì tốt nhất vẫn là dùng Javascript, bởi vì rõ ràng nó hỗ trợ tốt với các API đó.

Ở [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=Post-6-webassembly-outro), tác giả liên tục mở rộng biên giới hiệu năng của Javascript nhằm viết được nhiều code tối ưu và hiệu quả cao. Giải pháp của họ cần cung cấp hiệu năng nhanh chóng mặt vì không thể gây ảnh hưởng lên hiệu năng của app của khách hàng.

Một khi bạn đã tích hợp SessionStack vào web app của bạn, nó sẽ ghi lại mọi thứ diễn ra trên app/website: những thay đổi trên DOM, tương tác của người dùng, JS exception, stack trace, những request bị fail và cả thông báo debug, cho phép bạn chạy lại (replay) những issue đã xảy ra dưới dạng video và xem chúng diễn ra như thế nào với người dùng. Tất cả đều hoạt động theo thời gian thực (real-time) và không ảnh hưởng đến hiệu năng của webapp. SessionStack phải tối ưu hóa code một cách tối đa và làm cho quá trình này bất đồng bộ nhất có thể.

Không chỉ là một thư viện! Khi bạn chạy lại một session của người dùng trong SessionStack thì nó phải render lại toàn bộ những gì mà trình duyệt của user thực hiện tại thời điểm vấn đề xảy ra và team tác giả phải xây dựng lại toàn bộ trạng thái, cho phép bạn có thể nhảy tới nhảy lui trong timeline session. Để đạt được điều đó, team tác giả đã tận dụng tối đa khả năng bất đồng bộ mà Javascript cung cấp trong khi thiếu sót những giải pháp tốt hơn.

Với WebAssembly, team tác giả có thể đẩy những tiến trình xử lý và render nặng nhất vào một ngôn ngữ phù hợp hơn với công việc này và để phần thu thập dữ liệu, thay đổi DOM cho Javascript làm.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p6-so-sanh-voi-webassembly-mot-so-truong-hop-tot-hon-nen-su-dung</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p6-so-sanh-voi-webassembly-mot-so-truong-hop-tot-hon-nen-su-dung</guid>
            <pubDate>Fri, 16 Nov 2018 07:19:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P5: Hiểu sâu về WebSocket & HTTP/2 với SSE]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 5 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Trong phần này chúng ta sẽ đào sâu với thế giới của những giao thức giao tiếp, ánh xạ (mapping) và thảo luận về những thuộc tính cũng như thành phần của chúng. Chúng ta sẽ đưa ra 1 so sánh nhỏ giữa WebSockets và HTTP/s. Cuối cùng, team SessionStack sẽ chia sẻ một vài ý tưởng về việc lựa chọn phương thức nào cho phù hợp với giao thức mạng.

# Giới thiệu

Ngày nay những webapp phức tạp có nhiều tính năng, UI động xuất hiện như trăm hoa đua nở. Cũng không phải bất ngờ, internet cũng đã phát triển được một quãng đường khá dài kể từ khi bắt đầu.

Ban đầu, internet không được xây dựng để dành cho những app động và phức tạp. Nó được hình thành như là một tập hợp của các trang HTML, kết nối với nhau để cấu thành nên khái niệm về "Web" chứa thông tin. Phần lớn mọi thứ được xây dựng xung quanh mô hình request/response nổi tiếng của HTTP. Một client tải trang và không có gì xảy ra cho đến khi user bắt đầu click và di chuyển đến trang tiếp theo.

Khoảng năm 2005, AJAX được giới thiệu và rất nhiều người đã khám phá khả năng tạo kết nối giữa client và server theo 2 chiều (**bidirectional**). Và vẫn như thế, tất cả giao tiếp HTTP được chỉ đạo bởi client yêu cầu user tương tác hoặc thực hiện theo chu kỳ để lấy dữ liệu mới từ server.

# Tạo một HTTP “2 chiều”

Công nghệ cho phép server gửi dữ liệu về client một cách "chủ động" đã phát triển được 1 thời gian. Push và Comet là ví dụ.

Một trong số mẹo nổi tiếng để tạo ra ảo giác rằng server đang gửi dữ liệu về client được gọi là long polling. Với long polling, client mở kết nối HTTP đến server và giữ nó tiếp tục mở cho đến khi có response trả về. Mỗi khi server có dữ liệu mới cần được gửi, nó chuyển giao thông tin dưới dạng một response.

Cùng xem một ví dụ đơn giản về long polling:

```javascript
(function poll() {
  setTimeout(function () {
    $.ajax({
      url: "https://api.example.com/endpoint",
      success: function (data) {
        // Làm gì đó với `data`
        // ...

        // Cài đặt poll mới theo đệ quy
        poll();
      },
      dataType: "json",
    });
  }, 10000);
})();
```

Đây là một hàm tự thực thi cơ bản chạy một cách tự động lần đầu tiên. Nó sẽ cài đặt một khoảng thời gian 10 giây và sau mỗi lời gọi Ajax bất đồng bộ đến server, callback lại gọi ajax lần nữa.

Vài kỹ thuật khác có thể kể đến như [Flash](http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/Socket.html), request nhiều thành phần XHR và [htmlfiles](http://cometdaily.com/2007/12/27/a-standards-based-approach-to-comet-communication-with-rest/) nổi tiếng.

Tất cả những phương pháp này đều có chung một vấn đề: Chúng qua mặt HTTP, làm cho chúng không phù hợp với những app có độ trễ thấp. Giả sử như game bắn súng nhiều người chơi trên trình duyệt hoặc bất kỳ game onlinen nào có đối thủ thực.

# Giới thiệu WebSockets

Thông số kỹ thuật của WebSocket định nghĩa một kết nối API dạng "socket" (ổ cắm điện!) giữa trình duyệt và server. Theo nghĩa đen thì có 1 kết nối cố định giữa client và server và cả 2 bên có thể gửi dữ liệu bất kỳ lúc nào.

![](https://cdn-images-1.medium.com/max/1000/1*a4lA5FYDkjA9mv53NPKtOg.png)

Client thiết lập một kết nối WebSocket thông qua một tiến trình được gọi là WebSocket handshake (bắt tay WebSocket). Tiến trình này bắt đầu với client gửi một request HTTP thông thường đến server. Nó kèm theo header Upgrade để thông báo cho server rằng client muốn tạo một kết nối WebSocket.

Cùng xem thử quá trình mở kết nối WebSocket như thế nào ở phía client:

```javascript
// Create a new WebSocket with an encrypted connection.
var socket = new WebSocket("ws://websocket.example.com");
```

> WebSocket URL sử dụng ws scheme. Chúng ta còn có cả wss cho những kết nối WebSocket bảo mật hơn, tương tự như HTTPS.

Scheme này bắt đầu một tiến trình mở kết nối WebSocket đến websocket.example.com.

Dưới đây là 1 ví dụ đơn giản của header của request khởi tạo.

```javascript
GET ws://websocket.example.com/ HTTP/1.1
Origin: http://example.com
Connection: Upgrade
Host: websocket.example.com
Upgrade: websocket
```

Nếu server hỗ trợ giao thức WebSocket, nó sẽ đồng ý để nâng cấp và giao tiếp thông qua header Upgrade trong response.

Cùng xem phần thiết lập của nó trong Node.js như thế nào:

```javascript
// Chúng ta sẽ dùng https://github.com/theturtle32/WebSocket-Node
// Triển khai WebSocket
var WebSocketServer = require("websocket").server;
var http = require("http");

var server = http.createServer(function (request, response) {
  // xử lý HTTP request.
});
server.listen(1337, function () {});

// tạo server
wsServer = new WebSocketServer({
  httpServer: server,
});

// WebSocket server
wsServer.on("request", function (request) {
  var connection = request.accept(null, request.origin);

  // Đây là callback quan trọng nhất,chúng ta sẽ
  // xử lý thông tin của client ở đây.
  connection.on("message", function (message) {
    // Xử lý thông tin WebSocket
  });

  connection.on("close", function (connection) {
    // Đóng kết nối
  });
});
```

Sau khi thành lập kết nối, server trả về:

```javascript
HTTP/1.1 101 Switching Protocols
Date: Wed, 25 Oct 2017 10:07:34 GMT
Connection: Upgrade
Upgrade: WebSocket
```

Khi kết nối đã được thiết lập, sự kiện open sẽ được bắn ra cho instance WebSocket ở phía client:

```javascript
var socket = new WebSocket("ws://websocket.example.com");

// Hiện thông báo khi kết nối WebSocket thành công.
socket.onopen = function (event) {
  console.log("WebSocket is connected.");
};
```

Giờ thì quá trình "bắt tay" đã hoàn tất, kết nối khởi tạo HTTP được thay thế bằng WebSocket và sử dụng cùng loại nền tảng kết nối TCP/IP. Tại thời điểm này, cả 2 bên đều có thể gửi dữ liệu.

Với WebSocket, bạn có thể truyền bao nhiêu thông tin tùy thích mà không cần phải gánh chịu những chi phí không đáng có liên quan đến request HTTP truyền thống. Dữ liệu được truyền đi thông qua WebSocket dưới dạng tin nhắn (message), mỗi tin nhắn bao gồm một hoặc nhiều _frame_ chứa dữ liệu bạn gửi đi (gọi là _kiện hàng_ - _payload_). Để đảm bảo message có thể tái cấu trúc một cách chính xác khi nó đến với client, mỗi frame được gán cứng từ 4-12 byte thông tin về payload. Sử dụng hệ thống thông tin dựa trên frame như thế này giúp giảm tải khối lượng dữ liệu dư thừa (non-payload data) phải truyền đi, có thể làm cho độ trễ giảm đi đáng kể.

**Lưu ý**: _Đặc biệt chú ý là client chỉ được thông báo về message mới một khi tất cả frame đều được nhận và payload message gốc được tái cấu trúc đầy đủ_

# WebSocket URLs

Chúng ta có đề cập sơ qua về WebSocket URL scheme ở trên. Trong thực thế, chúng giới thiệu có 2 scheme mới là ws:// và wss://

URL có cấu trúc ngữ pháp cụ thể về scheme. WebSocket URL đặc biệt vì nó không hỗ trợ nhóm ký tự anchor (có dấu thăng ở trước, ví dụ: #đây_là_anchor).

Có những luật chung được áp dụng cho cả style của WebSocket URL và HTTP URL. ws không được mã hóa, nó có cổng mặc định là 80 trong khi đó wss yêu cầu mã hóa TLS và dùng cổng 443 mặc định.

# Framing protocol (Giao thức framing)

Cùng đào sâu một chút về framing protocol với những gì [RFC](https://tools.ietf.org/html/rfc6455) cung cấp:

```javascript
0                   1                   2                     3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len |    Extended payload length    |
|I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
|N|V|V|V|       |S|             |   (if payload len==126/127)   |
| |1|2|3|       |K|             |                               |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|     Extended payload length continued, if payload len == 127  |
+ - - - - - - - - - - - - - - - +-------------------------------+
|                               |Masking-key, if MASK set to 1  |
+-------------------------------+-------------------------------+
| Masking-key (continued)       |          Payload Data         |
+-------------------------------- - - - - - - - - - - - - - - - +
:                     Payload Data continued ...                :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
|                     Payload Data continued ...                |
+---------------------------------------------------------------+
```

Theo như RFC định nghĩ về WebSocket thì nó chỉ có duy nhất một header trước mỗi gói tin, và nó khá phức tạp. Chúng ta cùng tìm hiểu:

- fin (1 bit): biểu thị nếu frame đó là frame cuối cùng tạo nên message. Hầu hết message đều có thể chứa trong một frame duy nhất và bit này luôn có giá trị. Thực nghiệm cho thấy Firefox tạo 1 frame thứ 2 sau mỗi 32K.
- rsv1, rsv2, rsv3 (Mỗi thứ 1 bit): phải bằng 0 trừ khi có một [extension](https://tools.ietf.org/html/rfc6066) (đại khái như tiện ích mở rộng) được trao đổi và nó định nghĩa ý nghĩa cho giá trị khác 0\. Nếu nhận về một giá trị khác 0 và không có extension nào xác định ý nghĩa của giá trị khác 0 đó được trao đổi thì người nhận cuối sẽ bị mất kết nối.
- opcode (4 bit): nó cho biết những gì frame đại diện. Có những giá trị sau đây được dùng:
  - 0x00: frame này tiếp tục payload từ frame trước đó.
  - 0x01: frame này chứa dữ liệu chữ (text).
  - 0x02: frame này chứa dữ liệu nhị phân (binary).
  - 0x08: frame này hủy kết nối.
  - 0x09: frame này là ping.
  - 0x0a: frame này là pong.

(Bạn có thể thấy rằng có nhiều giá trị không sử dụng, chúng được dự trữ cho tương lai khi cần)

- mask (1 bit): biểu thị nếu kết nối đã được che đậy (mask). Rõ ràng là mỗi message từ client đến server _phải được che đậy_ và về mặt kỹ thuật thì nó sẽ hủy kết nối nếu không được che đậy.
- payload_len (7 bit): độ dài của payload. WebSocket frame có những độ dài theo các khoảng tính theo byte như sau:
  - 0-125 biểu thị độ dài của payload
  - Nếu là 126 byte thì 2 byte tiếp theo biểu thị độ dài payload dưới dạng số nguyên 16bit không dấu
  - Nếu là 127 byte thì 8 byte tiếp theo biểu thị độ dài payload dưới dạng số nguyên 64bit không dấu
  - Vậy là độ dài payload sẽ vào khoảng ~7bit, 16bit hoặc 64bit.
- masking-key (32 bit): tất cả frame được gửi từ client đến server sẽ được che đậy (mask) bằng một giá trị 32bit đính kèm trong frame.
- payload: Dữ liệu thật sự cần được che đậy. Độ dài của nó chính là payload_len

Tại sao WebSocket lại dựa trên frame (frame-based) mà không dựa trên dòng chảy (stream-based)? Có trời mới biết, tác giả cũng không biết vì sao nên nếu bạn có thông tin gì về điều này thì có thể nhắn tin đến tác giả. Ngoài ra thì có [một topic thảo luận rất tốt về vấn đề này trên HackerNews](https://news.ycombinator.com/item?id=3377406), bạn có thể tham khảo.

# Dữ liệu trên frame

Như đã nói ở trên, dữ liệu có thể phân mảnh thành nhiều frame. Frame đầu tiên chuyển giao dữ liệu có một opcode biểu thị kiểu dữ liệu đang được truyền. Điều này cần thiết bởi vì Javascript hầu như không có hỗ trợ cho kiểu dữ liệu nhị phân (binary) khi nó được xây dựng. 0x01 biểu thị kiểu encode văn bản UTF-8, 0x02 là dữ liệu nhị phân. Đa số mọi người sẽ chuyển giao JSON trong trường hợp bạn muốn chọn opcode văn bản. Khi bạn phát tín hiệu (emit) dữ liệu nhị phân nó sẽ được thể hiện trên trình duyệt dưới dạng cụ thể là [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob).

API để gửi dữ liệu thông qua WebSocket khá đơn giản:

```javascript
var socket = new WebSocket("ws://websocket.example.com");
socket.onopen = function (event) {
  socket.send("Some message"); // Gửi dữ liệu đến server.
};
```

Khi WebSocket nhận dữ liệu (ở phía client), một sự kiện message được bắn ra. Sự kiện này bao gồm một thuộc tính gọi là data có thể dùng để truy cập nội dung của message.

```javascript
// Xử lý message gửi đi từ server.
socket.onmessage = function (event) {
  var message = event.data;
  console.log(message);
};
```

Bạn có thể khám phá dữ liệu một cách dễ dàng trong mỗi frame trong kết nối WebSocket sử dụng tab Network trong Chrome DevTools:

![](https://cdn-images-1.medium.com/max/1000/1*Sz4wI2ukt91vRrgf8UonWw.png)

# Sự phân mảnh

Dữ liệu payload có thể được chia thành nhiều frame riêng. Nơi nhận có nhiệm vụ lưu đệm chúng cho đến khi bit fin được set. Thế nên bạn có thể chuyển 1 chuỗi "Hello World" trong 11 gói tin của 6 (độ dài header) + 1 byte cho mỗi gói. Sự phân mảnh không được chấp nhận cho gói tin điều khiển (control packages). Tuy nhiên, đặc điểm kỹ thuật muốn bạn có thể xử lý những frame điều khiển xen kẽ nhau. Đó là trường hợp gói tin TCP nhận được có thứ tự lộn xộn.

Logic để kết nối frame được mô tả sơ lược như sau:

- Nhận frame đầu tiên
- Ghi nhớ opcode
- Nối các frame payload lại với nhau cho đến khi bit fin được set.
- Giả định rằng opcode cho mỗi gói tin là 0

Mục đích chính của sự phân mảnh là cho phép gửi message khi không biết rõ kích thước ban đầu của message. Với sự phân mảnh, server có thể chọn một kích thước buffer (bộ đệm) phù hợp và khi buffer đầy thì ghi mảnh (fragment) đó vào network. Trường hợp sử dụng phụ của sự phân mảnh là truyền tin đa luồng (multiplexing), vốn dĩ không cần một message lớn trên một kênh logic để tiếp nhận toàn bộ kênh đầu ra, vì thế multiplexing cần phải giải phóng để cắt message ra thành nhiều mảnh để có thể chia sẻ đến kênh đầu ra tốt hơn.

# Heartbeating (nhịp tim) là gì ?

Tại một thời điểm sau khi "bắt tay" (handshake), cả client và server có thể lựa chọn để gửi đi một ping đến phía kia. Khi ping được nhận, người nhận phải gửi ngược lại một pong ngay khi có thể. Đó gọi là heartbeat (nhịp tim đập). Bạn có thể dùng nó để đảm bảo client vẫn đang được kết nối.

Một ping hay pong chỉ là frame bình thường, không phải frame điều khiển. Ping có opcode là 0x9 và opcode của pong là 0xA. Khi bạn nhận được ping, gửi ngược lại pong với chính xác cùng dữ liệu Payload như ping (với ping và pong thì độ dài payload tối đa là 125). Bạn cũng có thể nhận được pong mà chưa từng gửi ping. Nếu nó xảy ra thì bỏ qua, quên nó đi.

Heartbeat có thể rất có ích. Có nhiều dịch vụ (chẳng hạn như bộ cân bằng tải - load balancer) sẽ hủy những kết nối đứng yên (idle). Thêm nữa, bên nhận không thể biết nếu bên kia (bên gửi) đã bị kết thúc hay chưa. Chỉ có đến lần gửi thông tin tiếp theo ta mới nhận ra có gì đó không ổn.

# Xử lý lỗi

Bạn có thể xử lý bao nhiêu lỗi xảy ra cũng được bằng cách listen đến sự kiện error.
Ví dụ:

```javascript
var socket = new WebSocket("ws://websocket.example.com");

// Xử lý lỗi xảy ra.
socket.onerror = function (error) {
  console.log("WebSocket Error: " + error);
};
```

# Đóng kết nối

Để đóng kết nổi thì client hoặc server phải gửi một frame điều khiển với dữ liệu chứa opcode 0x8. Ngay khi nhận được frame đó thì bên nhận sẽ gửi trả một frame đóng (close). Bên gửi sẽ đóng kết nối. Bất kỳ thông tin nào nhận được sau khi đóng kết nối đều bị vứt bỏ.

Đây là cách bạn khởi tạo quá trình đóng kết nối WebSocket từ client:

```javascript
// Đóng nếu kết nối đang được mở.
if (socket.readyState === WebSocket.OPEN) {
  socket.close();
}
```

Để thực hiện dọn dẹp sau khi đóng kết nối thành công, bạn có thể thêm một event listener vào sự kiện close:

```javascript
// Dọn dẹp những thứ cần thiết.
socket.onclose = function (event) {
  console.log("Disconnected from WebSocket.");
};
```

Server lắng nghe sự kiện close để xử lý nếu cần:

```javascript
connection.on("close", function (reasonCode, description) {
  // Kết nối đang bị đóng.
});
```

# So sánh WebSockets và HTTP/2

Trong khi HTTP/2 cung cấp nhiều thứ, nó lại không hoàn toàn thay thế sự cần thiết cho các công nghệ push/streaming hiện có.

Điều quan trọng đầu tiên về HTTP/2 mà ta cần chú ý là nó không phải là một thay thế cho tất cả HTTP. Những động từ, mã status và đa số các loại header sẽ vẫn như cũ. HTTP/2 hướng đến cải thiện sự hiệu quả trong cách mà dữ liệu truyền trên đường dây.

Giờ nếu so sánh HTTP/2 với WebSocket thì ta có nhiều thứ tương đồng:

|              | HTTP/2                            | WebSocket             |
| ------------ | --------------------------------- | --------------------- |
| Headers      | Được nén (HPACK)                  | Không nén             |
| Binary       | Có                                | Nhị Phân hoặc Văn Bản |
| Multiplexing | Có                                | Có                    |
| Sự ưu tiên   | Có                                | Không                 |
| Nén          | Có                                | Có                    |
| Đinh hướng   | Client/Server hoặc là Server Push | 2 chiều               |
| Full-duplex  | Có                                | Có                    |

Như đã thấy ở trên, HTTP/2 giới thiệu tính năng [Server Push](https://en.wikipedia.org/wiki/Push_technology?oldformat=true) để cho phép server gửi tài nguyên một cách chủ động đến bộ đệm phía client. Tuy nhiên, nó không cho phép tự ý push dữ liệu xuống client. Server push chỉ được xử lý bằng browser và không được bật trong code của ứng dụng, nghĩa là không có API cho app để get thông báo từ những sự kiện như thế này.

Đây là nơi Sự kiện server gửi thông tin (Server-Sent Events - SSE) trở nên rất có ích. SSE là 1 cơ chế cho phép server push dữ liệu bất đồng bộ về client một khi kết nối client-server được thiết lập. Server có thể lựa chọn để gửi dữ liệu khi nào một "cục" dữ liệu mới đã sẵn sàng. Nó có thể được cân nhắc như là mô hình đăng ký-xuất bản ([publish-subscribe](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern)) 1 chiều. Nó cũng cung cấp một chuẩn Javascript client API tên là EventSource được triển khai trong đa số các trình duyệt hiện đại như là 1 phần của tiêu chuẩn HTML5 bởi [W3C](https://www.w3.org/TR/eventsource/). Chú ý rằng trình duyệt không hỗ trợ [EventSource API](http://caniuse.com/#feat=eventsource) cũng có thể dễ dàng polyfill.

Bởi vì SSE dựa trên HTTP, nó có thể phù hợp với HTTP/2 và có thể kết hợp để đạt được sự tốt nhất của cả 2 bên: HTTP/2 xử lý tầng giao vận (transport layer) hiệu quả dựa trên các luồng multiplex và SSE cung cấp API cho app để thực hiện push.

Để hiểu hoàn toàn về Stream và Multiplexing, đầu tiên ta cần biết sơ lược về định nghĩa tại IETF: _một "stream" là chuỗi tuần tự 2 chiều và độc lập của nhiều frame được trao đổi giữa client và server trong một kết nối HTTP/2\. Mộ trong số những đặc tính chính của nó là một kết nối HTTP/2 có thể chứa đồng thời nhiều stream đang mở với frame endpoint xen kẽ từ nhiều stream._

![](https://cdn-images-1.medium.com/max/1000/1*pSh7IORJoUXbwCjyJ7fM9A.png)

Phải nhớ rằng SSE là dựa trên HTTP. Nghĩa là với HTTP/2, không chỉ nhiều stream SSE được xen kẽ trên một kết nối TCP mà cũng cơ chế đó có thể thực hiện với sự kết hợp của nhiều stream SSE (push từ server đến client) và nhiều client request (client đến server). Nhờ ơn HTTP/2 và SSE mà giờ đây chúng ta đã có một kết nối HTTP 2 chiều thuần túy với API đơn giản để code ứng dụng có thể đăng ký cho server push. Thiếu đi khả năng giao tiếp 2 chiều thường được xem như là một bước cải lùi khi so sánh SSE với WebSocket. Cảm ơn HTTP/2, nhờ nó mà điều này không còn là vần đề nữa. Thêm nữa là nó mở ra cơ hội để bỏ qua WebSocket và tập trung vào những công nghệ thay thế dựa trên HTTP.

# Làm thế nào để chọn giữa WebSocket & HTTP/2?

WebSocket chắc chắn sẽ tồn tại trong sự thống trị của HTTP/2 + SSE, chủ yếu bởi vì nó là công nghệ đã được đón nhận và trong nhiều trường hợp cụ thể nó có sự vượt trội so với HTTP/2 như cách nó được xây dựng cho khả năng giao tiếp 2 chiều với ít chi phí tốn kém (ví dụ: headers).

Giả sử bạn muốn xây dựng game MMO (Massive Multiplayer Online: Game nhiều người chơi trực tuyến) cần một lượng khổng lồ message từ cả 2 đầu kết nối. Trong những trường hợp như thế thì WebSocket thể hiện rất rất tốt.

Tổng quát thì sử dụng WebSocket khi nào bạn cần một kết nối với độ trễ rất thấp, gần như là realtime giữa client & server. Nhớ kỹ rằng việc này có thể yêu cầu bạn cân nhắc lại cách xây dựng ứng dụng server-side của bạn, cũng như chuyển sang tập trung vào những công nghệ như event queue.

Nếu trường hợp của bạn cần hiển thị tin tức thị trường, dữ liệu thị trường, ứng dụng chat... theo thời gian thực, sử dụng HTTP/2 + SSE sẽ cung cấp cho bạn kênh giao tiếp 2 chiều hiệu quả trong khi gặt hái nhiều lợi ích khi hoạt động trong thế giới của HTTP:

- WebSocket thường gây ra khó khăn khi cân nhắc sự tương thích với hạ tầng web hiện tại cũng như nó nâng cấp kết nối HTTP đến một giao thức hoàn toàn khác mà không có gì dính dáng tới HTTP.
- Mở rộng và bảo mật: những thành phần của web (firewall, phát hiện xâm nhập, cân bằng tải) được xây dựng, bảo trì và thiết đặt với tư tưởng của HTTP, một môi trường cho ứng dụng lớn và nghiêm ngặt sẽ ưu tiên khả năng phục hồi, bảo vật và khả năng mở rộng.

Bạn cũng cần phải cân nhắc về vấn đề hỗ trợ của trình duyệt:

![](https://cdn-images-1.medium.com/max/1000/1*YFr59cEF2qxzjjleebvbcQ.png)

Khá tốt phải không nào?

Nhưng với HTTP/2 thì không hẳn:

![](https://cdn-images-1.medium.com/max/1000/1*C1VWSKOx89vqdiSiflDRJw.png)

- Chỉ có TLS (Cũng không tệ lắm)
- Hỗ trợ một phần cho IE11 nhưng chỉ trên Windows 10
- Chỉ hỗ trợ OSX 10.11 trở lên trên Safari
- Chỉ hỗ trợ HTTP/2 nếu bạn có thể điều hướng nó qua APLN (server của bạn cũng cần phải hỗ trợ nó rõ ràng)

Hỗ trợ SSE thì tốt hơn một chút:

![](https://cdn-images-1.medium.com/max/1000/1*9ryMUEZhtbTg7lECHVz0fw.png)

Chỉ có IE/Edge là không hỗ trợ (Opera Mini cũng thế). Vẫn có những polyfill khá tốt để giúp chúng ta làm viêc với SSE trên IE/Edge.

# SessionStack lựa chọn như thế nào?

Team SessionStack sử dụng cả 2 WebSocket và HTTP, tùy thuộc vào từng trường hợp. Một khi bạn đã tích hợp SessionStack vào web app của bạn, nó sẽ ghi lại mọi thứ diễn ra trên app/website: những thay đổi trên DOM, tương tác của người dùng, JS exception, stack trace, những request bị fail và cả thông báo debug, cho phép bạn chạy lại (replay) những issue đã xảy ra dưới dạng video và xem chúng diễn ra như thế nào với người dùng. Tất cả đều hoạt động theo thời gian thực (real-time) và không ảnh hưởng đến hiệu năng của webapp.

Điều đó nghĩa là bạn có thể tham gia vào một phiên làm việc của user, trong khi user đang hoạt động trên trình duyệt. Trong trường hợp này, team tác giả chọn sử dụng HTTP bởi vì không cần giao tiếp 2 chiều (server chỉ cần stream dữ liệu đến trình duyệt). Nếu dùng WebSocket ở đây thì sẽ rất tệ, càng khó để bảo trì và mở rộng.

Tuy nhiên, thư viện SessionStack tích hợp vào trong webapp của bạn sử dụng WebSocket (nếu có thể, còn không thì HTTP). Nó sắp xếp và gửi dữ liệu về server và cũng là giao tiếp 1 chiều. Team tác giả chọn WebSocket vì trong trường hợp này vài tính năng cần thiết sử dụng giao tiếp 2 chiều.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p5-hieu-sau-ve-websocket-http-2-voi-sse</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p5-hieu-sau-ve-websocket-http-2-voi-sse</guid>
            <pubDate>Fri, 16 Nov 2018 07:04:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P4: Event loop, lập trình bất đồng bộ & 5 mẹo cải thiện Async/Await]]></title>
            <description><![CDATA[
Chào các bạn đến với bài thứ 4 trong series đục khoét và khám phá Javascript cũng như các thành phần của nó. Trong quá trình xác định và tìm hiểu các thành phần cốt lõi, tác giả cũng chia sẻ một số nguyên tắc mà họ đang dùng để xây dựng SessionStack, một ứng dụng Javascript hướng đến sự mạnh mẽ, hiệu năng cao và ổn định.

Lần này chúng ta sẽ mở rộng những gì có trong bài đầu tiên bằng cách đánh giá những nhược điểm của môi trường đơn luồng (single thread) và làm thế nào để vượt qua chúng nhằm xây dựng những Javascript UI ấn tượng. Và vẫn như cũ, cuối bài viết tác giả sẽ chia sẻ 5 mẹo nhỏ để viết code tốt hơn với async/await.

# Tại sao đơn luồng lại là giới hạn.

Trong bài đầu tiên của series, chúng ta suy ngẫm về câu hỏi điều gì xảy ra khi chúng ta có 1 hàm trong callstack và hàm đó lại ngốn quá nhiều thời gian để thực thi.

Hãy tưởng tượng, ta thực hiện một thuật toán chuyển đổi hình ảnh phức tạp chạy trên browser.

Trong khi callstack đang thực thi các hàm, trình duyệt lại không thể làm gì cả, nó bị kẹt. Nghĩa là trình duyệt không thể vẽ, render, nó không thể chạy code khác, chỉ đơn giản là kẹt. Và vấn đề là ở đây, giao diện (UI) của app bạn sẽ hoạt động không hiệu quả.

App của bạn bị kẹt.

Trong một vài trường hợp thì đây không phải vấn đề nghiêm trọng. Tuy nhiên, có vấn đề còn lớn hơn nữa. Một khi trình duyệt của bạn xử lý quá nhiều thứ trong callstack, nó sẽ bị "đỡ" trong 1 khoảng thời gian dài. Tại thời điểm đó, đa số các browser sẽ chọn giải pháp hiện lỗi, hỏi người dùng có muốn hủy trang hiện tại không.

Điều này thật là xấu xí và ảnh hưởng nghiêm trọng đến trải nghiệm (UX):

![](https://cdn-images-1.medium.com/max/1000/1*MCt4ZC0dMVhJsgo1u6lpYw.jpeg)

# Những thành phần xây dựng nên 1 chương trình JS

Bạn có thể viết toàn bộ code JS trong 1 file .js duy nhất nhưng chương trình của bạn chắc chắn chứa nhiều thành phần nhỏ (gọi là những block), chỉ có một số block sẽ được **thực thi ngay** (gọi là nhóm A) và phần còn lại thì **chạy sau** (nhóm B). Đơn vị block phổ biến nhất là function (hàm).

Vấn đề mà đa số các developer JS mới gặp phải là họ nghĩ rằng nhóm B không cần phải được thực thi một cách nghiêm ngặt ngay sau khi thực thi nhóm A. Nói cách khác, những nhiệm vụ không được hoàn thành ngay bây giờ thì theo lỹ thuyết nó sẽ được hoàn thành một cách bất đồng bộ, nghĩa là bạn sẽ không phải gặp tình huống blocking (bị chặn) như đề cập ở trên

Ví dụ:

```javascript
// Giả sử ajax(..) là một hàm Ajax thuộc thư viện nào đó
var response = ajax("https://example.com/api");

console.log(response);
// `response` sẽ không chứa dữ liệu trả về
```

Chắc bạn cũng nhận thấy rằng những request Ajax như thế này không chạy đồng bộ với nhau, nghĩa là tại thời điểm code thực thi, hàm ajax(...) chưa có dữ liệu trả về để gán vào biến response

Một cách đơn giản cho thường gặp để "chờ" một hàm xử lý bất đồng bộ trả kết quả về đó là sử dụng callback:

```javascript
ajax("https://example.com/api", function (response) {
  console.log(response); // "response" giờ đã có dữ liệu
});
```

Chú ý: Bạn có thể viết những Ajax request đồng bộ, tuy nhiên đừng bao giờ làm thế. Nếu bạn viết Ajax như vậy thì UI sẽ bị block cứng đơ và người dùng sẽ không thể thực hiện các hành động như click, nhập dữ liệu, điều hướng, lăn chuột... Một trải nghiệm kinh khủng.

Đây là cách mà Ajax được viết đồng bộ, nhưng làm ơn, đừng bao giờ sử dụng nó trong app của bạn:

```javascript
// Giả sử bạn đang dùng jQuery
jQuery.ajax({
  url: "https://api.example.com/endpoint",
  success: function (response) {
    // callback ở đây.
  },
  async: false, // Một ý tưởng cực kỳ tồi tệ
});
```

Chúng ta đã sử dụng Ajax request để ví dụ. Ngoài ra bạn có thể dùng bất kỳ đoạn code nào để thực hiện bất đồng bộ.

Dưới đây là ví dụ khác với hàm `setTimeout(callback, milliseconds)`. Cách thức mà hàm setTimeout hoạt động là nó sẽ đặt 1 sự kiện (ở đây là sự kiện timeout) và để nó thực hiện sau:

```javascript
function first() {
  console.log("first");
}
function second() {
  console.log("second");
}
function third() {
  console.log("third");
}
first();
setTimeout(second, 1000); // gọi hàm `second` sau 1000ms
third();
```

Và đây là kết quả của đoạn code trên:

```javascript
first;
third;
second;
```

# Mổ xẻ Event Loop (vòng lặp sự kiện)

Chúng ta sẽ bắt đầu với một chút "kỳ quặc" - mặc dù JS chấp nhận code chạy bất đồng bộ (như trường hợp của setTimeout) thì cho đến khi giới thiệu ES6, JS cũng không thực sự có một khái niệm trực tiếp nào về bất đồng bộ. Bộ engine JS chưa bao giờ làm gì vượt ra khỏi việc thực thi **một** khối lệnh trong chương trình của bạn tại 1 thời điểm cố định.

Bạn có thể xem chi tiết hơn về cách engine JS (cụ thể là Google V8) hoạt động như thế nào ở [bài viết trước](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-2---Ben-trong-engine-V8---5-meo-de-toi-uu-hoa-code).

Vậy thì ai là người ra lệnh cho engine JS phải thực thi những khối lệnh trong chương trình? Trên thực tế, engine JS không chạy cô lập, nó hoạt động bên trong một môi trường chủ (hosting environment), môi trường này đối với đa số các developer chính là trình duyệt web hoặc Node.js. Thực ra, ngày nay, JS đã và đang được nhúng vào rất nhiều loại thiết bị khác nhau, từ robot cho tới bóng đèn. Mỗi một thiết bị có thể xem như là 1 loại khác nhau của môi trường chủ cho engine JS.

Mẫu số chung của tất cả các môi trường đó là một cơ chế tích hợp sẵn được gọi là **event-loop** (vòng lặp sự kiện), nó xử lý quá trình thực thi của nhiều khối lệnh trong chương trình theo thời gian, mỗi lần đều gọi engine JS.

Điều này nghĩa là engine JS chỉ là 1 môi trường thực thi theo yêu cầu cho bất kỳ đoạn code JS tùy ý nào. Nó chỉ là môi trường bao quanh có lịch trình cho các sự kiện (quá trình thực thi code JS).

Ví dụ, khi code JS của bạn gọi Ajax request để lấy dữ liệu từ server, bạn cài đặt một đoạn code _response_ trong một hàm (gọi là callback), và engine JS sẽ truyền đạt lại với môi trường chủ: _Này, tao chuẩn bị tạm ngưng quá trình thực thi ngay bây giờ, nhưng mà khi nào mày xong việc với request đó và có một vài cục dữ liệu thì nhớ gọi lại hàm này nhé._

Trình duyệt sau đó sẽ lắng nghe về response từ mạng, và khi nó có gì đó trả về cho bạn, nó sẽ lên lịch cho hàm callback được thực thi bằng cách chèn nó vào trong event loop

Cùng xem sơ đồ này nào:

![](https://cdn-images-1.medium.com/max/1000/1*FA9NGxNB6-v1oI2qGEtlRQ.png)

Bạn có thể xem lại phần bài viết về Memory Heap & Call Stack trong [bài viết trước đây](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-1---Khai-quat-ve-engine--runtime-va-callstack)

Vậy thì những Web APIs này là gì? Về bản chất, chúng là những tiến trình mà bạn không thể truy xuất (access), bạn chỉ có thể gọi nó. Chúng là những thành phần của trình duyệt mà trong đó cách xử lý đồng bộ được bắt đầu. Nếu bạn là một Node.js developer thì chúng là những C++ APIs.

**Vậy cuối cùng thì event loop là cái éo gì ?**

![](https://cdn-images-1.medium.com/max/1000/1*KGBiAxjeD9JT2j6KDo0zUg.png)

**Event Loop** có một công việc đơn giản: theo dõi Call Stack và Callback Queue (hàng đợi các hàm callback). Nếu Call Stack đang trống, nó sẽ lấy event đầu tiên từ trong hàng đợi ra và đẩy nó vảo trong Call Stack - tức là thực thi nó.

Mỗi vòng lặp như thế được gọi là 1 **tick** trong Event Loop. Mỗi sự kiện chỉ là 1 hàm callback.

```javascript
console.log("Hi");
setTimeout(function cb1() {
  console.log("cb1");
}, 5000);
console.log("Bye");
```

Cùng _thực thi_ đoạn code trên và xem điều gì xảy ra nào:

1.  Trạng thái đang trống, console của trình duyệt đang trống, Call Stack đang trống. ![](https://cdn-images-1.medium.com/max/1000/1*9fbOuFXJHwhqa6ToCc_v2A.png)
2.  `console.log('Hi')` được thêm vào Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*dvrghQCVQIZOfNC27Jrtlw.png)
3.  `console.log('Hi')` được thực thi. ![](https://cdn-images-1.medium.com/max/1000/1*yn9Y4PXNP8XTz6mtCAzDZQ.png)
4.  `console.log('Hi')` bị xóa khỏi Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*iBedryNbqtixYTKviPC1tA.png)
5.  `setTimeout(function cb1() { ... })` được thêm vào Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*HIn-BxIP38X6mF_65snMKg.png)
6.  `setTimeout(function cb1() { ... })` được thực thi. Trình duyệt tạo một timer - vốn là một phần của Web APIs. Nó sẽ thực hiện phần đếm ngược cho bạn. ![](https://cdn-images-1.medium.com/max/1000/1*vd3X2O_qRfqaEpW4AfZM4w.png)
7.  The `setTimeout(function cb1() { ... })` được thực hiện xong và bị xóa khỏi Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*_nYLhoZPKD_HPhpJtQeErA.png)
8.  `console.log('Bye')` được thêm vào Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*1NAeDnEv6DWFewX_C-L8mg.png)
9.  `console.log('Bye')` được thực thi. ![](https://cdn-images-1.medium.com/max/1000/1*UwtM7DmK1BmlBOUUYEopGQ.png)
10. `console.log('Bye')` bị xóa khỏi Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*-vHNuJsJVXvqq5dLHPt7cQ.png)
11. Sau ít nhất 5000ms, timer hoàn thành công việc của nó và đẩy cb1 callback vào trong Callback Queue. ![](https://cdn-images-1.medium.com/max/1000/1*eOj6NVwGI2N78onh6CuCbA.png)
12. Event Loop lấy cb1 từ trong Callback Queue và đưa nó vào trong Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*jQMQ9BEKPycs2wFC233aNg.png)
13. cb1 được thực thi và nó thêm `console.log('cb1')` vào trong Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*hpyVeL1zsaeHaqS7mU4Qfw.png)
14. `console.log('cb1')` được thực thi. ![](https://cdn-images-1.medium.com/max/1000/1*lvOtCg75ObmUTOxIS6anEQ.png)
15. `console.log('cb1')` bị xóa khỏi Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*Jyyot22aRkKMF3LN1bgE-w.png)
16. cb1 bị xóa khỏi Call Stack. ![](https://cdn-images-1.medium.com/max/1000/1*t2Btfb_tBbBxTvyVgKX0Qg.png)

Ảnh gif tổng hợp lại quá trình 16 bước ở trên:
![](https://cdn-images-1.medium.com/max/1000/1*TozSrkk92l8ho6d8JxqF_w.gif)

Thật thú vị khi biết rằng ES6 có mô tả event loop hoạt động như thế nào, nghĩa là về mặt kỹ thuật, nó nằm trong phạm vi trách nghiệm của một JS engine, tức là không còn chỉ đóng vai trò môi trường chủ. Một lý do chính đáng cho sự thay đổi này chính là việc giới thiệu Promise trong ES6 bởi vì promise mới cần truy xuất trực tiếp, kiểm soát tối đa lịch trình điều hành đối với event loop queue (Sau này chúng ta sẽ thảo luận chi tiết hơn)

# setTimeout(…) hoạt động như thế nào?

Điều quan trọng cần phải biết là setTimeout(...) không tự động đặt callback vào trong event loop queue. Nó thiết lập một bộ đếm. Khi bộ đếm kết thúc, môi trường đặt callback vào trong event loop, vì thế những **tick** tiếp theo có thể lấy nó ra và thực thi:

```javascript
setTimeout(myCallback, 1000);
```

Nó không có nghĩa là myCallback sẽ được thực thi sau 1000ms, mà đúng hơn là, trong 1000ms, myCallback sẽ được thêm vào trong queue. Tuy nhiên queue này có thể đang có event khác đã được thêm vào trước đó, và vì thế callback của bạn sẽ phải chờ.

Có một vài bài biết hoặc bài hướng dẫn dành cho người mới bắt đầu với bất đồng bộ trong JS hướng dẫn rằng ta nên setTimeout(callback, 0). Bây giờ bạn đã biết cách event loop làm việc và cách setTimeout hoạt động rồi: gọi setTimeout với thời gian là **0** chỉ vì mục đích hoãn callback lại cho tới khi Call Stack rỗng hoàn toàn.

Hãy xem ví dụ dưới đây:

```javascript
console.log("Hi");
setTimeout(function () {
  console.log("callback");
}, 0);
console.log("Bye");
```

Mặc dù thời gian chờ của callback là _0ms_ nhưng kết quả in ra lại như thế này:

```javascript
Hi;
Bye;
callback;
```

# Jobs (công việc) trong ES6 là gì?

Một khái niệm mới gọi là **Job Queue** (Hàng đợi công việc) được giới thiệu trong ES6\. Nó là lớp trên cùng của event loop queue. Nhiều khả năng bạn sẽ gặp phải nó khi xử lý vấn đề liên quan đến bất đồng bộ của Promise (Chúng ta sẽ nói về nó sau).

Bây giờ thì chúng ta chỉ tìm hiểu về mặt ý tưởng cơ bản để sau này khi thảo luận về bất đồng bộ với Promise, bạn có thể hiểu về những hành động đã được lên lịch và xử lý.

Tưởng tượng nó như thế này: Job queue là 1 queue được gắn vào cuối mỗi tick trong event loop queue. Mỗi hành động bất đồng bộ nhất định khi xảy ra trong 1 tick sẽ không làm cho toàn bộ event được thêm vào event loop queue nhưng thay vì thế sẽ thêm 1 item (tức là job) vào cuối job queue của tick hiện tại.

Điều này nghĩa là bạn có thể thêm những tính năng khác để có thể thực thi sau và bạn có thể chắc chắn rằng nó sẽ được thực thi ngay sau đó, trước bất kỳ đoạn code nào khác.

Một job có thể thêm nhiều job khác vào đoạn cuối của cùng 1 queue. Trên lý thuyết, job có thể lặp (loop) vô thời hạn (một job thực hiện thêm nhiều job khác, v..v...), do đó nó sẽ làm cho chương trình bị quá tải tài nguyên cần thiết để tiếp tục chạy. Về mặt khái niệm thì điều này tương tự như một công việc có thời gian thực thi dài hoặc là một vòng lặp vô hạn (ví dụ: while(true)).

Job cũng giống như trick setTimeout(callback, 0) (set thời gian bằng _0_) nhưng được triển khai theo cách có vẻ như "chính thống" hơn và có sự đảm bảo về thứ tự: thực hiện sau, nhưng phải làm ngay khi có thể.

# Callbacks

Như bạn đã biết, callback là cách phổ biến nhất để thể hiện & quản lý sự bất đồng bộ trong JS. Rõ ràng, callback là mô hình bất đồng bộ cơ bản nhất trong JS. Vô số chương trình JS, kể cả những app tinh vi và phức tạp nhất thì cũng phải dùng tới callback.

Ngoại trừ việc callback không xuất hiện mà không có thiếu sót. Nhiều developer đang cố gắng tìm kiếm những mô hình bất đồng bộ tốt hơn. Tuy nhiên, chúng ta không thể sử dụng bất kỳ phương pháp thay thế nào khác nếu như bạn chưa thực sự hiểu rõ về callback.

Ở chương tiếp theo, chúng ta sẽ khám phá sâu hơn về vấn đề này để tìm hiểu tại sao những mô hình bất đồng bộ tinh vi khác (sẽ nói ở những bài sau) là cần thiết và được đề nghị nên sử dụng.

# Callback lồng nhau (nested callback)

Xem đoạn code dưới đây:

```javascript
listen("click", function (e) {
  setTimeout(function () {
    ajax("https://api.example.com/endpoint", function (text) {
      if (text == "hello") {
        doSomething();
      } else if (text == "world") {
        doSomethingElse();
      }
    });
  }, 500);
});
```

Chúng ta có 3 hàm lồng nhau, mỗi hàm thể hiện 1 bước trong chuỗi bất đồng bộ.

Kiểu code như thế này thường được gọi là **callback hell**. Nhưng _callback hell_ thực sự không phải vấn đề về lồng nhau hay cách dòng, thụt lề. Câu chuyện thực sự sâu xa hơn thế nhiều.

Đầu tiên, chúng ta listen một event _click_, sau đó thì chờ timer hoạt động, rồi cuối cùng là chờ cho Ajax trả kết quả về và quá trình này có thể lặp lại nhiều lần mỗi khi chúng ta click.

Thoạt nhìn đoạn code này thể hiện sự đồng bộ một cách tự nhiên theo thứ tự các bước như sau:

```javascript
listen("click", function (e) {
  // ..
});
```

...rồi sau đó:

```javascript
setTimeout(function () {
  // ..
}, 500);
```

...tiếp theo là:

```javascript
ajax("https://api.example.com/endpoint", function (text) {
  // ..
});
```

...và cuối cùng:

```javascript
if (text == "hello") {
  doSomething();
} else if (text == "world") {
  doSomethingElse();
}
```

Chà, đúng là một cách thể hiện code bất đồng bộ một cách rất tự nhiên, phải không nào? _cười_

# Promises

Cùng xem đoạn code sau:

```javascript
var x = 1;
var y = 2;
console.log(x + y);
```

Rất rõ ràng rằng nó tính tổng của x và y rồi in kết quả ra console. Tuy nhiên, nếu như giá trị của x và y chưa tồn tại và vẫn còn đang chờ để được xác định thì sao? Giả sử chúng ta cần lấy giá trị của x và y từ server trước khi chúng được dùng để tính tổng.
Tưởng tượng rằng chúng ta có một hàm loadX và loadY để thực hiện load dữ liệu cho x và y từ server và một hàm để tính tổng 2 số sau khi chúng được load xong.
Đoạn code sẽ giống như thế này (xấu xí và phức tạp, phải không nào?):

```javascript
function sum(getX, getY, callback) {
  var x, y;
  getX(function (result) {
    x = result;
    if (y !== undefined) {
      callback(x + y);
    }
  });
  getY(function (result) {
    y = result;
    if (x !== undefined) {
      callback(x + y);
    }
  });
}
// Một hàm đồng bộ hoặc bất đồng bộ để get giá trị của "x"
function fetchX() {
  // ..
}

// Một hàm đồng bộ hoặc bất đồng bộ để get giá trị của "y"
function fetchY() {
  // ..
}
sum(fetchX, fetchY, function (result) {
  console.log(result);
});
```

Có một điều quan trọng cần phải nêu lên ở đây: trong đoạn code trên, chúng ta xem x và y như những giá trị tương lai và hàm sum() không quan tâm về việc x hay y hay cả 2 biến có hay không có tồn tại giá trị.

Dĩ nhiên là cách tiếp cận thô dựa trên callback này cho ta nhiều thứ đáng mong đợi. Đây chỉ là 1 bước tiến nhỏ để hiểu về ích lợi của _giá trị tương lai_ mà không cần lo lắng về khía cạnh thời gian khi chúng sẵn có.

# Giá trị của Promise

Cùng xem ví dụ về x + y được thực hiện với Promise:

```javascript
function sum(xPromise, yPromise) {
  // `Promise.all([ .. ])` nhận vào 1 mảng các promise,
  // và trả về 1 promise chờ đợi tất cả chúng hoàn thành
  return (
    Promise.all([xPromise, yPromise])

      // khi một promise được phân giải (resolve),
      // ta lấy giá trị x, y trả về và cộng chúng lại.
      .then(function (values) {
        // `values` là mảng chứa giá trị của các object
        // từ những promise đã được resolve
        return values[0] + values[1];
      })
  );
}

// `fetchX()` và `fetchY()` trả về promise
// chứa kết quả tương ứng, có thể có
// luôn hoặc chờ sau mới có dữ liệu
sum(fetchX(), fetchY())
  // Ta có 1 promise cho tổng của 2 số.
  // Giờ thì gọi mắt xích (chain-call) hàm `.then(...)` để chờ
  // kết quả của promise trả về.
  .then(function (sum) {
    console.log(sum);
  });
```

Có 2 lớp Promise trong đoạn code này.

fetchX() và fetchY() được gọi trực tiếp và giá trị trả về của chúng (**promise!**) được đẩy vào hàm sum(...). Giá trị mà những promise này thể hiện có thể sẵn sàng để dùng ngay lúc gọi hàm hoặc là sau đó 1 chút nhưng bất kể sớm hay muộn thì mỗi promise đều chuẩn hóa hành vi của nó cho giống nhau. Chúng ta suy đoán về giá trị của x và y theo hướng độc lập thời gian. Theo chu kỳ, chúng là những _giá trị tương lai_.

Lớp thứ 2 là promise do hàm sum(...) tạo ra (thông qua Promise.all([ ... ])) và trả về, và cũng chờ nó get giá trị khi gọi .then(...). Khi hàm sum(...) hoàn tất, tổng _giá trị tương lai_ đã sẵn sàng và có thể in nó ra. Chúng ta ẩn phần logic chờ _giá trị tương lai_ của x và y trong hàm `sum(...).

**Lưu ý**: _Bên trong sum(...), lời gọi đến Promise.all([ … ]) tạo một promise (cái này sẽ gọi đến xPromise và yPromise rồi phân giải chúng). Chain-call đến .then() sẽ tạo ra 1 promise khác và promise này sẽ trả về values[0] + values[1] ngay khi resolve (với giá trị kết quả của phép cộng). Do đó lời gọi .then(...) ta đặt ở cuối hàm .sum(...), tức là cuối đoạn code, thực ra là xử lý trên giá trị trả về của promise thứ 2 hơn là promise thứ nhất được tạo ra bởi Promise.all([ ... ]). Mặc dù vậy thì chúng ta không chain-call vào cuối hàm .then(...) sau vì làm vậy sẽ tạo thêm 1 promise và ta lại phải xử lý nó. Phần Promise chain-call này sẽ được giải thích kỹ hơn ở các phần sau trong chương này._

Với Promise, lời gọi .then(...) có thể nhận 2 hàm param, hàm thứ nhất là để thực hiện thao tác với response hoàn thành (như trên), hàm thứ 2 là với trường hợp bị lỗi và bác bỏ (rejection).

```javascript
sum(fetchX(), fetchY()).then(
  // Hàm xử lý hoàn thành
  function (sum) {
    console.log(sum);
  },
  // Hàm xử lý bác bỏ
  function (err) {
    console.error(err); // bummer!
  }
);
```

Nếu có gì đó không đúng trong quá trình get x và y hoặc là có sai sót khác thì promise mà .sum(...) trả về sẽ bị reject, hàm callback thứ 2 xử lý lỗi đã được đẩy vào .then(...) sẽ nhận giá trị reject từ promise.

Bởi vì promise đóng gói trạng thái độc lập thời gian từ bên ngoài - chờ cho giá trị được xử lý hoàn thành/reject, và bản thân promise đã là độc lập thời gian, do đó nhiều promise có thể được kết hợp với nhau theo những cách có thể đoán trước được bất kể là thời gian hay kết quả.

Hơn nữa, một khi promise được resolve thì nó sẽ tồn tại vĩnh viễn: nó trở thành một giá trị **bất biến** tại thời điểm đó, và có thể được lấy ra sử dụng bao nhiêu lần cũng được

Thực sự là rất hữu ích khi ta nối promise thanhf 1 chuỗi:

```javascript
function delay(time) {
  return new Promise(function (resolve, reject) {
    setTimeout(resolve, time);
  });
}

delay(1000)
  .then(function () {
    console.log("after 1000ms");
    return delay(2000);
  })
  .then(function () {
    console.log("after another 2000ms");
  })
  .then(function () {
    console.log("step 4 (next Job)");
    return delay(5000);
  });
// ...
```

Gọi hàm delay(2000) sẽ tạo ra 1 promise mà nó được hoàn thành trong 2000ms, sau đó trả nó về từ hàm hoàn thành trong .then() đầu tiên, điều này làm cho hàm .then(...) thứ hai sẽ chờ 2000ms

**Lưu ý**: _Bởi vì giá promise là bất biến sau khi đã được resolve, chúng ta có thể truyền nó đi khắp nơi mà không cần lo lắng về việc nó bất ngờ bị thay đổi. Điều này đặc biệt có ích khi có nhiều đoạn code cùng sử dụng kết quả của 1 promise. Tính bất biến nghe có vẻ như là một chủ đề liên quan đến học thuật, nhưng thật ra nó là 1 phần rất cơ bản và có khía cạnh quan trọng trong thiết kế promise mà ta không nên bỏ qua._

# Promise hay không Promise ?

Một chi tiết quan trọng về promise là phải biết một giá trị thực sự là promise hay không phải. Nói cách khác, đó có phải là 1 giá trị sẽ hành xử như 1 promise?

Chúng ta biết rằng promise được xây dựng bằng lệnh new Promise(...), và bạn cho rằng p instanceof Promise là đủ để kiểm tra? Thực ra thì không hẳn.

Chủ yếu bởi vì bạn có thể nhận giá trị promise từ một cửa sổ trình duyệt khác (ví dụ: iframe), nó sẽ có promise riêng của nó, khác với promise trong cửa sổ/frame hiện tại của bạn, và câu lệnh check ở trên sẽ fail khi xác định instance của promise.

Hơn nữa, một thư viện hay framework có thể sử dụng promise của riêng nó mà không dùng promise mặc định của ES6\. Thật ra, bạn có thể dùng promise của thư viện trên những trình duyệt cũ không hỗ trợ promise.

# Nuốt chửng ngoại lệ (exception)

Nếu trong quá trình tạo promise hoặc là khi tiếp nhận kết quả từ nó, một lỗi biệt lệ JS xảy ra, ví dụ như TypeError hoặc ReferenceError, exception sẽ được bắt, khi đó nó sẽ ép (force) cho promise đang chạy bị reject.

Ví dụ:

```javascript
var p = new Promise(function (resolve, reject) {
  foo.bar(); // `foo` chưa được định nghĩa, lỗi!
  resolve(374); // Code sẽ không đến được đây :(
});

p.then(
  function fulfilled() {
    // không đến đây luôn :(
  },
  function rejected(err) {
    // `err` sẽ là một object của exception`TypeError`
    // từ dòng `foo.bar()`.
  }
);
```

Nhưng nếu như một promise được hoàn thành nhưng có lỗi exception JS trong quá trình tiếp nhận (ví dụ như trong callback của .then(...) )? Kể cả như thế thì nó cũng không bị mất, bạn sẽ thấy một chút ngạc nhiên khi biết cách mà chúng được xử lý. Đào sâu thêm 1 tí nào:

```javascript
var p = new Promise(function (resolve, reject) {
  resolve(374);
});

p.then(
  function fulfilled(message) {
    foo.bar();
    console.log(message); // không đến được đây nè.
  },
  function rejected(err) {
    // không đến được đây nè.
  }
);
```

Có vẻ như exception từ foo.bar() thực sự đã bị nuốt trôi (swallow). Đúng là như thế. Có gì đó sâu hơn bên trong đã hoạt động sai tuy nhiên chúng ta lại không biết. Lời gọi p.then(...) cho chính nó trả về 1 promise khác và nó sẽ bị reject với ReferenceError exception.

# Xử lý những biệt lệ không bị bắt (Uncaught exception)

Có nhiều cách tiếp cận khác mà nhiều người cho rằng sẽ tốt hơn.

Một đề nghị phổ biến đó là promise nên có thêm một phương thức done(...), nó sẽ đánh dấu chuỗi promise là đã xong (done). .done(...)không tạo ra và trả về một promise vì thế callback truyền qua .done(...) rõ ràng là không liên quan đến việc báo cáo các vấn đề xảy ra với một chuỗi promise không tồn tại.

Nó hoạt động giống như bạn đã biết trong các điều kiện uncaught error: các exception bên trong một hàm reject trong .done(...) sẽ bị bắn ra ngoài developer console dưới dạng global uncaught error.

```javascript
var p = Promise.resolve(374);

p.then(function fulfilled(msg) {
  // Số number không có hàm của string,
  // nên sẽ bắn ra lỗi
  console.log(msg.toLowerCase());
}).done(null, function () {
  // Nếu có uncaught exception ở đây thì nó sẽ bị bắn ra như là một global exception
});
```

# Điều gì xảy ra trong ES8 và Async/await

Javascript ES8 giới thiệu async/await để giúp cho công việc xử lý promise dễ dàng hơn. Chúng ta sẽ lướt sơ qua những khả năng mà async/await cung cấp và xem thử làm thế nào để dùng chúng để viết code bất đồng bộ một cách phù hợp.

Vậy thì đầu tiên là xem thử hoạt động của async/await.

Bạn định nghĩa một hàm bất đồng bộ sử dụng định nghĩa hàm async. Những hàm như vậy sẽ trả về object [AsyncFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AsyncFunction). Object AsyncFunction biểu diễn hàm bất đồng bộ trong đó nó thực thi code bên trong nó.

Khi một hàm async được gọi, nó sẽ trả về Promise. Khi hàm async trả về giá trị, nó lại không phải promise, một promise sẽ được tạo ra tự động và được phân giải (resolve) với giá trị trả về từ hàm. Khi hàm async bắn ra exception, promise sẽ reject với giá trị bắn ra.

Một hàm async có thể chứa thể hiện await, nó sẽ dừng quá trình thực thi của hàm và đợi cho promise giải quyết xong rồi quay lại thực thi tiếp và trả về giá trị đã được resolve.

Bạn có thể xem như promise trong JS tương tự với Java Future hay C# Task.

> Mục đích của async/await là làm đơn giản hóa quá trình sử dụng promise.

Xem ví dụ sau:

```javascript
// Hàm JS bình thường
function getNumber1() {
  return Promise.resolve("374");
}
// Giống như hàm trên
async function getNumber2() {
  return 374;
}
```

Tương tự, những hàm bắn ra exception tương tự với những hàm trả về promise bị reject:

```javascript
function f1() {
  return Promise.reject("Some error");
}
async function f2() {
  throw "Some error";
}
```

Từ khóa await chỉ có thể được dùng bên trong hàm async và cho phép bạn chờ promise một cách đồng bộ. Nếu chúng ta sử dụng promise bên ngoài một hàm async thì phải dùng tới callback:

```javascript
async function loadData() {
  // `rp` là một hàm gọi promise.
  var promise1 = rp("https://api.example.com/endpoint1");
  var promise2 = rp("https://api.example.com/endpoint2");

  // Hiện tại cả 2 request đều được gọi đồng thời và
  // ta phải đợi cho nó hoàn thành.
  var response1 = await promise1;
  var response2 = await promise2;
  return response1 + " " + response2;
}
// Bởi vì ta không ở trong hàm `async`
// nên chúng ta phải dùng `then()`.
loadData().then(() => console.log("Done"));
```

Bạn có thể định nghĩa hàm async bằng cách sử dụng async function expression (AFE - Thể hiện hàm async). Một AFE tương tự và gần giống như một async function statement (AFS). Điểm khác biệt chính giữa AFE và AFS là tên của hàm, trong AFE ta có thể bỏ qua tên để tạo hàm vô danh (anonymous function). Một AFE có thể sử dụng như một IIFE ([Immediately Invoked Function Expression](https://developer.mozilla.org/en-US/docs/Glossary/IIFE)), loại hàm được thực thi ngay sau khi nó được định nghĩa.

Nó trông như thế này:

```javascript
var loadData = async function () {
  // `rp` là một hàm gọi promise.
  var promise1 = rp("https://api.example.com/endpoint1");
  var promise2 = rp("https://api.example.com/endpoint2");

  // Hiện tại cả 2 request đều được gọi đồng thời và
  // ta phải đợi cho nó hoàn thành.
  var response1 = await promise1;
  var response2 = await promise2;
  return response1 + " " + response2;
};
```

Quan trọng là async/await được hỗ trợ và có thể chạy trên đa số các trình duyệt:

[![](https://cdn-images-1.medium.com/max/1000/0*z-A-JIe5OWFtgyd2.)](https://cdn-images-1.medium.com/max/1000/0*z-A-JIe5OWFtgyd2.) <a></a>

Nếu như trình duyệt nào không hỗ trợ thì ta vẫn có thể sử dụng các JS transpiler như [Babel](https://babeljs.io/docs/plugins/transform-async-to-generator/) hay [TypeScript](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-3.html)

Cuối cùng thì điều quan trọng nhất là không nên chọn lựa một cách mù quáng những cách tiếp cận "mới nhất" để viết code bất đồng bộ. Tốt hơn là bạn hiểu về cấu trúc bất đồng bộ của JS, nghiên cứu tại sao nó lại là một vấn đề nghiêm túc và hiểu một cách sâu sắc về các thành phần bên trong của giải pháp mà bạn lựa chọn. Mỗi cách tiếp cận khác nhau đều có những điểm mạnh và điểm yếu, hãy cân nhắc.

# 5 mẹo để viết code bất đồng bộ vừa chắc chắn vừa dễ bảo trì

### 1\. **Clean code (code sạch)**:

Sử dụng async/await cho phép bạn viết code ít hơn nhiều. Mỗi lần sử dụng async/await bạn có thể bỏ qua một số bước không cần thiết, ví dụ: .then(), viết hàm anonymous để xử lý responsive, đặt tên response từ callback...

```javascript
// `rp` là một hàm gọi promise
rp(‘https://api.example.com/endpoint1').then(function(data) {
 // …
});
```

...so với

```javascript
// `rp` là một hàm gọi promise
var response = await rp(‘https://api.example.com/endpoint1');
```

### 2\. **Xử lý lỗi**:

Async/await giúp chúng ta có thể xử lý cả lỗi đồng bộ và bất đồng bộ với cùng một cấu trúc code: chính là try/catch nổi tiếng. Ví dụ:

```javascript
function loadData() {
  try {
    // Catches synchronous errors.
    getJSON()
      .then(function (response) {
        var parsed = JSON.parse(response);
        console.log(parsed);
      })
      .catch(function (e) {
        // Catches asynchronous errors
        console.log(e);
      });
  } catch (e) {
    console.log(e);
  }
}
```

...so với

```javascript
async function loadData() {
  try {
    var data = JSON.parse(await getJSON());
    console.log(data);
  } catch (e) {
    console.log(e);
  }
}
```

### 3\. **Điều kiện**:

Viết code điều kiện với async/await rõ ràng hơn rất nhiều:

```javascript
function loadData() {
  return getJSON().then(function (response) {
    if (response.needsAnotherRequest) {
      return makeAnotherRequest(response).then(function (anotherResponse) {
        console.log(anotherResponse);
        return anotherResponse;
      });
    } else {
      console.log(response);
      return response;
    }
  });
}
```

...so với

```javascript
async function loadData() {
  var response = await getJSON();
  if (response.needsAnotherRequest) {
    var anotherResponse = await makeAnotherRequest(response);
    console.log(anotherResponse);
    return anotherResponse;
  } else {
    console.log(response);
    return response;
  }
}
```

### 4\. **Stack Frames**:

Không giống như async/await, stack lỗi trả về từ một chuỗi promise làm chúng ta không biết lỗi xuất phát từ đâu mà lần:

```javascript
function loadData() {
  return callAPromise()
    .then(callback1)
    .then(callback2)
    .then(callback3)
    .then(() => {
      throw new Error("boom");
    });
}
loadData().catch(function (e) {
  console.log(err);
  // Error: boom at callAPromise.then.then.then.then (index.js:8:13)
});
```

...so với

```javascript
async function loadData() {
  await callAPromise1();
  await callAPromise2();
  await callAPromise3();
  await callAPromise4();
  await callAPromise5();
  throw new Error("boom");
}
loadData().catch(function (e) {
  console.log(err);
  // output
  // Error: boom at loadData (index.js:7:9)
});
```

### 5\. **Quá trình Debug**:

Nếu bạn đã từng sử dụng promise, bạn sẽ biết rằng debug với chúng thực sự là ác mộng. Giả sử bạn đặt breakpoint bên trong .then() và dùng những lệnh debug như stop-over, debugger sẽ không đi đến .then() tiếp theo bởi vì nó "lỡ chân" bước vào code bất đồng bộ.
Với async/await bạn có thể duyệt qua những lời gọi await chính xác như những hàm đồng bộ thông thường.

**Viết code Javascript bất đồng bộ là rất quan trọng không chỉ cho app mà cả cho những thư viện nữa**.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p4-event-loop-lap-trinh-bat-dong-bo-5-meo-cai-thien-async-await</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p4-event-loop-lap-trinh-bat-dong-bo-5-meo-cai-thien-async-await</guid>
            <pubDate>Tue, 13 Nov 2018 23:34:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P3: Quản lý bộ nhớ & 4 trường hợp memory leaks phổ biến]]></title>
            <description><![CDATA[
Mấy hôm trước chúng ta đã bắt đầu series bài viết đục khoét về Javascript và cách nó hoạt động như thế nào, bằng cách hiểu về những thành phần cơ bản và cách chúng tương tác với nhau thì chúng ta có thể viết code tốt hơn và _ngon_ hơn.

Bài đầu tiên là tổng quan về series, cung cấp cái nhìn toàn cảnh về engine, runtime & callstack. Bài thứ 2 là một cái nhìn cụ thể hơn về những thành phần bên trong của bộ engine V8 của Google và một số mẹo vặt để tối ưu Javascript code.

Ở bài thứ 3 này, chúng ta sẽ thảo luận về một vấn đề không kém phần quan trọng nhưng lại thường bị các dev bỏ qua do sự phức tạp ngày càng gia tăng của các ngôn ngữ lập trình thường dùng: quản lý bộ nhớ. Chúng ta cũng sẽ tìm hiểu một số mẹo để có thể xử lý những trường hợp rò rì bộ nhớ của Javascript mà team SesstionStack đã áp dụng để tránh bị rò rỉ và không làm tốn bộ nhớ của webapp.

# Tổng quan

Những ngôn ngữ như C có bộ quản lý bộ nhớ level thấp khá cơ bản là malloc() và free(). Những phương thức này được sử dụng để cấp phát một cách tường minh và giải phóng bộ nhớ trên hệ điều hành.

Một cách tương tự, Javascript cấp phát bộ nhớ khi object, string, ... được tạo ra và _tự động_ giải phóng nó mỗi khi không được sử dụng nữa bởi một tiến trình dọn rác (garbage collection). Quá trình giải phóng tài nguyên một cách _tự động hóa_ như thế này gây ra sự nhầm lẫn và làm cho Javascript (và những ngôn ngữ bậc cao khác) developer cảm thấy "ấn tượng" nên họ thường bỏ qua vấn đề quản lý bộ nhớ. **Đây là một sai lầm lớn.**

Kể cả khi làm việc với ngôn ngữ bậc cao, developer cũng nên hiểu về vấn đề quản lý bộ nhớ (ít nhất là những thứ cơ bản). Thỉnh thoảng có những vấn đề xảy ra với quản lý bộ nhớ tự động (bug hay sự giới hạn thực hiện trong GC...) mà developer cần phần hiểu để có thể xử lý một cách đúng đắn (hoặc tìm cách "đi đường vòng" vượt qua nó với ít thiệt hại nhất).

# Vòng đời của bộ nhớ

Dù cho bạn đang dùng ngôn ngữ lập trình nào đi nữa thì vòng đời bộ nhớ hầu như đều giống nhau:

![](https://cdn-images-1.medium.com/max/1000/1*slxXgq_TO38TgtoKpWa_jQ.png)

Đây là những gì xảy ra ở mỗi bước trong vòng đời:

- **Cấp phát bộ nhớ**: bộ nhớ được cấp phát bởi hệ điều hành và cho phép chương trình sử dụng nó. Ở ngôn ngữ bậc thấp (như C), đây là một quá trình tường minh, rõ ràng mà developer phải xử lý. Trong các ngôn ngữ bậc cao thì phần này ngôn ngữ sẽ làm giúp bạn.

- **Sử dụng bộ nhớ**: Đây là thời điểm khi chương tình của bạn sử dụng những vùng nhớ đã được cấp phát trước đó. Các thao tác Đọc và Ghi được thực hiện khi chúng ta thực thi những biến đã được khai báo trong code.

- **Giải phóng bộ nhớ**: Giờ là lúc giải phóng toàn bộ những vùng nhớ mà bạn không còn dùng đến nữa để sử dụng lại về sau. Giống như phần cấp phát, bước này được thực hiện một cách tường minh trong các ngôn ngữ bậc thấp.

Để hiểu thêm về các khái niệm của callstack và heap thì mời bạn xem lại [Phần 1](https://kipalog.com/posts/Duc-khoet-Javascript--Phan-1---Khai-quat-ve-engine--runtime-va-callstack) của series.

# Bộ nhớ là gì?

Trước khi đi sâu vào bộ nhớ của Javascript, chúng ta sẽ duyệt sơ qua bộ nhớ cơ bản và cách hoạt động của nó.

Ở phần cứng, bộ nhớ máy tính bao gồm một cơ số các [flip flops](https://vi.wikipedia.org/wiki/Flip-flop) (đại khái là 1 trạng thái đóng-mở). Mỗi flip-flop chứa một vài transistor và có thể lưu trữ 1 bit thông tin. Một flip-flop độc lập có thể được truy xuất bằng số định danh duy nhất (**unique identifier**), do đó chúng ta có thể đọc và ghi lên chúng. Và lẽ dĩ nhiên, về mặt ý tưởng chúng ta có thể công nhận rằng toàn bộ bộ nhớ máy tính là 1 mảng khổng lồ các bit có thể đọc & ghi.

Về phần con người thì họ không giỏi làm việc với bit nên tổ chức chúng vào những nhóm lớn hơn, 8 bit thành 1 byte. Ngoài byte còn có word (16 hoặc 32 bit)

Có rất nhiều thứ được lưu trữ trong bộ nhớ:

1.  Tất cả các biến và dữ liệu được sử dụng trong các chương trình.
2.  Code của chương trình chạy, kể cả code của hệ điều hành.

Trình biên dịch và hệ điều hành làm việc với nhau để xử lý hầu như toàn bộ phần quản lý bộ nhớ nhưng chúng tôi khuyến cáo bạn nên có cái nhìn sơ lược về những gì xảy ra ở nội bộ bên trong.

Khi biên dịch code, trình biên dịch sẽ xem xét các kiểu dữ liệu nguyên thủy (string, number, boolean...) và tính toán trước bao nhiêu bộ nhớ mà chúng cần sử dụng. Lượng bộ nhớ cần thiết sau đó sẽ được cấp phát cho chương tình trong không gian callstack. Vùng không gian được cấp phát được gọi là stack space bởi vì khi gọi hàm, bộ nhớ của nó được thêm vào vị trí trên cùng của bộ nhớ hiện tại. Và khi hủy bỏ, chúng bị gỡ bỏ theo quy tắc LIFO (last-in-first-out, vào sau ra trước). Ví dụ:

```javascript
int n; // 4 bytes
int x[4]; // mảng 4 phần tử, mỗi phần tử 4 bytes
double m; // 8 bytes
```

Trình biên dịch sẽ tính toán ngay lập tức đoạn code này cần 4 + 4 \* 4 + 8 = 28 bytes

> Đó là cách hoạt động của kích thước vùng nhớ cho kiểu số integer và double. Khoảng 20 năm trước, integer là 2 byte và double là 4 byte. Code của bạn không phải phụ thuộc vào kích thước của các kiểu dữ liệu cơ bản.

Trình biên dịch sẽ chèn code tương tác với hệ điều hành để yêu cầu số lượng byte cần thiết để lưu trữ các biến.

Trong ví dụ trên, trình biên dịch biết chính xác bao nhiêu bộ nhớ cần thiết cho mỗi biến. Thực tế thì mỗi khi ghi dữ liệu vào biến n, nó sẽ được dịch nội bộ thành mộ thứ đại loại như "địa chỉ vùng nhớ 4127963"

Để ý rằng nếu ta thử truy xuất x[4] thì ta sẽ truy xuất nhầm sang dữ liệu đang liên kết với m. Bởi vì chúng ta đang cố truy xuất vào một phần tử không tồn tại trong mảng: 4 byte này nằm ngoài vùng x[3] vốn là vùng nhớ được cấp phát cuối cùng của mảng (index đánh từ 0 :v), và vậy là có thể ta đọc/ghi nhầm sang các bit của biến m. Điều này có thể gây ra nhiều hậu quả không mong muốn cho toàn bộ chương trình. Xem hình cho rõ hơn nhé:

![](https://cdn-images-1.medium.com/max/1000/1*5aBou4onl1B8xlgwoGTDOg.png)

Khi một hàm gọi một hàm khác thì mỗi hàm sẽ chiếm một phần của stack. Phần đó sẽ lưu giữ tất cả những biến cục bộ cũng như một bộ đếm để ghi nhớ vị trí mà quá trình thực thi của hàm dừng lại. Khi hàm kết thúc thì vùng bộ nhớ lại được giải phóng cho thằng khác dùng.

# Cấp phát động

Thật không may là mọi thứ dường như không dễ như ta tưởng khi mà ta không biết bao nhiêu bộ nhớ 1 biến có thể cần tại thời điểm thực thi. Giả sử chúng ta muốn làm như sau:

```javascript
int n = readInput(); // đọc input từ người dùng
...
// tạo 1 mảng với "n" phần tử
```

Tại thời điểm biên dịch, trình biên dịch không biết mảng sẽ cần bao nhiêu bộ nhớ bởi vì nó được xác định bởi dữ liệu nhập vào từ phía người dùng.

Vì thế nó không thể cấp phát vùng nhớ cho biến trên stack. Thay vì thế, chương trình của chúng ta cần hỏi hệ điều hành về kích thước bộ nhớ phù hợp trong khi thực thi (run-time). Vùng nhớ này được gán từ không gian _heap_. Sự khác biệt giữa cấp phát bộ nhớ động và tĩnh được tổng kết trong bảng sau:

| Cấp phát tĩnh                            | Cấp phát động                       |
| ---------------------------------------- | ----------------------------------- |
| Biết kích thước tại thời điểm biên dịch. | Không biết kích thức lúc biên dịch  |
| Thực hiện lúc biên dịch                  | Thực hiện lúc thực thi (runtime)    |
| Gán vào stack                            | Gán vào heap                        |
| Gán theo thứ tự FILO (first-in-last-out) | Gán không theo thứ tự cụ thể nào cả |

Để có thể có cái nhìn sâu sắc về cấp phát bộ nhớ động, có thể chúng ta cần dành thêm thời gian tìm hiểu về **con trỏ**, nhưng như vậy thì hơi bị lạc đề. Nếu bạn thấy có hứng thú với chủ đề này thì xin lỗi phải hẹn bạn trong 1 bài viết khác rồi.

# Cấp phát trong Javascript

Javascript giúp developer giảm bớt trách nhiệm trong việc cấp phát bộ nhớ. JS tự làm hết mọi thứ.

```javascript
var n = 374; // cấp phát bộ nhớ cho số
var s = "sessionstack"; // cấp phát cho string
var o = {
  a: 1,
  b: null,
}; // cấp phát cho object và các thuộc tính của nó
var a = [1, null, "str"]; // (giống như object) cấp phát cho
// mảng và các giá tị của nó
function f(a) {
  return a + 3;
} // cấp phát cho hàm (là 1 object có thể thực thi)
// function expressions cũng cấp phát object
someElement.addEventListener(
  "click",
  function () {
    someElement.style.backgroundColor = "blue";
  },
  false
);
```

Một vài lời gọi hàm cũng trả về dạng cấp phát object:

```javascript
var d = new Date(); // cấp phát Date object
var e = document.createElement("div"); // cấp phát 1 phần tử DOM
```

Phương thức có thể cấp phát giá trị hoặc object:

```javascript
var s1 = "sessionstack";
var s2 = s1.substr(0, 3); // s2 là 1 string mới
// Bởi vì string là bất biến,
// JavaScript có thể chọn không cấp phát bộ nhớ
// mà lưu trữ phạm vi [0, 3]
var a1 = ["str1", "str2"];
var a2 = ["str3", "str4"];
var a3 = a1.concat(a2);
// mảng mới gồm 4 phần tử là
// sự kết hợp của mảng a1 và a2
```

# Sử dụng bộ nhớ trong Javascript

Sử dụng bộ nhớ đã được cấp phát trong Javascript có thể gói gọn một cách đơn giản trong 2 chữ **đọc/ghi**

Việc này có thể thực hiện bằng cách đọc/ghi giá trị của biến hoặc thuộc tính của object hoặc truyền đối số (argument) vào 1 hàm.

# Giải phóng khi không dùng bộ nhớ nữa

Đa số các phần đề về quản lý bộ nhớ xảy ra ở giai đoạn này.

Công việc khó nhất ở đây là tìm hiểu khi nào bộ nhớ đã được cấp phát có còn được sử dụng hay không. Thường thì nó yêu cầu developer xác định vùng nhớ nào trong chương trình không dùng nữa và giải phóng nó.

Ngôn ngữ bậc cao thêm vào 1 chương tình gọi là bộ dọn rác (garbage collector - GC) thực hiện công việc đi tìm những vùng nhớ đã được cấp phát và tìm hiểu xem nó còn được sử dụng hay không, nếu không dùng nữa thì sẽ tự động giải phóng nó.

Điều hơi chuối là tiến trình này chỉ tương đối đúng, bởi vì vấn đề tổng quát về việc xác định một vùng nhớ có còn được sử dụng hay không là bất khả thi (không thể thực hiện bằng thuật toán).

Đa số GC hoạt động bằng cách thu thập những vùng nhớ không còn bị truy xuất đến, ví dụ: tất cả biến đang trỏ đến nó đều đi ra khỏi phạm vi thực thi. Tuy nhiên, điều này cũng lại không hẳn là chính xác vì tại bất kỳ thời điểm nào một địa chỉ vùng nhớ đều có thể được trỏ tới bởi 1 biến, nhưng biến đó lại không bao giờ được sử dụng nữa.

# Quá trình dọn rác

Rõ ràng cách thức để tìm được vùng nhớ "không còn dùng nữa" là bất khả thi cho nên GC thực hiện một giải pháp hạn chế cho vấn đề chung. Phần này sẽ giải thích những khái niệm cần thiết để bạn có thể hiểu được những thuật toán GC và các giới hạn của chúng.

## Tham chiếu bộ nhớ

Ý tưởng chính của những thuật toán GC dựa trên **tham chiếu**

Trong ngữ cảnh quản lý bộ nhớ, một object A tham chiếu đến object B khác nếu như A có truy xuất đến B (có thể tường minh hoặc không tường minh). Ví dụ: một Javascript object có tham chiếu đến prototype của chính nó (**không tường minh**) và tham chiếu đến giá trị của thuộc tính của nó (**tường minh**).

Trong trường hợp này, khái niệm của 1 "object" được mở rộng thành một thứ gì đó hơn là JS object thông thường và bao trùm cả function scope (hoặc là lexical scope toàn cục).

> Lexical scoping định nghĩa cách mà những tên biến được phân giải trong các hàm lồng nhau: những hàm con chưa scope của hàm cha kể cả khi hàm cha đã được return.

## Bộ đếm tham chiếu

Đây là thuật toán dọn rác đơn giản nhất. Một object được đánh giá là "rác có thể dọn" nếu như không có tham chiếu nào trỏ đến nó.

Ví dụ:

```javascript
var o1 = {
  o2: {
    x: 1,
  },
};
// Tạo 2 object
// 'o1' tham chiếu đến 'o2' vì nó là 1 thuộc tính của 'o1'
// Hiện tại không có rác để dọn.

var o3 = o1; // biến 'o3' đang tham chiếu tới cùng 1 object với 'o1'

o1 = 1; // giờ thì object được tham chiếu trước đó bởi 'o1'
// chỉ còn lại 1 tham chiếu duy nhất là 'o3'

var o4 = o3.o2; // tham chiếu đến thuộc tính 'o2'
// object này giờ có 2 tham chiếu:
// một là thuộc tính của 'o3': o3.o2
// hai là biến 'o4'

o3 = "374"; // Giờ thì object trước đây là của o1 không còn tham chiếu nữa.
// Nó có thể bị dọn dẹp bởi GC
// Tuy nhiên thuộc tính 'o2' của nó thì vẫn còn
// được tham chiếu bởi biến 'o4' nên chưa bị dọn

o4 = null; // thuộc tính 'o2' trước đây trong 'o1' giờ
// đã không còn gì tham chiếu đến nó
// lần này thì GC có thể dọn nó được rồi.
```

## Vấn đề từ tham chiếu vòng tròn

Có một số giới hạn liên quan đến tham chiếu vòng tròn. Trong ví dụ sau, 2 object được tạo ra và được tham chiếu lẫn nhau, tạo thành 1 vòng tròn. Chúng sẽ được đẩy ra ngoài scope sau khi hàm kết thúc nên về mặt lý thuyết thì chúng vô dụng và có thể được giải phóng. Tuy nhiên, thuật toán đếm tham chiếu xem xét rằng mỗi object đều đang có ít nhất 1 tham chiếu đến object đó nên thuật toán sẽ bỏ qua mà không dọn dẹp.

```javascript
function f() {
  var o1 = {};
  var o2 = {};
  o1.p = o2; // o1 tham chiếu đến o2
  o2.p = o1; // o2 tham chiếu đến o1\.
  // 2 thanh niên này tạo thành 1 vòng tròn tham chiếu.
}

f();
```

![](https://cdn-images-1.medium.com/max/1000/1*GF3p99CQPZkX3UkgyVKSHw.png)

## Thuật toán Đánh dấu và dọn dẹp (Mark-and-sweep)

Để xác định xem object có còn cần thiết không thì thuật toán này thử xem object đó có thể truy cập tới hay không.

Thuật toán **Mark-and-sweep** có 3 bước:

1.  **Roots**: Nhìn chung, _roots_ là những biến toàn cục (global) được tham chiếu đến trong code. Với Javascript, một biến toàn cục có vai trò như 1 _root_ chính là object **window**. Trong Node.js thì nó gọi là **global**. Danh sách hoàn chỉnh các _roots_ được xây dựng bởi GC.
2.  Thuật toán sẽ điều tra tất cả các _roots_ và con cháu (children) của nó rồi đánh dấu chúng là đang hoạt động (active) (nghĩa là, chúng không phải rác). Thứ gì mà không phải con cháu của root, root không truy xuất đến được thì đều bị coi là _rác_.
3.  Cuối cùng, GC sẽ giải phóng các vùng nhớ không được đánh dấu _active_ và trả bộ nhớ lại cho hệ điều hành.

![](https://cdn-images-1.medium.com/max/1000/1*WVtok3BV0NgU95mpxk9CNg.gif)

Thuật toán này tốt hơn thuật toán trước vì "đối tượng không có tham chiếu" dẫn tới trường hợp đối tượng không thể truy cập, ở hướng ngược lại thì nó giải quyết được vấn đề của tham chiếu vòng tròn.

Năm 2012, tất cả trình duyệt hiện đại đều tích hợp sẵn bộ GC Mark-and-sweep. Những cải tiến dành cho bộ Javascript GC (như GC Thế hệ (Generational)/ Gia tăng (Incremental)/ Đồng thời (Concurrent)/ Song song (Parallel)) trong những năm gần đây đều là những nâng cấp của thuật toán Mark-and-sweep, nhưng không phải là cải tiến thuật toán GC, cũng không phải quyết định xem 1 object có thể truy cập được hay là không.

[Trong bài viết này](https://en.wikipedia.org/wiki/Tracing_garbage_collection), bạn có thể tìm hiểu chi tiết hơn về quá trình truy tìm rác, nó cũng bao gồm luôn cả thuật toán Mark-and-sweep và cách tối ưu hóa của nó.

## Tham chiếu vòng tròn chỉ là muỗi

Trong ví dụ đầu tiên, sau khi hàm được trả về, 2 object đều không được tham chiếu đến bởi một object có thể truy cập được từ đối tượng toàn cục. Một lẽ dĩ nhiên, thì chúng sẽ bị GC đánh dấu và dọn sạch sẽ.

![](https://cdn-images-1.medium.com/max/1000/1*FbbOG9mcqWZtNajjDO6SaA.png)

Mặc dù giữa 2 object đều có tham chiếu lẫn nhau nhưng chúng không thể truy cập được từ _root_

## Hành vi phản trực quan của GC

Mặc dù GC rất tiện lợi nhưng chúng cũng đi kèm với những khuyết điểm. Một trong số đó là sự _không xác định được_. Nói cách khác, GC là không thể đoán trước được. Ta không thể biết rõ khi nào thì GC được thực thi. Có nghĩa là trong một vài trường hợp chương trình sử dụng nhiều bộ nhớ hơn số lượng mà chúng cần. Trong trường hợp khác, những thời điểm tạm dừng ngắn hạn (short-pauses) có thể đáng được chú ý trong một số ứng dụng đặc biệt nhạy cảm.
Mặc dù _không xác định được_ nghĩa là không biết khi nào GC sẽ chạy, đa số GC đều dùng chung một mô hình thu thập trong quá trình cấp phát. Nếu như cấp phát không chạy, hầu như GC cũng không chạy. Cần cân nhắc trường hợp sau:

1.  Cấp phát một số lược bộ nhớ lớn.
2.  Đa số các phần tử này (hoặc toàn bộ) đều được đánh dấu là không thể truy cập (Giả sử chúng ta vô hiệu hóa một tham chiếu đang trỏ đến bộ nhớ cache mà chúng ta không cần nữa.)
3.  Không có cấp phát nào được thực thi nữa.

Trong trường hợp này, đa số các GC sẽ không chạy bất kỳ một thu gom nào. Nói cách khác, mặc dù có những tham chiếu không thể truy cập được đang tồn tại nhưng chúng lại không được GC "để mắt" đến. Đây không phải là một loại rò rỉ nghiêm trọng nhưng dĩ nhiên nó vẫn sử dụng bộ nhớ nhiều hơn bình thường.

# Rò rỉ bộ nhớ là gì ?

Nếu bạn đọc hết những phần ở trên thì cũng dễ hiểu thôi, rò rỉ bộ nhớ là những vùng nhớ được cấp phát và sử dụng trong chương trình nhưng sau đó, khi không còn dùng nữa, chúng vẫn không được giải phóng và trả về cho hệ điều hành hoặc là kho chứa bộ nhớ.

![](https://cdn-images-1.medium.com/max/1000/1*0B-dAUOH7NrcCDP6GhKHQw.jpeg)

Các ngôn ngữ lập trình có nhiều cách khác nhau để quản lý bộ nhớ. Tuy nhiên, một vùng nhớ cụ thể được dùng hay không thực sự là [vấn đề khó đoán](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#Release_when_the_memory_is_not_needed_anymore). Nói cách khác, chỉ có developer mới biết khi nào thì một vùng nhớ nên được giải phóng và trả lại cho hệ điều hành.

Những ngôn ngữ lập trình cung cấp các tính năng giúp developer làm việc này. Trong khi một số ngôn ngữ khác muốn developer hiểu tường tận về việc khi nào thì 1 vùng nhớ không được sử dụng nữa. Wikipedia có bài viết hay về việc quản lý bộ nhớ [tự động](https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29) và [bằng tay](https://en.wikipedia.org/wiki/Manual_memory_management), bạn có thể xem qua.

## 4 loại rò rỉ phổ biến trong Javascript

### 1\. Biến toàn cục

Javascript xử lý những biến không được khai báo một cách khá thú vị: khi một biến không được khai báo được tham chiếu đến thì một biến mới sẽ được tạo ra trong object toàn cục (global). Trên trình duyệt thì tên của nó là **window**, nghĩa là đoạn này

```javascript
function foo(arg) {
  bar = "some text";
}
```

...tương đương với

```javascript
function foo(arg) {
  window.bar = "some text";
}
```

Giả sử mục đích của bar chỉ để tham chiếu đến 1 biến trong hàm foo thì một biến toàn cục dư thừa lúc này đã được tạo ra bởi vì ta định nghĩa bar mà không dùng var. Ở ví dụ trên, nó không gây ra nhiều tổn hại, nhưng dĩ nhiên bạn có thể tưởng tượng ra bối cảnh đáng lo ngại hơn nhiều. Ví dụ như gán 1 object phức tạp trong bar chẳng hạn.

Thỉnh thoảng bạn cũng có thể vô tình tạo biến toàn cục bằng this:

```javascript
function foo() {
  this.var1 = "potential accidental global";
}
// trong hàm foo() ở đây thì "this" đang trỏ tới biến toàn cục
foo();
```

Bạn có thể tránh trường hợp đáng tiếc này bằng cách thêm dòng use strict vào đầu file Javascript, nó sẽ, nói nôm na, là bật chế độ "nghiêm túc" lên khi phân tích cú pháp (parse) code JS và sẽ ngăn chặn trường hợp vô tình tạo biến toàn cục.

Những biến toàn cục ngoài dự tính như trên rõ ràng là 1 vấn đề, tuy nhiên, thường thì code của bạn sẽ bị "nhiễm độc" bởi những biến toàn cục tường minh mà những biến đó lại không thể thu thập bởi GC. Đặc biệt chú ý đến các biến toàn cục thường được dùng để lưu trữ tạm thời và xử lý 1 số lượng lớn thông tin. Sử dụng biến toàn cục để lưu trữ dữ liệu nếu bạn **phải** làm thế, nhưng nhớ kỹ là gán nó bằng null hoặc gán lại 1 giá trị khác khi đã xong việc với nó.

### 2\. Timers hoặc callbacks bị bỏ quên

Lần này ta lấy setInterval làm ví dụ vì nó thường được dùng trong JS.

Những thư viện có dùng callback cung cấp observer và các công cụ tương tự thường đảm bảo tham chiếu đến callback sẽ không thể truy cập được một khi instance của nó không thể truy cập được. Ví dụ dưới đây không phải hiếm:

```javascript
var serverData = loadData();
setInterval(function () {
  var renderer = document.getElementById("renderer");
  if (renderer) {
    renderer.innerHTML = JSON.stringify(serverData);
  }
}, 5000); // hàm sẽ được thực thi sau mỗi 5 giây.
```

Đoạn code trên cho thấy hậu quả của việc sử dụng timer có tham chiếu đến node hay dữ liệu cũ, không còn dùng nữa.

Object renderer có thể được thay thế hoặc gỡ bỏ ở đâu đó trong quá trình thực thi, điều này làm cho hàm callback trong setInterval trở nên thừa thãi. Nếu điều này xảy ra, dù cho callback hay những thứ bên trong có đủ điều kiện để được dọn dẹp thì trước hết cái interval đó phải dừng lại trước đã (bỏi vì nó vẫn đang hoạt động mà). Dĩ nhiên nếu như serverData đang chứa hay đang xử lý cả 1 đống dữ liệu thì cũng không thể bị thu dọn được.

Khi sử dụng observer, bạn cần đảm bảo phải có một câu lệnh tường minh để gỡ bỏ chúng mỗi khi xong việc (Dù là observer đó không cần dùng nữa hay object không thể truy cập được).

May mắn thay, đa số các trình duyệt hiện đại đều làm giúp bạn việc đó rồi: chúng sẽ tự động thu thập các observer mỗi khi object trong đó trở nên không thể truy cập được kể cả nếu như bạn quên gỡ các listener. Trước đây, một số trình duyệt không làm được điều này (IE6 chẳng hạn).

Nhưng cách tốt nhất vẫn là gỡ bỏ observer khi đã xong việc với nó. Bạn xem ví dụ dưới đây:

```javascript
var element = document.getElementById("launch-button");
var counter = 0;
function onClick(event) {
  counter++;
  element.innerHtml = "text " + counter;
}
element.addEventListener("click", onClick);
// Do stuff
element.removeEventListener("click", onClick);
element.parentNode.removeChild(element);
// Giờ thì "element" đã được đưa ra khỏi phạm vi thực thi,
// Cả "element" và "onClick" sẽ được dọn dẹp kể cả trên các trình duyệt cũ
```

Bạn không càn phải gọi hàm removeEventListener trước khi làm cho node không thể truy cập được vì các trình duyệt hiện đại hỗ trợ GC có thể tự động xác định và xử lý chúng một cách thích hợp.

Nếu bạn dùng jQuery APIs (có nhiều thư viện và frameworks khác cũng hỗ trợ), bạn cũng có thể gỡ bỏ các listener trước khi node bị đưa vào "dĩ vãng" và không dùng nữa. Những thư viện cũng đảm bảo không có rò rỉ bộ nhớ kể cả khi ứng dụng của bạn chạy trên những trình duyệt cũ.

### 3\. [Closures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures)

Một phần quan trọng của Javascript chính là closure: một hàm con có thể truy xuất đến biến của hàm bên ngoài nó. Trong quá tình triển khai chi tiết môi trường thực thi (runtime) của JS thì có thể xảy ra tình trạng rò rỉ bộ nhớ với closure như sau:

```javascript
var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing)
      // một tham chiếu đến 'originalThing'
      console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join("*"),
    someMethod: function () {
      console.log("message");
    },
  };
};
setInterval(replaceThing, 1000);
```

Một khi replaceThing được gọi, theThing sẽ trở thành một object mới chứa 1 mảng rất lớn và 1 closure someMethod. Tuy nhiên, originalThing được tham chiếu bởi 1 closure mà nó lại nằm trong biến unused (chính là biến theThing từ lời gọi đến replaceThing trước đó). Nhớ rằng ở đây một khi **phạm vi (scope) của closure được tạo ra cho closure trong cùng parent scope thì scope đó được dùng chung**.

Trong trường hợp này, scope tạo ra cho closure someMethod được chia sẻ với unused. unused có tham chiếu đến originalThing. Mặc dù unused không bao giờ được dùng, someMehod có thể được sử dụng thông qua theThing bên ngoài scope của replaceThing (ví dụ: ở 1 nơi toàn cục nào đó). Và khi someMethod chia sẻ closure với unused, tham chiếu đến originalThing trong unused ép nó phải ở trong trạng thái hoạt động (toàn bộ scope chia sẻ giữa 2 closure). Điều này ngăn chặn GC hoạt động.

Trong ví dụ trên, scope được tạo ra cho closure someMethod được chia sẻ với unused, trong khi unused tham chiếu tới originalThing. someMethod có thể được gọi thông qua theThing bên ngoài scope của replaceThing, mặc dù sự thật là unused không bao giờ được sử dụng. Rõ ràng unused tham chiếu đến originalThing yêu cầu nó phải giữ trạng thái đang hoạt động bởi vì someMethod chia sẻ closure scope với unused.

Tất cả những điều này có thể làm bộ nhớ bị rò rỉ đáng kể. Bạn có thể thấy biểu đồ sử dụng bộ nhớ dâng lên cao ngất khi đoạn code trên bị lặp đi lặp lại. Kích thước của nó không bị giảm đi khi GC hoạt động. Một danh sách liên kết các closure được tạo ra (root của nó là theThing) và mỗi closure scope lại chưa một tham chiếu gián tiếp tới mảng khổng lồ.

Vấn đề này được tìm thấy bởi Meteor team và họ có [1 bài viết cụ thể mô tả về nó ở đây](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156).

### 4\. Tham chiếu ngoài DOM

Có những trường hợp mà developer lưu trữ DOM node bên trong cấu trúc dữ liệu. Giả sử bạn muốn cập nhật một cách nhanh chóng dữ liệu của nhiều row trong 1 table. Nếu bạn lưu tham chiếu đến mỗi DOM row trong 1 dictionary hay mảng, sẽ có 2 tham chiếu đến cùng 1 phần tử DOM: 1 là từ cây DOME, và 1 là từ dictionary. Nếu bạn chọn lựa xóa bỏ những row này, bạn cũng phải nhớ làm cho 2 tham chiếu trên không thể truy cập được.

```javascript
var elements = {
  button: document.getElementById("button"),
  image: document.getElementById("image"),
};
function doStuff() {
  elements.image.src = "http://example.com/image_name.png";
}
function removeImage() {
  // Cái ảnh là 1 node con trực tiếp của body
  document.body.removeChild(document.getElementById("image"));
  // Ở thời điểm này ta vẫn có 1 tham chiếu đến #button trong
  // biến toàn cục "element". Nói cách khác, "button" vẫn còn nằm
  // trong bộ nhớ và GC không thể dọn dẹp nó được.
}
```

Cần phải xem xét kỹ lưỡng khi tham chiếu đến node con hay node lá bên trong cây DOME. Nếu bạn giữ tham chiếu đến 1 table cell (thẻ `<td>`) trong code và chọn xóa table khỏi DOM tuy nhiên vẫn giữ tham chiếu đến cell đó, bạn có thể sẽ phải đối mặt với 1 vụ rò rỉ lớn. Bạn nghĩ rằng GC sẽ giải phóng tất cả mọi thứ ngoại trừ cell đó. Tuy nhiên, điều này không dễ dàng như vậy. Bởi vì cell là 1 node con của table và những node con thì có tham chiếu đến parent của chúng, vì thế 1 tham chiếu đến 1 cell có thể giữ cả 1 table lớn trong bộ nhớ.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p3-quan-ly-bo-nho-4-truong-hop-memory-leaks-pho-bien</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p3-quan-ly-bo-nho-4-truong-hop-memory-leaks-pho-bien</guid>
            <pubDate>Tue, 13 Nov 2018 23:03:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P2: Bên trong engine V8 & 5 mẹo để tối ưu hóa code]]></title>
            <description><![CDATA[
Hôm trước chúng ta đã có bài bắt đầu một chuỗi series đào sâu nghiên cứu về Javascript và cách thức nó hoạt động: Chúng tôi nghĩ rằng, bằng cách hiểu được những thành phần của JS và cách chúng tương tác với nhau thì chúng ta có thể viết code tốt hơn và _ngon_ hơn

Bài đầu tiên của series đã cho chúng ta có một cái nhìn tổng quan về engine, runtime và callstack. Trong bài thứ 2 này, chúng ta sẽ _đục khoét_ vào những thành phần bên trong của bộ engine V8 của Google. Tác giả cũng sẽ cung cấp một số mẹo vặt để có thể viết code Javascript tốt hơn - những thứ tốt nhất (best practices) mà team SessionStack đã và đang thực hiện để xây dựng những sản phẩm của họ.

# Tổng quan

Javascript engine là một trình thông dịch thực thi mã Javascript. Một JS engine có thể được triển khai thực hiện như là 1 trình thông dịch độc lập, hoặc là một trình biên dịch tức thời (Just-In-Time Compiler) mà nó sẽ biên dịch code Javascript thành bytecode (chưa phải mã máy, nhưng gần như là mã máy).

Dưới đây là danh sách các dự án phổ biến đã triển khai cho Javascript engine:

- [V8](https://en.wikipedia.org/wiki/V8_%28JavaScript_engine%29) - Nguồn mở, phát triển bởi Google trên nền C++
- [Rhino](https://en.wikipedia.org/wiki/Rhino_%28JavaScript_engine%29) - Được quản lý bởi quỹ Mozilla Foundation, nguồn mở, phát triển hoàn toàn bằng Java
- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey_%28JavaScript_engine%29) - Bộ JS engine đầu tiên, ngày xưa được hỗ trợ bởi Netscape Navigator, ngày nay là Firefox
- [JavaScriptCore](https://en.wikipedia.org/wiki/JavaScriptCore) - nguồn mở, còn được gọi là Nitro, được phát triển bởi Apple cho Safari
- [KJS](https://en.wikipedia.org/wiki/KJS_%28KDE%29) - Engine của KDE, phát triển bởi Harri Porten cho dự án trình duyệt Konqueror của KDE
- [Chakra (JScript9)](https://en.wikipedia.org/wiki/Chakra_%28JScript_engine%29) - Internet Explorer
- [Chakra (JavaScript)](https://en.wikipedia.org/wiki/Chakra_%28JavaScript_engine%29) -  Microsoft Edge
- [Nashorn](https://en.wikipedia.org/wiki/Nashorn_%28JavaScript_engine%29) - Nguồn mở và là 1 phần của OpenJDK, viết bằng Java bởi Oracle và Tool Group
- [JerryScript](https://en.wikipedia.org/wiki/JerryScript) - là 1 bộ engine nhẹ dành cho Vạn vật kết nối (Internet of Things)

# Tại sao V8 được tạo ra?

_Hỏi vớ vẩn_

V8 engine được xây dựng bởi Google bằng C++ và nó là phần mềm nguồn mở. Bộ engine này được dùng trong trình duyệt Google Chrome. Không giống như các engine khác, V8 còn được sử dụng trong môi trường runtime của Node.js

![](https://cdn-images-1.medium.com/max/1000/1*AKKvE3QmN_ZQmEzSj16oXg.png)

V8 đầu tiên được thiết kế nhằm gia tăng hiệu suất của tiến trình thực thi JavaScript bên trong trình duyệt. Để có thể đạt được tốc độ tốt, V8 dịch mã Javascript thành mã máy thay vì sử dụng trình thông dịch. Nó biên dịch mã JS thành mã máy ngay khi thực thi bằng bộ JIT compiler (Just-In-Time compiler) giống như đa số các JS engine hiện đại khác như SpiderMoney hay Rhino. Điểm khác biệt chính đó là V8 không sinh ra bytecode hay mã trung gian.

# V8 sử dụng 2 trình biên dịch

Trước khi phát hành phiên bản 5.9 (đầu năm 2017), engine V8 sử dụng 2 trình biên dịch:

- **full-codegen** - một trình biên dịch vừa đơn giản vừa cực nhanh, sinh mã máy đơn giản và tương đối chậm
- **Crankshaft** - một trình biên dịch tối ưu có hơi phức tạp (Just-In-Time) sinh mã đã được tối ưu tốt nhất.

V8 engine còn sử dụng nhiều tiến trình nội bộ khác:

- Tiến trình chính thực hiện những gì bạn thường thấy: lấy code, biên dịch và thực thi nó.
- Có một tiến trình riêng khác cho việc biên dịch, bằng cách này thì trong khi tiến trình chính biên dịch, tiến trình phụ tối ưu (optimize) code.
- Một tiến trình Profiler (không biết dịch) sẽ thông báo cho runtime những phương thức nào đang chiếm dụng nhiều thời gian xử lý để cho Crankshaft có thể tối ưu chúng.
- Một vài tiến trình khác để xử lý dọn rác (Garbage Collector)

Khi lần đầu thực thi mã Javascript, V8 engine sẽ gọi **full-codegen** để dịch trực tiếp những đoạn code JS đã được phân tích thành mã máy mà không thông qua bước chuyển đổi (transformation). Điều này cho phép thực thi mã máy rất nhanh. Để ý rằng V8 không sử dụng bytecode trung gian, cho thấy rằng cách làm này loại bỏ sự không cần thiết của 1 trình thông dịch.

Khi code đã chạy được một thời gian thì tiến trình profiler đã thu thập đủ dữ liệu để có thể xác định phương thức nào cần được tối ưu hóa.

Ở bước tiếp theo, **Crankshaft** sẽ bắt đầu 1 tiến trình khác. Nó dịch cây cú pháp trừu tượng (Abstract Syntax Tree - AST, sẽ có 1 bài riêng để nói về cái này nhé) của Javascript thành một dạng cấp độ cao của _static single assignment_ (SSA - vốn ngôn ngữ có hạn nên không biết dịch), còn được gọi là _Hydrogen_, và cố gắng tối ưu đồ thị Hydrogen đó. Đa số sự tối ưu hóa được hoàn thành là giai đoạn này.

# Inlining (Nội tuyến)

Bước tối ưu hóa đầu tiên là triển khai nội tuyến ([Inlining](https://vi.wikipedia.org/wiki/H%C3%A0m_n%E1%BB%99i_tuy%E1%BA%BFn)) nhiều code nhất có thể. Inlining là tiến trình thay thế một vị trí gọi (call site - dòng code nơi hàm được gọi) với thân (body) của hàm được gọi. Bước thực hiện đơn giản này cho phép những tối ưu hóa sau này được ý nghĩa hơn.

![](https://cdn-images-1.medium.com/max/1000/0*RRgTDdRfLGEhuR7U.png)

# Lớp ẩn (Hidden class)

Javascript là ngôn ngữ dựa trên các nguyên mẫu (prototype-based): không có các lớp (class) hay đối tượng (object) nào được tạo ra bằng tiến trình nhân bản (cloning process). Javascript cũng là ngôn ngữ động (dynamic), nghĩa là những thuộc tính (property) có thể được dễ dàng thêm vào hoặc xóa đi từ object sau khi object đó được khởi tạo.

Đa số các trình thông dịch JS sử dụng cấu trúc dạng như từ điển ([hash function based](http://en.wikipedia.org/wiki/Hash_function)) để lưu trữ vị trí của những giá trị của thuộc tính trong object trên bộ nhớ. Cấu trúc này làm cho quá trình lấy giá trị (get) trong JS trở nên tốn kém hơn nhiều so với những ngôn ngữ lập trình non-dynamic khác như Java hay C#.
Trong Java, tất cả các thuộc tính của object được xác định bởi cấu trúc object cố định trước khi biên dịch và không thể thêm hay bớt thuộc tính tại thời điểm thực thi (C# cũng có kiểu dynamic, nhưng cái đó hơi lạc đề rồi nên mình không đề cập).
Kết quả là, giá trị của thuộc tính (hay con trỏ đến thuộc tính đó) được lưu dưới dạng bộ đệm liên tục (continuous buffer) trên vùng nhớ với một offset cố định giữa các vùng nhớ. Độ dài của 1 offset có thể dễ dàng xác định dựa trên loại thuộc tính, trong khi đó điều này là bất khả thi đối với Javascript khi mà loại thuộc tính có thể bị thay đổi trong quá trình thực thi.

Bởi vì sử dụng cấu trúc từ điển để tìm vị trí của thuộc tính của object trong vùng nhớ là không hiệu quả nên V8 sử dụng một phương pháp khác: lớp ẩn (hidden class). Lớp ẩn hoạt động tương tự như một cấu trúc object (class) cố định trong Java, ngoại trừ việc nó được tạo ra ở quá trình thực thi (runtime). Giờ thì xem ví dụ bên dưới nhé:

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

Khi câu lệnh new Point(1, 2) được gọi, V8 sẽ tạo ra 1 lớp ẩn, tạm gọi là C0

![](https://cdn-images-1.medium.com/max/1000/1*pVnIrMZiB9iAz5sW28AixA.png)

Không có thuộc tính nào được định nghĩa trong Point, vì thế tạm thời C0 đang rỗng.

Khi câu lệnh this.x = x được thực thi (bên trong hàm Point), V8 sẽ tạo ra 1 lớp ẩn thứ hai dựa trên C0, ta tạm gọi là C1. C1 mô tả lại vị trí trên vùng nhớ (tương tự như con trỏ) nơi mà thuộc tính x được lưu.
Trong trường hợp này, x sẽ nằm ở offset 0, nghĩa là khi chúng ta view một object Point trên vùng nhớ dưới dạng bộ đệm liên tục (continuous buffer) thì offset đầu tiên sẽ tương ứng với thuộc tính x.
V8 cũng sẽ cập nhật C0 với một sự chuyển đổi lớp (class transition) và tuyên bố rằng thuộc tính x được thêm vào trong object Point, lớp ẩn lúc này sẽ chuyển từ C0 sang C1.
Lớp ẩn cho object Point ở hình dưới lúc này là C1

![](https://cdn-images-1.medium.com/max/1000/1*QsVUE3snZD9abYXccg6Sgw.png)
_Mỗi khi có thuộc tính mới được thêm vào object, lớp ẩn cũ được cập nhật và sẽ chuyển tiếp (transition) sang lớp ẩn mới. Sự chuyển tiếp lớp ẩn là rất quan trọng bởi vì chúng cho phép những object được tạo ra theo những cách giống nhau có thể cùng chia sẻ các lớp ẩn. Nếu 2 object cùng dùng chung 1 lớp ẩn và 1 thuộc tính được thêm vào cả 2 object đó, sự chuyển tiếp sẽ đảm bảo rằng cả 2 object đều nhận được cùng 1 lớp ẩn mới và sẽ được tối ưu cùng nhau._

Quá trình này được lặp lại khi câu lệnh tiếp theo this.y = y được thực thi (bên trong hàm Point, ngay sau dòng this.x = x).

Một lớp ẩn mới, tạm gọi là C2 được tạo ra, một lớp chuyển tiếp (class transition) được thêm vào C1 biểu thị rằng nếu thuộc tính y được thêm vào object Point (object đã chứa thuộc tính x) thì lớp ẩn sẽ được thay đổi sang C2, và lớp ẩn của object Point sẽ được cập nhật thành C2

![](https://cdn-images-1.medium.com/max/1000/1*spJ8v7GWivxZZzTAzqVPtA.png)

Sự chuyển tiếp lớp ẩn phụ thuộc vào thứ tự mà những thuộc tính được thêm vào 1 object. Ví dụ:

```javascript
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;
```

Nhìn vào đoạn code trên, bạn sẽ nghĩ rằng cả p1 và p2 sẽ dùng chung lớp ẩn và sự chuyển tiếp giữa các lớp. Nhưng sự thật không phải như vậy. Đối với p1, thuộc tính thứ nhất là a sẽ được thêm vào và sau đó đến b. Với p2 thì ngược lại, b trước rồi mới đến a.
Vì vậy, p1 và p2 sẽ sinh ra 2 lớp ẩn khác nhau và có sự chuyển tiếp lớp ẩn cũng khác nhau. Trong trường hợp này, tốt nhất là nên giữ đúng thứ tự thuộc tính mỗi khi khởi tạo dữ liệu để lớp ẩn có thể được dùng lại:

```javascript
var p1 = new Point(1, 2);
p1.a = 5;
p1.b = 6;

var p2 = new Point(3, 4);
p2.a = 8;
p2.b = 7;
```

_Phần diễn giải về hidden class này khá là rối và khó hiểu, để hiểu rõ hơn thì mời bạn tham khảo thêm [bài viết chi tiết](https://thefullsnack.com/posts/javascript-v8-notes.html) của tác giả thefullsnack_

# Inline caching (Bộ đệm nội tuyến)

V8 có một điểm mạnh trong kỹ thuật tối ưu hóa dành cho các ngôn ngữ với kiểu dữ liệu động, gọi là Inline caching (bộ đệm nội tuyến). Inline caching dựa trên sự quan sát những lời gọi được lặp lại nhiều lần đến cùng 1 phương thức có xu hướng xảy ra trên cùng 1 loại object. Diễn giải chi tiết hơn về inline caching có thể xem ở [đây](https://github.com/sq/JSIL/wiki/Optimizing-dynamic-JavaScript-with-inline-caches)

Giờ chúng ta sẽ duyệt sơ qua những khái niệm chung chung của inline caching (nếu như bạn không có thời gian đọc hết bài chi tiết ở trên)

Vậy thì nó hoạt động như thế nào? V8 duy trì bộ nhớ đệm về kiểu của các object được truyền qua dưới dạng tham số (parameter) trong những lần gọi method gần đây và sử dụng thông tin này để dự đoán về kiểu object sẽ được truyền trong tương lai. Nếu như V8 có thể dự đoán tương đối tốt về kiểu object sẽ được truyền vào thì nó có thể bỏ qua bước xử lý tìm hiểu về các thuộc tính của object đó, nó sẽ dùng những thông tin có sẵn đã được lưu từ lần trước và áp dụng cho lớp ẩn của object này.

Vậy thì lớp ẩn và inline caching liên quan với nhau như thế nào? Khi một phương thức được gọi trên một object cụ thể, V8 sẽ thực hiện tìm kiếm lớp ẩn của object đó để xác định offset nhằm phục vụ cho việc truy xuất thuộc tính. Sau 2 lần gọi thành công cùng 1 phương thức đến cùng 1 lớp ẩn, V8 sẽ bỏ qua việc tìm kiếm lớp ẩn đó và đơn giản là thêm offset của thuộc tính vào trong bản thân con trỏ của object. Về sau, cứ mỗi lần gọi phương thức, V8 sẽ giả định rằng lớp ẩn không thay đổi và nhảy trực tiếp vào trong địa chỉ vùng nhớ của thuộc tính và sử dụng offset đã được lưu từ lần tìm kiếm trước đó. Cách này có thể gia tăng đáng kể tốc độ thực thi.

Inline caching cũng là lý do quan trọng cho việc cùng kiểu object sẽ dùng chung lớp ẩn. Nếu bạn tạo ra 2 object có cùng 1 kiểu nhưng khác hidden class (như chúng ta đã làm ở trên), V8 sẽ không thể sử dụng inline caching bởi vì mặc dù 2 object có cùng kiểu nhưng lớp ẩn tương ứng của nó lại gán offset khác nhau cho mỗi thuộc tính.

![](https://cdn-images-1.medium.com/max/1000/1*iHfI6MQ-YKQvWvo51J-P0w.png)
2 object về cơ bản là giống nhau nhưng thuộc tính a và b lại có thứ tự khác nhau.

# Biên dịch thành mã máy

Một khi đồ thị Hydrogen đã được tối ưu hóa, Crankshaft chuyển nó xuống một tầng thấp hơn gọi là Lithium. Hầu như toàn bộ các Lithium này là kiến trúc cụ thể (architecture-specific, mình cũng không hiểu nữa, kiến thức chuyên sâu quá). Đăng ký cấp phát xảy ra ở tầng này.

Ở bước cuối cùng, Lithium được biên dịch thành mã máy. Sau đó, quá trình thay đổi trên ngăn xếp (on-stack replacement: OSR) sẽ diễn ra. Trước khi chúng ta bắt đầu biên dịch và tối ưu hóa một phương thức ngốn nhiều thời gian, chúng ta thường chạy nó trước. V8 sẽ không vứt hết những đoạn code chậm và chạy lại từ đầu đoạn code đã tối ưu. Thay vì thế, V8 sẽ chuyển hóa toàn bộ ngữ cảnh hiện tại (ngăn xếp, các thanh ghi), do đó ta có thể chuyển đổi sang phiên bản đã được tối ưu ngay giữa quá trình thực thi. Đây là một thao tác cực kỳ phức tạp, hãy nhớ rằng V8 đã _inline_ toàn bộ code giữa quá trình tối ưu hóa (Đoạn này viết khó hiểu quá, nhưng mà cũng không quan tọng lắm đâu). Ngoài ra thì V8 không phải là engine duy nhất có thể làm được điều này.

Có một giải pháp an toàn đó là đảo ngược quá trình tối ưu hóa (deoptimization - phức tạp hóa ?) để chuyển đổi toàn bộ code về với trạng thái chưa được tối ưu trong trường hợp engine gặp trục trặc.

# Bộ dọn rác (Garbage collection - GC)

Đối với GC thì V8 sử dụng phương pháp thế hệ theo kiểu truyền thống là đánh-dấu-và-quét (mark-and-sweep) để dọn dẹp những thứ cũ. Giả sử quá tình đánh dấu có thể làm ngưng sự thực thi Javascript. Để có thể điều hành GC hiệu quả và thực hiện một cách ổn định, V8 sử dụng đánh dấu gia tăng (incremental marking), thay vì duyệt qua toàn bộ heap và cố đánh dấu nhiều object nhất có thể, nó sẽ đi qua từng heap, sau đó quay lại với những thực thi bình thường.
Lần tiếp theo GC chạy sẽ tiếp tục từ vị trí heap mà trước đó nó đã dừng lại. Cách này cho phép một khoảng thời gian dừng rất ngắn giữa quá trình thực thi. Và như đã đề cập ở trước, quá tình quét dọn được xử lý bằng 1 tiến trình khác.

# Ignition và TurboFan

Cùng với sự ra mắt của V8 bản 5.9 đầu năm 2017, có 2 pipeline thực thi mới được giới thiệu, mang lại khả năng cải thiện hiệu năng tốt hơn và tiết kiệm bộ nhớ đáng kể đối với những ứng dụng Javascript.

Bộ pipeline mới này được xây dựng trên trình thông dịch của V8 là [Ignition](https://github.com/v8/v8/wiki/Interpreter) và trình biên dịch tối ưu hóa mới nhất là [TurboFan](https://github.com/v8/v8/wiki/TurboFan).

Bạn có thể xem thêm thông tin trong bài viết trên blog của V8 tại [đây](https://v8project.blogspot.bg/2017/05/launching-ignition-and-turbofan.html)

Kể từ phiên bản 5.9 thì _full-codegen_ và _Crankshaft_ (những công nghệ đã xuất hiện trong V8 từ năm 2010) đã không còn được sử dụng cho quá trình thực thi Javascript nữa khi mà nhóm phát triển V8 đã phải vất vả để có thể theo kịp với những tính năng mới và sự tối ưu hóa cần thiết cho những tính năng này.

Điều này nghĩa là xét một cách tổng quát thì V8 sẽ đơn giản hơn và có kiến trúc dễ bảo trì hơn.

![](https://cdn-images-1.medium.com/max/1000/0*pohqKvj9psTPRlOv.png)

Những cải tiến này chỉ là bước khởi đầu. Ignition và TurboFan sẽ lót đường cho những tối ưu hóa về sau, đẩy mạnh hiệu năng Javascript và tinh giản bớt V8 trong Chrome và Node.js trong những năm tới.

Cuối cùng, dưới đây là 1 số mẹo vặt để bạn có thể viết được bộ code Javascript một cách tối ưu. Bạn có thể dễ dàng rút ra được bài học từ những gì đã nêu ở trên, nhưng để dễ hiểu hơn thì mời bạn xẹm tổng kết:

# Làm thế nào để tối ưu hóa Javascript

1.  **Thứ tự các thuộc tính của object**: luôn luôn khởi tạo các thuộc tính của object sao cho chúng có cùng thứ tự để lớp ẩn và những code tối ưu có thể chia sẻ dùng chung.
2.  **Thuộc tính động** (Dynamic properties): thêm thuộc tính vào một object sau khi khởi tạo sẽ ép lớp ẩn phải thay đổi và làm chậm những phương thức đã được tối ưu cho lớp ẩn trước đó. Thay vì thế, ta có thể gán tất cả các thuộc tính của object trong hàm khởi tạo constructor.
3.  **Phương thức**: code thực thi cùng 1 phương thức nhưng nhiều lần sẽ chạy nhanh hơn code thực thi nhiều phương thức khác nhau nhưng mỗi phương thức chạy một lần (xem phần inline caching)
4.  **Mảng**: Tránh sử dụng mảng thưa (sparse arrays) mà key không phải là số tăng liên tục. Mảng thưa mà không có phần tử nào thì lại là bảng băm (hash table). Mỗi phần tử trong mảng như vậy sẽ gây ra sự tốn kém mỗi lần truy xuất. Ngoài ra cần tránh trường hợp cấp phát bộ nhớ trước cho những mảng lớn. Cứ để cho mảng "nở ra" một cách tự nhiên. Cuối cũng thì cũng đừng xóa các phần tử trong mảng (toán tử delete()) vì nó chỉ xóa phần từ chứ không đánh index lại mảng.
5.  **Tagged values**: Trong V8 thì object và số (number) là 32bits. Nó sử dụng 1 bit để phân biệt object (flag = 1) và số integer (flag = 0) gọi là SMI (SMall Integer). Vì thế nếu 1 giá trị số lớn hơn 31 bit thì V8 sẽ đóng gói số đó, chuyển nó thành kiểu double và tạo 1 object mới để lưu số. Chỉ nên sử dụng số nguyên có dấu 31 bit để tránh quá trình chuyển đổi không đáng có (lại tốn công xử lý) số thành object.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p2-ben-trong-engine-v8-5-meo-de-toi-uu-hoa-code</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p2-ben-trong-engine-v8-5-meo-de-toi-uu-hoa-code</guid>
            <pubDate>Tue, 13 Nov 2018 22:52:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách Javascript hoạt động P1: Khái quát về engine, runtime và callstack]]></title>
            <description><![CDATA[
Javascript càng ngày càng phổ biến, có nhiều nhóm các lập trình viên đã và đang nâng cấp cũng như hỗ trợ JS ở nhiều mức độ khác nhau: từ frontend đến backend, hybrid app, thiết bị nhúng và còn nhiều nữa.

Bài viết này mở đầu cho 1 series hướng tới mục đích đào sâu (aka _Đục Khoét_) vào trong Javascript và cách mà nó hoạt động như thế nào: Bằng cách hiểu rõ các thành phần của JS và cách mà chúng tương tác với nhau thì bạn có thể viết code tốt hơn và _ngon_ hơn. Bên cạnh đó team SessionStack cũng chia sẻ một vài bí kíp trong khi xây dựng SessionStack - 1 ứng dụng Javascript nhẹ nhưng có chất lượng cao và mạnh mẽ.

Như ta thấy trong [GitHut stats](https://githut.info/), Javascript đang là top đứng đầu trong các repo đang hoạt động (Active Repositories) và tổng số push (Total Pushes) ở GitHub. Và nó cũng không bị tụt lùi quá nhiều ở những hạng mục khác.

![](https://cdn-images-1.medium.com/max/1000/1*Zf4reZZJ9DCKsXf5CSXghg.png)

([Xem cập nhật mới nhất về GitHut stat](https://madnight.github.io/githut/)).

Nếu dự án phụ thuộc quá lớn vào Javascript thì có nghĩa rằng các lập trình viên phải tận dụng tối đa khả năng mà ngôn ngữ này cũng như hệ sinh thái (ecosystem) của nó cung cấp và thấu hiểu một cách triệt để về bản chất của nó để có thể xây dựng được những công trình vi diệu.

Và một cách hiển nhiên là có rất nhiều lập trình viên đang sử dụng Javascript hằng ngày nhưng lại không có kiến thức hoặc không biết gì về những thứ đang thực sự diễn ra bên trong JS.

# Tổng quan

Hầu như mọi người ai cũng từng nghe qua bộ engine V8 và đa số mọi người biết rằng JS là một ngôn ngữ đơn luồng (single-thread) hoặc là nó sử dụng hàng đợi các callback (callback queue - không biết dịch sao cho đúng
![](https://assets-cdn.github.com/images/icons/emoji/unicode/1f613.png)
)

Trong bài này, chúng ta sẽ đi lần lượt một cách chi tiết qua các khái niệm cơ bản và giải thích cụ thể Javascript chạy như thế nào. Bằng cách đó, chúng ta có thể viết code được tốt hơn, xây dựng app có khả năng xử lý API một cách mượt mà, không bị block lẫn nhau (non-blocking apps).

Nếu bạn là người mới học Javascript thì bài viết này sẽ giúp bạn hiểu tại sao Javascript lại "quái dị" khi so sánh với các ngôn ngữ khác.

Và nếu bạn là một dev có kinh nghiệm với JS thì hi vọng bài viết này sẽ giúp ích cho bạn hiểu thêm về cách hoạt động của JS Runtime - thứ mà bạn đang sử dụng mỗi ngày.

# JavaScript Engine

_Engine: Cỗ máy - mình sẽ không dịch từ mà để nguyên gốc tiếng Anh_

Một ví dụ điển hình của JS Engine chính là bộ Google V8\. Bộ engine V8 này được sử dụng trong Google Chrome và Node.js. Dưới đây là một mô hình đơn giản nhất của nó:
![](https://cdn-images-1.medium.com/max/1000/1*OnH_DlbNAPvB9KLxUCyMsA.png)

Engine gồm 2 thành phần chính:

- Vùng nhớ heap (memory heap): khu vực cấp phát bộ nhớ
- Ngăn xếp (call stack): đây là nơi chứa các khung stack khi bạn thực thi code.

# Runtime (Môi trường thực thi)

Có những API trong trình duyệt đang được sử dụng bởi đa số JS developer hiện nay (ví dụ: setTimeout). Những API này lại không được cung cấp bởi các Engine.

Vậy thì chúng từ đâu tới ?

Sự thật có đôi chút phức tạp một tí.

![](https://cdn-images-1.medium.com/max/1600/1*4lHHyfEhVB0LnQ3HlhSs8g.png)

Chúng ta có JS Engine nhưng thực ra còn nhiều thứ hơn thế. Các browser thường cung cấp một hệ thống _Web APIs_ bao gồm nhiều thành phần như DOM, AJAX, setTimeout, vân vân và mây mây.

Và rồi cả những thứ nổi tiếng như event loop và callback queue nữa.

# Ngăn xếp (Call Stack)

Javascript là ngôn ngữ lập trình đơn luồng (single-threaded), nghĩa là nó chỉ có 1 cái call stack. Vì thế nó chỉ có thể làm 1 công việc tại 1 thời điểm nhất định.

Call Stack là một cấu trúc dữ liệu mà về cơ bản thì nó ghi nhớ vị trí của chúng ta trong chương trình đang chạy. Nếu như chúng ta thực thi một hàm (function) thì khi đó ta sẽ đặt hàm đấy vào vị trí trên cùng của ngăn xếp (stack), sau khi xử lý xong và return từ hàm đó, vị trí trên cùng sẽ bị đẩy ra khỏi stack. Đó là cách hoạt động của Call Stack.

Để dễ hiểu hơn thì mời bạn xem ví dụ bên dưới:

```javascript
function multiply(x, y) {
  return x * y;
}
function printSquare(x) {
  var s = multiply(x, x);
  console.log(s);
}
printSquare(5);
```

Khi engine bắt đầu thực thi code, Call Stack còn đang rỗng. Ngay sau đó, từng bước thực hiện sẽ giống như hình bên dưới:

![](https://cdn-images-1.medium.com/max/1600/1*Yp1KOt_UJ47HChmS9y7KXw.png)

Mỗi bản ghi trong Call Stack được gọi là khung của ngăn xếp (Stack Frame).

Và đây cũng là cách chính xác mà stack traces được xây dựng và in ra mỗi khi có xử lý biệt lệ (exception handling). Về cơ bản thì nó chính là trạng thái của Call Stack ngay tại thời điểm có biệt lệ xảy ra. Hãy nhìn vào đoạn code bên dưới:

```javascript
function foo() {
  throw new Error("SessionStack will help you resolve crashes :)");
}
function bar() {
  foo();
}
function start() {
  bar();
}
start();
```

Nếu như chạy đoạn code đó trên Chrome console (giả sử toàn bộ code nằm trong 1 file foo.js), thì chúng ta sẽ có stack trace như sau:

![](https://cdn-images-1.medium.com/max/1600/1*T-W_ihvl-9rG4dn18kP3Qw.png)

Thổi tung ngăn xếp (**Blowing the stack**)  - Trường hợp này xảy ra khi chương trình thực thi đạt tới kích thước giới hạn tối đa của Call Stack. Và để có thể có được tình huống này một cách dễ dàng nhất, chỉ cần _vô tình_ gọi đệ quy một cách không cẩn thận là được à:

```javascript
function foo() {
  foo();
}
foo();
```

Khi engine bắt đầu thực thi code, nó gọi hàm foo đầu tiên. Hàm này lại gọi đệ quy chính bản thân nó để rồi rơi vào 1 vòng lặp vô hạn không có điều kiện dừng. Mỗi khi gọi hàm thì 1 bản ghi sẽ được đẩy vào Call Stack, và cứ thế, cứ thể đẩy vào làm cho tràn ngăn xếp (aka stackoverflow). Giống như hình bên dưới:

![](https://cdn-images-1.medium.com/max/1600/1*AycFMDy9tlDmNoc5LXd9-g.png)

Tại 1 thời điểm cụ thể nào đó khi số lần gọi hàm đạt tới ngưỡng giới hạn của Call Stack (call stack size) thì trình duyệt sẽ quyết định "giải cứu" bằng cách bắn ra 1 lỗi trông như thế này đây:

![](https://cdn-images-1.medium.com/max/1600/1*e0nEd59RPKz9coyY8FX-uw.png)

Chạy code đơn tiến trình có thể khá là dễ dàng bởi vì chúng ta không phải mất công đối phó với những tình huống phức tạp thường gặp trong môi trường đa tiến trình (chẳng hạn như deadlocks).

Tuy nhiên đơn tiến trình cũng có những giới hạn của nó. Bởi vì Javascript chỉ có 1 Call Stack, điều gì sẽ xảy ra khi có vài xử lý chậm chạp?

# Xử lý đồng thời (Concurrency) & Vòng lặp sự kiện (Event Loop)

Điều gì sẽ xảy ra nếu như bạn có 1 hàm xử lý đang ở trong Call Stack nhưng hàm đó lại tốn kha khá thời gian để chạy? Ví dụ như bạn muốn thực hiện một vài thuật toán chuyển đổi hình ảnh phức tạp bằng Javascript ngay trên trình duyệt.

Thế thì có vấn đề gì nào? Vấn đề ở đây là trong khi Call Stack đang bận tối tăm mặt mũi để xử lý thì trình duyệt lại rảnh không, ngồi chơi xơi nước vì không có gì để làm, đúng hơn là không thể làm gì được - trình duyệt đã bị block. Có nghĩa là trình duyệt không thể render, nó cũng không chạy được các câu lệnh khác, tóm lại là bị mắc kẹt. Điều này gây ảnh hưởng lớn đến sự mượt mà của UI trên app.

Đó cũng không phải vấn đề duy nhất đâu. Một khi trình duyệt bắt đầu xử lý quá nhiều thứ trong Call Stack, nó sẽ bị "đơ", không thể tương tác được trong 1 khoảng thời gian dài. Đa số trình duyệt sẽ bắn ra lỗi, hỏi bạn xem có muốn hủy trang đang chạy không. Đại loại là giống như hình dưới:

[![](https://cdn-images-1.medium.com/max/1600/1*WlMXK3rs_scqKTRV41au7g.jpeg)](https://cdn-images-1.medium.com/max/1600/1*WlMXK3rs_scqKTRV41au7g.jpeg) <a></a>

Rõ ràng điều này không phải là 1 trải nghiệm người dùng (User experience) tối ưu phải không nào?

Vậy thì làm thế nào để xử lý code vừa nhiều vừa nặng mà lại không làm UI bị kẹt cũng như trình duyệt bị đơ? Giải pháp đó là sử dụng callback bất đồng bộ (**asynchronous callbacks**).

Điều này sẽ được giải thích kỹ hơn trong Phần 2 của series: **Bên trong engine V8 & 5 mẹo để tối ưu hóa code**. Các bạn đón xem nhé.

PS: Trong các bài sau mình sẽ trình bày chi tiết và kỹ hơn về cách hoạt động của Event Loop.
]]></description>
            <link>https://hungvn.com/blog/cach-javascript-hoat-dong-p1-khai-quat-ve-engine-runtime-va-callstack</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-javascript-hoat-dong-p1-khai-quat-ve-engine-runtime-va-callstack</guid>
            <pubDate>Tue, 13 Nov 2018 22:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Một số nguyên tắc, định luật trong lập trình]]></title>
            <description><![CDATA[
## Nguyên tắc Demeter

Còn có tên gọi khác là nguyên tắc “càng biết ít càng tốt”.

Demeter là tên gọi của Nữ thần nông nghiệp, cũng là nữ thần phân phát trong thần thoại Hi Lạp. Tên bà được dùng để đánh dấu sự ra đời của nguyên tắc này, đây có thể xem là một triết lý nền tảng của việc lập trình được sinh ra từ một aspect-oriented programming (AOP) project cùng tên.

Quan điểm cơ bản của nguyên tắc này chính là : tối giản sự hiểu biết của 1 object về cấu trúc, thuộc tính của các object khác ngoài nó (bao gồm các thành phần con).

[http://en.wikipedia.org/wiki/Law_of_Demeter](http://en.wikipedia.org/wiki/Law_of_Demeter)

Nói một cách đơn giản là không được tiếp xúc với thuộc tính, method của các object khác một cách trực tiếp.

```javascript
#Vi phạm nguyên tắc Demeter
console.log(aStudent.class.grade)

#Không vi phạm nguyên tắc Demeter
console.log(aStudent.getGrade())
```

## Định luật Wirth

“Software gets slower faster than hardware gets faster” – “Tốc độ tiến hóa của phần cứng không bằng tốc độ thoái hóa của phần mềm.”

[http://en.wikipedia.org/wiki/Wirth’s_law](http://en.wikipedia.org/wiki/Wirth%E2%80%99s_law)

Có lẽ ý chính của nó là : lập trình ngày càng dùng nhiều tài nguyên phong phú nên framework phải luôn tiến hóa để phục vụ cho việc đó. Suy ra, tốc độ phần cứng dù có tang lên đi nữa thì tốc độ phần mềm cũng chẳng hề thay đổi gì.

## Định luật Brook

Đây là một định luật dựa trên kinh nghiệm thực tế : “Đưa thêm người vào 1 project đang chậm, sẽ chỉ khiến nó càng chậm hơn.”

Hay có thể nói theo một cách khác nữa là “Tập hợp 9 bà bầu lại cũng không thể khiến đứa trẻ ra đời sau 1 tháng.”

Luận thuyết cơ bản của định luật này là

- Cần thời gian để quen với project
- Công sức dành cho việc communication sẽ tăng

[http://en.wikipedia.org/wiki/Brooks's_law](http://en.wikipedia.org/wiki/Brooks%27s_law)

## Định luật Conway

“Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.”

“Một công ty thiết kế hệ thống thế nào cũng sẽ làm ra những thiết kế giống y hệt với thiết kế hệ thống của chính công ty họ.”

[http://en.wikipedia.org/wiki/Conway's_law](http://en.wikipedia.org/wiki/Conway%27s_law)

Nghiên cứu gần đây chỉ ra rằng hệ thống của công ty là nhân tố ảnh hưởng lớn nhất đến vấn đề phát sinh ra bug của sản phẩm.

[http://research.microsoft.com/apps/pubs/default.aspx?id=70535](http://research.microsoft.com/apps/pubs/default.aspx?id=70535)

## Nguyên tắc bất ngờ nhỏ nhất (least astonishment)

Trong trường hợp trên cùng 1 interface có 2 yếu tố hành xử mâu thuẫn với nhau, hoặc cách hành xử không rõ ràng thì cần phải chọn cách hành xử nào gây bất ngờ ít nhất cho người sử dụng.

[http://en.wikipedia.org/wiki/Principle_of_least_astonishment](http://en.wikipedia.org/wiki/Principle_of_least_astonishment)

Đây là 1 nguyên tắc về giao diện người dùng.

Một ví dụ đơn giản :

Trên 1 interface có 2 chức năng :

- Ấn ctrl+Q để thoát chương trình.
- Nhập macro (lưu 1 tổ hợp phím mang 1 chức năng nào đó để tiện cho việc sử dụng về sau).

Sẽ có trường hợp user muốn dùng Ctrl+Q cho macro của mình, nên hành xử đúng với nguyên tắc bất ngờ nhỏ nhất chính là : trong khi nhập macro thì ctrl+Q được coi như là tổ hợp phím bình thường, không phải là lệnh tắt chương trình. Đây chính là điều gây bất ngờ ít nhất cho người dùng.

## Nguyên tắc Boy Scout

Nguyên tắc của các tổ chức Boy scout chính là : lúc đi phải sạch đẹp hơn lúc đến.

Trong lĩnh vực lập trình thì nguyên tắc đó sẽ được hiểu là “Khi bạn checkin 1 module thì lúc đó nó phải đẹp hơn lúc bạn checkout.”

## Nguyên tắc YAGNI

Viết tắt của “You ain’t gonna need it” – Cái (chức năng, phần) ấy rồi sẽ không cần thiết.

Đó là một câu khẩu ngữ nhắc nhở người lập trình rằng trong quy trình Extreme Programming (lập trình cực hạn) thì : “Chưa phải lúc cần thiết thì chưa được phép làm.”

## Nguyên tắc DRY

Viết tắt của “Don’t repeat yourself” – với ý nghĩa là “Đừng lặp lại những gì giống nhau”.

[http://en.wikipedia.org/wiki/Don't_repeat_yourself](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)

Khi nguyên tắc này được áp dụng tốt, dù ta có thay đổi 1 phần thì những phần không liên quan cũng sẽ không bị thay đổi theo. Hơn nữa, những phần có liên quan sẽ được thay đổi cùng 1 lượt, giúp ích rất nhiều cho cả khâu estimate và khâu thực hiện.

## Nguyên tắc KISS

Viết tắt của “Keep it simple, stupid” – “Cứ đơn giản thôi, đồ ngu!”. Đây là 1 triết lí của Hải quân Mỹ.

[http://en.wikipedia.org/wiki/KISS_principle](http://en.wikipedia.org/wiki/KISS_principle)

Những triết lý tương tự có thể kể đến là :

**Phương châm dao cạo Okham (Okham’s razor)** – “Không đưa ra nhiều giả thiết nếu không cần thiết. Cái gì cần ít giả thiết để chứng minh sẽ không thể chứng minh được bằng nhiều giả thiết.”

**Albert Einstein** – “Làm cái gì cũng nên đơn giản nhất có thể, nhưng đơn giản quá thì không được”.

**Leonardo da Vinci** – “Đơn giản nhất chính là điêu luyện nhất”.

**Antoine de Saint- Exupéry** – “Hoàn hảo, không phải là không thêm vào được nữa, mà là không thể bớt đi được nữa”.

## Nguyên tắc SOLID

Tập hợp những nguyên tắc trong lập trình hướng đối tượng. Các chữ cái đầu hợp lại thành SOLID.

[http://en.wikipedia.org/wiki/SOLID\_(object-oriented_design)](<http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)>)

**SRP (Single Responsibility Principle)** – “Một class chỉ được có 1 nhiệm vụ” hay nói cách khác, “nếu muốn chỉnh sửa class thì chỉ được phép có 1 và chỉ 1 lý do”.

**OCP (Open/closed principle)** – “Mở class khi cần mở rộng nó, đóng class khi cần chỉnh sửa nó”.

**LSP (Liskov substitution principle)** – “Subtype phải luôn có thể được thay thế bằng supertype”.

**ISP (Interface segregation principle)** – “Việc dùng nhiều interface cho các client khác nhau, tốt hơn là việc chỉ dùng 1 interface cho cùng lúc nhiều mục đích” hay nói cách khác “Không được phép hạn chế access vào những method mà client không sử dụng”.

**DIP (Dependency inversion principle)** – “Module tầng trên không được phụ thuộc vào module tầng dưới. Bất cứ module nào cũng phải phụ thuộc vào cái trừu tượng, không phải vào cái cụ thể”.
]]></description>
            <link>https://hungvn.com/blog/mot-so-nguyen-tac-dinh-luat-trong-lap-trinh</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mot-so-nguyen-tac-dinh-luat-trong-lap-trinh</guid>
            <pubDate>Tue, 06 Nov 2018 07:29:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Khi nào nên sử dụng PureComponent hoặc Component]]></title>
            <description><![CDATA[
PureComponent tiền đề của nó là một phiên bản có hiệu suất cao hơn của Component. Điều này là đúng, nhưng hiệu suất đạt được đi cùng với một vài thứ đi kèm. Chúng ta hãy tìm hiểu về PureComponent và hiểu tại sao chúng ta nên sử dụng nó nhé.

## Component và PureComponent có một sự khác biệt

```javascript
PureComponent chính xác giống như Component ngoại trừ việc đó là nó xử lý shouldComponentUpdate cho bạn.
```

Khi props hoặc state thay đổi, PureComponent sẽ làm một _shallow comparison_ (so sánh nông) trên cảm props và state. Component trên mặt khác sẽ không so sánh props và state của hiện tại với tương lai. Như vậy, component sẽ re-render bởi mặc định bất cứ khi nào shouldComponentUpdate gọi.

## Shallow Comparison 101

Khi so sánh props và state trước và sau, một _shallow comparison_ sẽ kiểm tra những giá trị nguyên thuỷ đó có cùng giá trị(ví dụ 1 bằng 1 hoặc _true_ bằng với _true_) và rằng các _references value_ là giống nhau giữa các giá trị javascript phức tạp như objects và arrays.

## Never MUTATE

Bạn có lẽ đã nghe không thay đổi objects và arrays trong props và state. Nếu bạn thay đổi object trong một component cha, component "pure" con của bạn sẽ không update. Mặc dù giá trị đã thay đổi ở component cha, component con sẽ so sánh _reference_ tới props trước đó và không phát hiện ra sự khác biệt chúng vân cùng reference tới cùng một object.

Thay vào đó trả về một objects mới khi bạn làm một sự thay đổi bằng cách tận dụng es6 cho object và array _spreading_ hoặc sử dụng một thư viện để thi hành _immutability_.

## Có vấn đề với hiệu năng không?

So sánh primitives và object references là một hoặt động **vô cùng rẻ tiền**. Nếu bạn có một danh sách của object con và một trong đó update, làm một kiểm tra trên props và state của chúng là so sánh nhanh như ánh sáng so với chi phí của việc re-render từng cái một.

# Những cách khác bạn có thể làm để tăng hiệu năng

### Đừng bind giá trị vào fuction trong render

Bạn có một danh sách các items, mỗi lần chuyền một tham số độc nhất tới phương thức cha. Theo thứ tự bind parameter bạn có lẽ sẽ hoàn thành như thê này:

```javascript
<CommentItem likeComment={() => this.likeComment(user.id)} />
```

vấn đề đó là mỗi lần component cha render method sẽ gọi, một function mới (với một reference mới) được tạo ra và chuyền xuống **LikeComnent**. Điều này có side effect của thay đổi props trên mỗi component con mà lần lượt sẽ là nguyên nhân tât cả chúng re-render, thậm chí tất cả dữ liệu là giống nhau.

Để giải quyết vấn đề này, chỉ cần chuyền function nguyên mẫu từ component cha tới con. prop của **LikeComent** sẽ luôn luôn có cùng reference và không bao giờ gây ra re-render không cần thiết.

```javascript
<CommentItem likeComment={this.likeComment} userID={user.id} />
```

Sau đó trong component con tạo ra một class method sẽ reference props của nó:

```javascript
class CommentItem extends PureComponent {
  ...
  handleLike() {
    this.props.likeComment(this.props.userID)
  }
  ...
}
```

### Đừng lấy dữ liệu trong render

Xem xét một danh sách của các bài viết từ đó component hồ sơ của bạn sẽ hiển thị 10 người dùng bạn thích nhất.

```javascript
render() {
  const { posts } = this.props
  const topTen = [...posts].sort((a, b) =>
    b.likes - a.likes).slice(0, 9)
  return //...
}
```

**TopTen** sẽ có một _new reference_ mỗi lần component re-render, mặc dù **posts** không có sự thay đổi và dữ liệu có cùng nguồn gốc. Điều này sau đó sẽ re-render list một cách không cần thiết.

Bạn có thể giải quyết điều này bởi _caching_ dữ liệu gốc. Cho ví dụ, đặt dữ liệu gốc trong state của component và update chỉ khi **posts** có updated.

```javascript
componentWillMount() {
  this.setTopTenPosts(this.props.posts)
}
componentWillReceiveProps(nextProps) {
  if (this.props.posts !== nextProps.posts) {
    this.setTopTenPosts(nextProps.posts)
  }
}
setTopTenPosts(posts) {
  this.setState({
    topTen: [...posts].sort((a, b) => b.likes - a.likes).slice(0, 9)
  })
}
```

Nếu bạn sử dụng Redux, xem xét sử dụng [reselect](https://github.com/reduxjs/reselect) để tạo "selectors" để soạn và cache dữ liệu gốc.

# Tổng kết

An toàn khi sử dụng pureComponent thay thế Component miễn là bạn theo hai quy tắc đơn giản sau:

1.  Thay đổi đột ngột **reference value** nhìn chung là không tốt. Nhưng vấn đề là phức tạp khi sử dụng PureComponent.
2.  Nếu bạn tạo ra một function, object, array mới trong render bạn (có lẽ) làm nó sai.
]]></description>
            <link>https://hungvn.com/blog/khi-nao-nen-su-dung-purecomponent-hoac-component</link>
            <guid isPermaLink="true">https://hungvn.com/blog/khi-nao-nen-su-dung-purecomponent-hoac-component</guid>
            <pubDate>Wed, 17 Oct 2018 07:57:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Redux hay MobX: Lý giải sự nhầm lẫn]]></title>
            <description><![CDATA[
# Chúng ta cần giải quyết vấn đề gì?

Tất cả chúng ta đều muốn có một cách nào đó để quản lý state trong một ứng dụng. Nhưng bạn đã bao giờ tự hỏi nó giải quyết được vấn đề gì cho chúng ta chưa? Hầu hết các lập trình viên đều sử dụng một thư viện quản lý state ngay cả đối với những ứng dụng nhỏ. Hiển nhiên thôi mà, khi tất cả những người khác đều nói về chúng, tất nhiên chúng ta cũng phải bắt kịp xu thế chứ? Redux này, MobX này. Thế nhưng hầu hết các ứng dụng lại không cần đến những công cụ quản lý state phức tạp đến vậy. Nó còn nguy hiểm hơn, vì hầu hết mọi người sẽ không bao giờ gặp những vấn đề mà những thư viện như Redux hay MobX cố gắng để giải quyết.

Ngày nay, một hiện trạng mà chúng ta dễ dàng thấy là việc mọi người đều viết ra những frontend app với các component. Component thì có state nội tại. Ví dụ trong React thì state nội tại đó được xử lý bằng this.state và this.setState(). Với những app lớn, vấn đề guản lý state có thể trở nên khó khăn với state nội bộ bởi vì:

- Một component cần phải chia sẻ state với một component khác.
- Một component cần phải thay đổi state của một component khác.

Đến một lúc nào đó, vấn đề này càng ngày càng trở nên khó giải quyết khi nó trở thành một đống hỗn loạn các state object và các thay đổi diễn ra chồng chéo nhau khắp các component và rất khó để chúng ta có thể quản lý tất cả một cách hiệu quả.

Suy ra để giải quyết vấn đề này, chúng ta có thể sử dụng thư viện như MobX hay Redux. Những thư viện này cung cấp cho chúng ta công cụ để lưu giữ state, thay đổi state và nhận những thay đổi của state. Bạn có một chỗ để tìm state, một chỗ để thay đổi nó và cũng một chỗ để nhận các thay đổi. Chúng tuân theo nguyên tắc single source of truth (chỉ một nơi để lưu trữ toàn bộ state). Nó làm cho việc quản lý state trở nên dễ dàng hơn vì nó được tách rời khỏi các component của bạn.

Các thư viện quản lý state như Redux hay MobX thường có các add-on đi kèm, như với React thì chúng ta có react-redux và mobx-react, để cung cấp cho các component cách để truy cập các state. Thường thì các component đó được gọi là container component, hay chính xác hơn là, connected component. Bạn có thể truy cập hoặc thay đổi state từ bất cứ đâu trong ứng dụng của bạn bằng cách biến các component thành các connected component.

# Redux và MobX có gì khác nhau?

Trước khi chúng ta nói về những khác biệt, tôi muốn nói về một số điểm chung giữa MobX và Redux.

Cả 2 thư viện đều được dùng để quản lý state trong các ứng dụng Javascript. Chúng không nhất thiết phải đi kèm với một thư viện như React. Chúng cũng được dùng trong những thư viện khác như AngularJs hay VueJs nữa. Nhưng chúng kết hợp rất tốt với triết lý của React.

Nếu bạn chọn dùng một thư viện để quản lý state, bạn sẽ không bị ràng buộc bởi nó. Bạn có thể chuyển qua sử dụng một thư viện khác bất kỳ lúc nào. Bạn hoàn toàn có thể chuyển từ MobX sang Redux hoặc ngược lại.

Redux bởi Dan Abramov và Andrew Clark là một biến thể của kiến trúc flux. Trái ngược với flux, nó chỉ sử dụng duy nhất một store để lưu trữ state. Hơn nữa, thay vì sử dụng một dispatcher, nó dùng các pure function để thay đổi state. Redux bị ảnh hưởng rất nhiều bởi các nguyên tắc của functional programming (FP). Chúng ta có thể có FP trong Javascript, nhưng rất nhiều người đã quen với OOP như Java, và họ gặp rất nhiều khó khăn trong việc ứng dụng các nguyên tắc này. Điều này cũng lý giải tại sao MobX có thể sẽ dễ học hơn đối với người mới.

Bởi vì Redux áp dụng các nguyên tắc của FP, nó sử dụng hàm thuần khiết. Một hàm nhận input, trả về output và không có thêm bất cứ sự phụ thuộc nào khác. Một hàm thuần khiết luôn trả về cùng một output đối với cùng một input và không hề có side effect.

```javascript
(state, action) => newState;
```

Redux state là **immutable**. Thay vì thay đổi state, bạn luôn trả về một state mới. Bạn không bao giờ trực tiếp thay đổi object state hay phụ thuộc vào tham chiếu đến object.

```javascript
// Đừng làm thế này trong Redux vì nó trực tiếp thay đổi array
function addAuthor(state, action) {
  return state.authors.push(action.author);
}

// Luôn giữ state immutable và trả về object mới
function addAuthor(state, action) {
  return [...state.authors, action.author];
}
```

Điều cuối cùng nhưng ko kém phần quan trọng, state của bạn được normalize như trong một database. Các entity chỉ tham chiếu đến nhau bằng id. Đó là cách làm tốt nhất. Mặc dù không phải tất cả mọi người đều làm vậy, bạn có thể sử dụng một thư viện như normalizr để đạt được state đã chuẩn hóa. Normalized state giúp cho chúng ta có một state phẳng và lưu giữ các entity như một nguồn duy nhất.

```javascript
{
  post: {
    id: 'a',
    authorId: 'b',
    ...
  },
  author: {
    id: 'b',
    postIds: ['a', ...],
    ...
  }
}
```

Trong khi đó, MobX bởi Michel Weststrate lại chịu ảnh hưởng của lập trình hướng đối tượng, nhưng cũng một phần bởi lập trình phản ứng (Reactive programming). Nó đống gói state của bạn thành những observable. Vì thế bạn có mọi khả năng của một Observable trong state của bạn. Dữ liệu có thể chỉ cần có setter và getter thôi, nhưng observable làm cho chúng ta có khả năng nhận update khi dữ liệu thay đổi.

Trong MobX, state là **mutable**. Nghĩa là bạn thay đổi state trực tiếp:

```javascript
function addAuthor(author) {
  this.authors.push(author);
}
```

Thêm nữa, các entity tồn tại dưới một cấu trúc dữ liệu lồng nhau. Bạn không cần chuẩn hóa state. State được giữ không chuẩn hóa và có thể lồng nhiều tầng.

```javascript
{
  post: {
    id: 'a',
    ...
    author: {
      id: 'b',
      ...
    }
  }
}
```

### 1 Store và nhiều Store

Trong Redux bạn giữ mọi state trong một global store/global state. State object này là nguồn dữ liệu duy nhất của bạn. Mặt khác, chúng ta sử dụng nhiều reducer để thay đổi state này.

Trái lại, MobX lại dùng nhiều store. Tương tự như reducer của Redux, bạn có thể áp dụng chia để trị bằng cách phân bổ chúng thành nhiều tầng dữ liệu. Bạn có thể muốn có các domain entity trong một store riêng nhưng vẫn có khả năng kiểm soát state của view trong một trong các store của bạn. Sau cùng thì bạn là người quyết định và định hướng lại cấu trúc state nào có lợi cho ứng dụng của bạn nhất.

Trên lý thuyết bạn cũng có thể có nhiều store trong Redux. Không có ai bắt bạn phải dùng chỉ một store cả. Nhưng đó không phải là cách người ta khuyên dùng Redux. Nó sẽ làm trái lại những best practice nếu bạn dùng nhiều store. Trong Redux bạn chỉ cần có một store thôi và phản ứng với những thay đổi thông qua reducer và các global event.

### Implementation nhìn như thế nào?

Trong Redux, bạn sẽ cần đoạn code như dưới đây để thêm một user vào global state. Bạn có thể thấy chúng ta có thể sử dụng spread operator để trả về một state object mới. Bạn cũng có thể dùng Object.assign() để tạo ra một immutable object trong ES5.

```javascript
const initialState = {
  users: [
    {
      name: 'Dan'
    },
    {
      name: 'Michel'
    }
  ]
};

// reducer
function users(state = initialState, action) {
  switch (action.type) {
  case 'USER_ADD':
    return { ...state, users: [ ...state.users, action.user ] };
  default:
    return state;
  }
}

// action
{ type: 'USER_ADD', user: user };
```

Bạn sẽ cần phải gọi `dispatch({ type: 'USER_ADD', user: user });` để thêm một user mới vào global state.

Trong MobX, một store sẽ chỉ quản lý một substate (như một reducer trong Redux quản lý một substate) nhưng bạn có thể thay đổi state một cách trực tiếp. Annotation @observable giúp cho chúng ta có khả năng nhận update khi state thay đổi.

```javascript
class UserStore {
  @observable users = [
    {
      name: "Dan",
    },
    {
      name: "Michel",
    },
  ];
}
```

Giờ thì chúng ta có thể gọi userStore.users.push(user); vào một instance của store. Tuy vậy best practice đó là xử lý việc thay đổi state rõ ràng hơn với các action.

```javascript
class UserStore {
  @observable users = [
    {
      name: "Dan",
    },
    {
      name: "Michel",
    },
  ];

  @action addUser = user => {
    this.users.push(user);
  };
}
```

Bạn có thể bắt buộc việc sử dụng action bằng cách cấu hình Mobx với `configure({ enforceActions: true });`. Giờ thì bạn có thể thay đổi state bằng cách gọi `userStore.addUser(user);` với một instance của store.

Bạn đã thấy cách chúng ta cập nhật state trong cả Redux và MobX. Chúng rất khác nhau. Trong Redux state của bạn là read-only. Bạn chỉ có thể thay đổi state bằng các action rõ ràng. Ngược lại, state trong MobX lại có thể vừa read và vừa write. Bạn có thể thay đổi state trực tiếp mà không cần dùng action, nhưng bạn cũng có thể bắt buộc sử dụng action với cấu hình đã nói ở trên.

# Learning curve của quản lý state trong React

Cả Redux và MobX đều hầu hết được sử dụng trong các ứng dụng React. Nhưng bản chất của chúng thì là những thư viện quản lý state độc lập, và có thể được dùng mà không cần đến React. Chúng còn có những thư viện hỗ trợ tương thích để làm cho việc kết hợp với React component trở nên dễ dàng hơn, đó là react-redux cho Redux + React và mobx-react cho MobX + React.

Trong những thảo luận trên các diễn đàn công nghệ thì một vấn đề mà người ta hay nói đến đó là learning curve của Redux. Thường thì nó diễn ra trong bối cảnh mọi người bắt đầu học React nhưng đã muốn tìm hiểu là làm thế nào để quản lý state với Redux. Nhiều người sẽ cho rằng React và Redux nằm riêng thì có một learning curve khá tốt, nhưng kết hợp cả 2 lại thì chúng lại khó hiểu hơn nhiều. Vì thế MobX được coi là một giải pháp thay thế vì nó phù hợp hơn với những người mới học.

Tuy vậy, tôi muốn gợi ý một cách tiếp cận khác cho các bạn mới học React về vấn đề quản lý state, đó là bắt đầu với chính những tính năng quản lý state nội bộ của component. Trong một ứng dụng React, điều đầu tiên mà bạn sẽ học đó là các hàm nằm trong vòng đời của một component và làm thế nào để quản lý state bằng setState() và this.state. Đây là một cách học mà tôi đánh giá rất cao. Nếu không theo cách này, bạn sẽ rất dễ bị choáng ngợp bởi hệ sinh thái của React. Đến một thời điểm nào đó với cách học này, bạn sẽ nhận ra rằng việc quản lý các state nội bộ của component càng ngày càng trở nên khó hơn. Đó là lúc mà chúng ta trả lời câu hỏi: Vấn đề mà MobX và Redux giải quyết cho chúng ta là gì? Cả 2 đều cung cấp một cách để quản lý state của ứng dụng độc lập với các component. State được tách biệt hoàn toàn khỏi component. Component có thể truy cập state, thay đổi nó và nhận những cập nhật với state mới. State đó chính là single source of truth.

### Redux hay MobX cho người mới?

Một khi bạn đã quen với việc sử dụng component và quản lý state nội bộ, bạn có thể chọn một thư viện để giải quyết vấn đề này. Sau khi đã dùng cả 2 thư viện, tôi cho rằng MobX rất phù hợp đối với người mới. Chúng ta đều đã thấy MobX cần ít code hơn, dù cho nó sử dụng vài loại annotation mà có lẽ chúng ta chưa cần hiểu về chúng.

Với MobX bạn không cần phải làm quen với lập trình hàm hay phải hiểu những thuật ngữ như immutability. Lập trình hàm là một mô hình đang phát triển rất nhanh, nhưng lại xa lạ với hầu hết các lập trình viên Javascript. Dù thế giới lập trình đang dần được đẩy theo xu hướng này nhưng không phải ai cũng có kinh nghiệm về nó, nên các nguyên lý của MobX sẽ dễ dàng để hiểu hơn đối với những người đã biết về hướng đối tượng.

### Một ứng dụng đang phát triển

Trong MobX, bạn thay đổi object có annotation và component của bạn sẽ tự động render lại. MobX đem đến nhiều xử lý nội bộ hơn là Redux, nên sẽ làm cho nó dễ dùng hơn lúc đầu vì bạn phải viết ít code hơn. Nếu bạn đã biết Angular thì sẽ thấy dùng MobX giống như là two-way data binding vậy. Bạn giữ một vài state ở đâu đó, theo dõi state bằng annotation và để cho component tự update một khi state thay đổi.

```javascript
// component
<button onClick={() => store.users.push(user)} />
```

Cách tốt hơn để làm điều này đó là sử dụng [@action](https://viblo.asia/u/action) trong store.

```javascript
// component
<button onClick={() => store.addUser(user)} />

// store
@action addUser = (user) => {
  this.users.push(user);
}
```

Nó sẽ làm cho việc thay đổi state trở nên minh bạch hơn với các action. Hơn nữa chúng ta cũng có thể bắt buộc việc sử dụng action để thay đổi state bằng cách mà tôi đã nói ở trên.

```javascript
// root file
import { configure } from "mobx";

configure({ enforceActions: true });
```

Việc thay đổi state trực tiếp trong store như chúng ta đã làm ở ví dụ thứ nhất sẽ không còn hoạt động nữa. Việc sử dụng action là một trong các best practice của MobX. Hơn nữa một khi bạn chỉ dùng action, bạn đã áp dụng các ràng buộc của Redux.

Tôi xin gợi ý rằng chúng ta nên sử dụng MobX để bắt đầu một dự án. Một khi ứng dụng đã bắt đầu to lên, đó cũng là điều dễ hiểu khi chúng ta bắt buộc việc sử dụng các action. Điều này cũng đi theo đường lối của Redux đó là chúng ta không bao giờ thay đổi trực tiếp state mà lúc nào cũng phải thông qua các action.

### Chuyển sang Redux

Khi mà ứng dụng của bạn lớn dần và có thêm nhiều dev cùng làm việc, bạn nên chuyển qua dùng Redux. Bản chất của nó là việc nó bắt buộc sử dụng action để thay đổi state chứ không thông qua config như MobX. Action bao gồm kiểu và một payload và reducer có thể dùng để thay đổi state.

```javascript
// reducer
(state, action) => newState;
```

Redux cung cấp cho bạn cả một cấu trúc để quản lý state với những ràng buộc rõ ràng. Đó là [lý do mà Redux rất thành công.](https://www.youtube.com/watch?v=uvAXVMwHJXU)

Một điểm mạnh khác của Redux đó là việc sử dụng nó ở server side. Bởi vì chúng ta đang làm việc với Javascript object, bạn có thể gửi state qua mạng được. Serialize và deserialize các state object hoạt động một cách tự động mà bạn không cần làm thêm gì cả. Bạn cũng có thể làm như thế với MobX nữa.

MobX thì không có nhiều ràng buộc nhưng bạn cũng có thể tự tạo ra chúng bằng các config. Đó là lí do tại sao tôi không nói là bạn không thể dùng MobX với những ứng dụng lớn, nhưng Redux thì giúp chúng ta có một cách làm nhất quán hơn. Doc của MobX cũng có nói là: "MobX không hướng dẫn cho bạn cách bạn cấu trúc code, lưu state ở đâu hay xử lý các event như thế nào." Team của bạn cần phải tự cấu trúc việc quản lý state nếu sử dụng thư viện này.

Cuối cùng thì việc học quản lý state không khó như chúng ta nghĩ. Để tóm gọn lại vấn đề, một người mới học React đầu tiên sẽ học cách sử dụng setState() và this.state. Sau một thời gian thì họ sẽ thấy khó khăn với việc chỉ dùng setState() để quản lý state cho cả ứng dụng. Khi đi tìm giải pháp, họ gặp được những thư viện như MobX hay Redux. Nhưng nên chọn cái nào bây giờ? Bởi vì MobX có ít ràng buộc hơn, cần ít code hơn và dùng cũng tương tự như setState(), tôi nghĩ nó rất thích hợp với các ứng dụng vừa và nhỏ. Một khi ứng dụng đã to dần lên, bạn nên xem xét việc tạo ra thêm ràng buộc bằng config trong MobX hoặc chuyển sang dùng Redux.

# Lời kết

Mỗi khi tôi đọc comment về tranh luận giữa Redux và MobX, luôn luôn có 1 comment kiểu này: "Redux có quá nhiều code thừa, bạn nên dùng MobX đi. Tôi đã bỏ được XXX dòng code đấy." Comment này có thể đúng, nhưng họ chưa xem xét đến những sự đánh đổi. Redux có nhiều code thừa hơn MobX, vì nó được thêm vào vì những ràng buộc cụ thể trong thiết kế. Nó cho phép bạn có cái nhìn tổng quan hơn về state của ứng dụng dù ứng dụng đó lớn thế nào. Không phải tự nhiên mà nó là một trong những thư viện phổ biến nhất đâu.

Thư viện Redux có kích thước khá là nhỏ. Hầu hết thời gian bạn sẽ dành để xử lý Javascript object và array. Nó giống với Javascript thuần hơn là MobX. Trong MobX, chúng ta gói object và array vào trong observable object và điều này giấu đi hầu hết các boilerplate code. Nó được xây dựng dựa trên tính trừu tượng ẩn. Nó sẽ thực hiện một phép thuật nào đó và code bạn tự nhiên chạy được, nhưng đồng thời cũng làm cho các cơ chế ở tầng dưới trở nên khó hiểu hơn nhiều. Với Redux thì chúng ta test và debug ứng dụng dễ hơn vì nó chỉ sử dụng Javascript thuần.

Trong khi với Redux, chúng ta có một cách nhất định để làm mọi thứ thì MobX lại ít ràng buộc hơn. Nhưng dù vậy chúng ta vẫn nên tuân theo các best practice trong MobX, vì như thế sẽ dễ dàng hơn trong việc lí giải thay đổi của state.

Cả 2 thư viện đều rất tốt. Trong khi Redux đã được chứng minh trong thế giới React, MobX đang dần trở thành một giải pháp thay thế đáng chú ý.
]]></description>
            <link>https://hungvn.com/blog/redux-hay-mobx-ly-giai-su-nham-lan</link>
            <guid isPermaLink="true">https://hungvn.com/blog/redux-hay-mobx-ly-giai-su-nham-lan</guid>
            <pubDate>Thu, 06 Sep 2018 07:18:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách tối ưu trang web của bạn với nén Gzip]]></title>
            <description><![CDATA[
Nén là một phương pháp đơn giản, hiệu quả để tiết kiệm băng thông và tăng tốc trang web của bạn. Tôi đã ngần ngại khi gợi ý sử dụng nén gzip khi [tăng tốc tải file javascript của bạn](https://betterexplained.com/articles/speed-up-your-javascript-load-time/) vì một vài vấn đề ở trình duyệt cũ.

Nhưng giờ là thế kỷ 21. Hầu hết các truy cập đến trang của tôi đều từ các trình duyệt hiện đại, và thẳng thắn mà nói, hầu hết người dùng của tôi đều am hiểu công nghệ. Tôi không muốn làm mọi người chậm lại vì một vài người đang bám lấy IE 4 trên Windows 95. Google và Yahoo dùng nén gzip. Một trình duyệt hiện đại cần được tận hưởng nội dung và tốc độ của web hiện đại - vậy thì sử dụng gzip mã hóa nó. Dưới đây là cách cài đặt.

## Khoan, khoan, khoan: tại sao chúng ta lại làm điều này?

Trước khi chúng ta bắt đầu, tôi nên giải thích nội dung được mã hóa là gì. Khi bạn yêu cầu một file, ví dụ như `http://www.yahoo.com/index.html`, trình duyệt của bạn nói chuyện với một web server. Đoạn hội thoại sẽ diễn ra kiểu như sau:

![](https://betterexplained.com/wp-content/uploads/compression/HTTP_request.png)

1.  Trình duyệt: Này, **GET** cho tôi /index.html
2.  Server: Ok, để tôi tìm xem index.html có không
3.  Server: Tìm thấy rồi! Mã phản hồi của anh đây (200 OK) và tôi đang gửi file.
4.  Trình duyệt: 100KB? Ôi... chờ tí, chờ tí... ok, tải được rồi nhé.

Dĩ nhiên, header và giao thức thực tế sẽ hình thức hơn nhiều (quan sát chúng với [Live HTTP Headers](https://betterexplained.com/articles/how-to-debug-web-applications-with-firefox/) nếu bạn muốn).

Nhưng nó hoạt động, và bạn nhận được file.

## Thế vấn đề là gì?

Chà, hệ thống hoạt động, nhưng không hiệu quả. 100KB là **một đống text**, và thành thật thì, HTML khá là trùng lặp. Mỗi thẻ `<html>`, `<table>` và `<div>` đều có một thẻ đóng gần như tương tự. Các từ lặp đi lặp lại trong cả document. Bạn chia nó ra như thế nào thì HTML (và người anh em mạnh mẽ của nó, XML) đều không tinh gọn.

Và xử lý thế nào với một file quá lớn? Nén nó!

Nếu chúng ta có thể gửi một file .zip đến trình duyệt (index.html.zip) thay vì index.html thông thường, chúng ta sẽ tiết kiệm được băng thông và thời gian tải. Trình duyệt có thể tải file đã nén, giải nén nó, và sau đó hiển thị cho người dùng, người đang có tâm trạng tốt vì trang tải nhanh. Đoạn hội thoại giữa trình duyệt và server sẽ trông như sau:

![](https://betterexplained.com/wp-content/uploads/compression/HTTP_request_compressed.png)

1.  Trình duyệt: Này, tôi có thể **GET** index.html không? Tôi sẽ lấy phiên bản nén của nó nếu anh có.
2.  Server: Để tôi tìm... ừ, có đây. Và anh sẽ lấy bản nén? Tuyệt.
3.  Server: Ok, tôi tìm thấy index.html (200 OK), và tôi đang nén và gửi nó qua cho anh.
4.  Trình duyệt: Tuyệt! Chỉ có mỗi 10KB. Tôi sẽ giải nén và hiển thị cho người dùng.

Công thức rất đơn giản: File nhỏ hơn = tải nhanh hơn = **người dùng hạnh phúc**.

Không tin tôi à? Phần HTML của trang chủ của Yahoo giảm từ 101KB xuống còn 15KB sau khi nén:

![](https://betterexplained.com/wp-content/uploads/compression/yahoo.png)

## Chi tiết (không quá) lằng nhằng

Phần khó trong quá trình trao đổi này là trình duyệt và server phải biết rằng việc gửi nhận file nén là được chấp nhận. Việc đồng ý này bao gồm 2 phần

- **Trình duyệt gửi một header** nói với server rằng nó chấp nhận nội dung được nén (gzip và deflate là 2 cách nén): `Accept-Encoding: gzip, deflate`
- **Server gửi một phản hồi** nếu nội dung thực sự được nén: `Content-Encoding: gzip`

Nếu server không gửi content-encoding trong header của phản hồi, điều đó có nghĩa là file không được nén (điều mặc định ở nhiều server). Header "Accept-Encoding" chỉ là một yêu cầu từ trình duyệt, không phải mệnh lệnh. Nếu server không muốn gửi về nội dung được nén, trình duyệt sẽ phải tải về phiên bản nặng nề thông thường.

## Thiết lập server

"Tin tốt" là chúng ta không thể kiểm soát được trình duyệt. Nó sẽ gửi header `Accept-Encoding: gzip, deflate` hoặc là không.

Công việc của chúng ta là cấu hình server để nó trả về nội dung được nén nếu trình duyệt có thể xử lý, tiết kiệm băng thông cho mọi người (và đem lại một người dùng hạnh phúc).

Đối với IIS, [bật cấu hình nén](<https://technet.microsoft.com/en-us/library/cc771003(WS.10).aspx>) ở trong cài đặt.

Trong Apache, [bật cấu hình nén nội dung xuất](https://httpd.apache.org/docs/2.0/mod/mod_deflate.html) khá là đơn giản. Thêm các dòng sau vào file .htaccess:

```javascript
# compress text, html, javascript, css, xml:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript

# Or, compress certain file types by extension:
<files *.html>
SetOutputFilter DEFLATE
</files>
```

Apache có 2 tùy chọn nén:

- **mod_deflate** dễ dàng cài đặt và là chuẩn.
- **mod_gzip** có vẻ mạnh hơn: bạn có thể nén trước nội dung.

Deflate nhanh và hoạt động được, nên tôi sử dụng nó; dùng mod_gzip nếu bạn thấy thích. Trong cả 2 trường hợp, Apache đều kiểm tra xem trình duyệt có gửi header "Accept-Encoding" không và gửi lại phiên bản nén hoặc phiên bản thường của file. tuy nhiên, một số trình duyệt cũ sẽ phát sinh vấn đề (chi tiết bên dưới) và có một số chỉ lệnh đặc biệt mà bạn có thể thêm vào để sửa.

Nếu bạn không thể thay đổi file .htaccess, bạn có thể [dùng PHP](https://perishablepress.com/press/2007/03/26/fast-effective-php-compression/) để trả về nội dung nén. Thêm phần mở rộng .php vào file html của bạn và thêm đoạn code này ở đầu file:

```php
<?php
if (substr_count($_SERVER[‘HTTP_ACCEPT_ENCODING’], ‘gzip’))
   ob_start(“ob_gzhandler”);
else ob_start();
?>
```

Chúng ta kiểm tra header "Accept-Encoding" và trả về phiên bản nén gzip của file (ngược lại là phiên bản thường). Việc này gần như là tự xây dựng webserver của bạn (rất thú vị!). Nhưng thực sự thì, hãy thử sử dụng Apache để nén nội dung trả về nến bạn có thể. Bạn không muốn nghịch ngợm mấy file của mình đâu.

## Xác minh nội dung nén của bạn

Khi bạn đã cấu hình xong server của mình, hãy kiểm tra để đảm bảo rằng bạn thực sự trả về nội dung nén.

- **Online**: sử dụng [công cụ kiểm tra gzip online](http://www.gidnetwork.com/tools/gzip-test.php) để kiểm tra liệu trang của bạn có được nén không.
- **Trên trình duyệt**: trong Chrome, mở Developer Tools > Network (Firefox/IE sẽ tương tự). Tải lại trang, và nhấn vào dòng network tương ứng với trang (ví dụ www.google.com). Header `Content-Encoding: gzip` nghĩa là nội dung trả về đã được nén.

![](https://betterexplained.com/wp-content/uploads/2007/04/chrome-gzip-header.png)

Nhấn biểu tượng "Use large rows" để hiển thị thêm thông tin, bao gồm cả kích cỡ file nén và kích cõ thực.

![](https://betterexplained.com/wp-content/uploads/2007/04/request-size.png)

Hãy chuẩn bị cho điều kỳ diệu ở kết quả. [Trang chủ của instacalc](http://instacalc.com/) thu lại từ 36k xuống còn 10k, giảm 75% kích cỡ.

## Thử một số ví dụ

Tôi đã làm một số trang và một [ví dụ cho phép tải về](https://betterexplained.com/examples/compressed/compression-example.zip):

- [index.html](https://betterexplained.com/examples/compressed/index.html) - không nén (trên server này, tôi mặc định sử dụng nén)
- [index.htm](https://betterexplained.com/examples/compressed/index.htm) - nén với Apache .htaccess sử dụng luật \*.htm
- [index.php](https://betterexplained.com/examples/compressed/index.php) - nén sử dụng PHP header

Cứ thoải mái tải file, để chúng trong server của bạn và chỉnh sửa các cài đặt.

## Lưu ý

Dù khá thú vị nhưng HTTP Compression cũng chứa một số vấn đề. Dưới đây là những thứ cần phải coi chừng:

- **Trình duyệt cũ**: Phải, một số trình duyệt vẫn còn có rắc rối với nội dung nén (chúng nói rằng có thể chấp nhận nội dung nén, nhưng thực sự thì không thể). Nếu trang của bạn bắt buộc phải hoạt động với Netscape 1.0 trên Windows 95, bạn có lẽ sẽ không muốn dùng HTTP Compression. Apache mod_deflate có [một số luật](https://httpd.apache.org/docs/2.0/mod/mod_deflate.html#recommended) cho phép tránh việc nén trên một số trình duyệt cũ.
- **Nội dung đã nén**: Hầu hết ảnh, nhạc và video đều đã được nén. Đừng tốn thời gian nén chúng lần nữa. Trên thực tế, bạn sẽ chỉ muốn nén "big 3" (HTML, CSS và Javascript).
- **CPU-load**: nén nội dung khi nhận được yêu cầu sẽ tiêu tốn thời gian của CPU và tiết kiệm băng thông. Thường thì đây là sự đánh đổi tốt nếu biết tốc độ nén. Có nhiều cách để nén trước các nội dung tĩnh và gửi các bản nén này. Việc này cần được cấu hình thêm; cho dù không thể thì việc nén nội dung trả về vẫn là điều tốt. Sử dụng CPU cho người dùng có trải nghiệm nhanh hơn cũng khá là đáng, khi sự chú ý không đáng kể.

Nén là một trong những cách nhanh nhất để cải thiện hiệu năng cho trang web của bạn. Hãy đi, cài đặt, và để cho người dùng của bạn thận hưởng lợi ích nó mang lại.
]]></description>
            <link>https://hungvn.com/blog/cach-toi-uu-trang-web-cua-ban-voi-nen-gzip</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-toi-uu-trang-web-cua-ban-voi-nen-gzip</guid>
            <pubDate>Tue, 07 Aug 2018 20:45:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Functional trong Javascript với ES6 Recursive Patterns]]></title>
            <description><![CDATA[
### What’s the deal here?

Functional programming has been on the rise and is a topic that is very exciting to me. It allows me to write terse, declarative code that is easy to test and reason about. What is functional programming? I’ll defer that answer to someone with more knowledge on the subject, [Eric Elliot](https://medium.com/@_ericelliott):

> **Functional programming** (often abbreviated FP) is the process of building software by composing **pure functions**, avoiding **shared state,** **mutable data**,and **side-effects**. Functional programming is **declarative** rather than **imperative**, and application state flows through pure functions. Contrast with object oriented programming, where application state is usually shared and colocated with methods in objects.

ES6 brings many features that allow us to easily write pure functions, rest/spread being one of the most powerful. Using [rest params](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), we’re able to “loop without loops” with [recursion](https://en.wikipedia.org/wiki/Recursion_%28computer_science%29). In this article, we’re going to rewrite many commonly used JavaScript methods/functions that allow for functional patterns.

### Preface

The following functions are for demonstration and learning purposes. Many functions below are tail-recursive and should be optimized further. Fixing tail-recursion is not the subject of this article. ES6 brings tail-call optimization, but must be used in conjunction with `'use strict'` .

### Head

Return the first item in an array. Is useful when you need to separate the first item from the rest of the array items. To do this, we make use of [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment).

```javascript
const head = ([x]) => x;
```

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
head(array); // 1
```

### Tail

Return all but the first item in an array.

```javascript
const tail = ([, ...xs]) => xs;
```

Which is essentially the same as writing:

```javascript
const tail = ([x, ...xs]) => xs;
```

Since we don’t need to use `x` in the returned output, we can drop it, but keep the comma to get the rest of the items in the array.

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
tail(array); // [2,3,4,5]
```

### Def

Return if argument supplied is defined.

```javascript
const def = x => typeof x !== "undefined";
```

Example usage:

```javascript
const defined = "this is defined";
def(defined); // true
def(doesntExist); // false
```

### Undef

Return if argument supplied is undefined.

```javascript
const undef = x => !def(x);
```

Example usage:

```javascript
const defined = "this is defined";
undef(defined); // false
undef(doesntExist); // true
```

### Copy

Returns a copy of an array without using `Array.slice()`. Makes use of [spread](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator).

```javascript
const copy = array => [...array];
```

Example usage:

```javascript
let array = [1, 2, 3, 4, 5];
let copied = copy(array);
copied.push(6);

array; // [1,2,3,4,5]
copied; // [1,2,3,4,5,6]
```

### Length

Return the length of an array. This is a very simple form of looping through an array with recursion, even though the values of the array don’t matter in this case (increments up starting at 1 for every item in array). We include the **len** param to avoid [tail recursion](https://en.wikipedia.org/wiki/Tail_call).

```javascript
const length = ([x, ...xs], len = 0) => (def(x) ? length(xs, len + 1) : len);
```

If we don’t care about tail recursion, we can write it as:

```javascript
const length = ([x, ...xs]) => (def(x) ? 1 + length(xs) : 0);
```

This would add a stack frame for each item in the array, whereas the version that avoids tail recursion, replaces a single stack frame. If the array passed in is large enough, it will throw “Maximum call stack size exceeded”.

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
length(array); // 5
```

### Reverse

Return a reversed array.

```javascript
const reverse = ([x, ...xs]) => (def(x) ? [...reverse(xs), x] : []);
```

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
reverse(array); // [5,4,3,2,1]
```

`Array.reverse()` is okay, but it modifies the value in place which is a side-effect. Consider the following:

```javascript
const array = [1, 2, 3, 4, 5];

const newArray = array.reverse(); // [5,4,3,2,1]
array; // [5,4,3,2,1]

// using the reverse method we just created
const array2 = [1, 2, 3, 4, 5];

const newArray2 = reverse(array2); // [5,4,3,2,1]
array2; // [1,2,3,4,5]
```

### First

Returns a new array that contains the first n items of the given array.

```javascript
const first = ([x, ...xs], n = 1) => (def(x) && n ? [x, ...first(xs, n - 1)] : []);
```

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
first(array, 3); // [1,2,3]
```

### Last

Returns a new array that contains the last n items of the given array.

```javascript
const last = (xs, n = 1) => reverse(first(reverse(xs), n));
```

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
last(array, 3); // [3,4,5]
```

### Slice

Returns a new array with value inserted at given index.

```javascript
const slice = ([x, ...xs], i, y, curr = 0) =>
  def(x)
    ? curr === i
      ? [y, x, ...slice(xs, i, y, curr + 1)]
      : [x, ...slice(xs, i, y, curr + 1)]
    : [];
```

Example usage:

```javascript
const array = [1, 2, 4, 5];
slice(array, 2, 3); // [1,2,3,4,5]
```

### isArray

Returns if the value supplied is an array. Allows us to write `Array.isArray()` in a more functional manner.

```javascript
const isArray = x => Array.isArray(x);
```

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
isArray(array); // true
```

### Flatten

Combines nested arrays into a single array.

```javascript
const flatten = ([x, ...xs]) =>
  def(x) ? (isArray(x) ? [...flatten(x), ...flatten(xs)] : [x, ...flatten(xs)]) : [];
```

Example usage:

```javascript
const array1 = [1, 2, 3];
const array2 = [4, [5, [6]]];
flatten([array1, array2]); // [1,2,3,4,5,6]
```

### Swap

Return a new array with 2 items swapped based on their index.

```javascript
const swap = (a, i, j) =>
  map(a, (x, y) => {
    if (y === i) return a[j];
    if (y === j) return a[i];
    return x;
  });
```

Example usage:

```javascript
const array = [1, 2, 3, 4, 5];
swap(array, 0, 4); // [5,2,3,4,1]
```

### Map

From MDN: “…creates a new array with the results of calling a provided function on every element in this array.”

```javascript
const map = ([x, ...xs], fn) => {
  if (undef(x)) return [];
  return [fn(x), ...map(xs, fn)];
};
```

Which can be simplified as:

```javascript
const map = ([x, ...xs], fn) => (def(x) ? [fn(x), ...map(xs, fn)] : []);
```

Example usage:

```javascript
const double = x => x * 2;
map([1, 2, 3], double); // [2,4,6]
```

### Filter

From MDN: “…creates a new array with all elements that pass the test implemented by the provided function.”

```javascript
const filter = ([x, ...xs], fn) => {
  if (undef(x)) return [];
  if (fn(x)) {
    return [x, ...filter(xs, fn)];
  } else {
    return [...filter(xs, fn)];
  }
};
```

Which can be simplified as:

```javascript
const filter = ([x, ...xs], fn) =>
  def(x) ? (fn(x) ? [x, ...filter(xs, fn)] : [...filter(xs, fn)]) : [];
```

Example usage:

```javascript
const even = x => x % 2 === 0;
const odd = (x = !even(x));
const array = [1, 2, 3, 4, 5];

filter(array, even); // [2,4]
filter(array, odd); // [1,3,5]
```

### Reject

The opposite of filter, returns an array that does not pass the filter function.

```javascript
const reject = ([x, ...xs], fn) => {
  if (undef(x)) return [];
  if (!fn(x)) {
    return [x, ...reject(xs, fn)];
  } else {
    return [...reject(xs, fn)];
  }
};
```

Example usage:

```javascript
const even = x => x % 2 === 0;
const array = [1, 2, 3, 4, 5];

reject(array, even); // [1,3,5]
```

### Partition

Splits an array into two arrays. One whose items pass a filter function and one whose items fail.

```javascript
const partition = (xs, fn) => [filter(xs, fn), reject(xs, fn)];
```

Example usage:

```javascript
const even = x => x % 2 === 0;
const array = [0, 1, 2, 3, 4, 5];

partition(array, even); // [[0,2,4], [1,3,5]]
```

### Reduce

From MDN: “…applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.”

```javascript
const reduce = ([x, ...xs], fn, memo, i) => {
  if (undef(x)) return memo;
  return reduce(xs, fn, fn(memo, x, i), i + 1);
};
```

Which can be simplified as:

```javascript
const reduce = ([x, ...xs], fn, memo, i = 0) =>
  def(x) ? reduce(xs, fn, fn(memo, x, i), i + 1) : memo;
```

Example usage:

```javascript
const sum = (memo, x) => memo + x;
reduce([1, 2, 3], sum, 0); // 6

const flatten = (memo, x) => memo.concat(x);
reduce([4, 5, 6], flatten, [1, 2, 3]); // [1,2,3,4,5,6]
```

### ReduceRight

Similar to reduce, but applies the function from right-to-left.

```javascript
const reduceRight = (xs, fn, memo) => reduce(reverse(xs), fn, memo);
```

Example usage:

```javascript
const flatten = (memo, x) => memo.concat(x);

reduceRight(
  [
    [0, 1],
    [2, 3],
    [4, 5],
  ],
  flatten,
  []
); // [4, 5, 2, 3, 0, 1]
```

### Partial

Partially apply a function by filling in any number of its arguments.

```javascript
const partial =
  (fn, ...args) =>
  (...newArgs) =>
    fn(...args, ...newArgs);
```

Example usage:

```javascript
const add = (x, y) => x + y;
const add5to = partial(add, 5);

add5to(10); // 15
```

### SpreadArg

Convert function that takes an array to one that takes multiple arguments. This is useful when partially applying.

```javascript
const spreadArg =
  fn =>
  (...args) =>
    fn(args);
```

Example usage:

```javascript
const add = ([x, ...xs]) => (def(x) ? parseInt(x + add(xs)) : []);
add([1, 2, 3, 4, 5]); // 15

const spreadAdd = spreadArg(add);
spreadAdd(1, 2, 3, 4, 5); // 15
```

If you only want to define a single function you can write it as:

```javascript
const add = spreadArg(([x, ...xs]) => (def(x) ? parseInt(x + add(...xs)) : []));
add(1, 2, 3, 4, 5); // 15
```

In the above, you need to remember to spread the array you are sending into the function recursively, since you are spreading the argument.

### ReverseArgs

Reverse function argument order.

```javascript
const reverseArgs =
  fn =>
  (...args) =>
    fn(...reverse(args));
```

Example usage:

```javascript
const divide = (x, y) => x / y;
divide(100, 10); // 10

const reverseDivide = reverseArgs(divide);
reverseDivide(100, 10); // 0.1
```

Reversing arguments can be useful when partially applying arguments. Sometimes you want to partially apply arguments at the end of the list, not those at the beginning. Reversing the arguments allows us to do that.

```javascript
const percentToDec = partial(reverseDivide, 100);

percentToDec(25); // 0.25
```

### Pluck

Extract property value from array. Useful when combined with the **map** function.

```javascript
const pluck = (key, object) => object[key];
```

Example usage:

```javascript
const product = { price: 15 };
pluck("price", product); // 15

const getPrices = partial(pluck, "price");
const products = [{ price: 10 }, { price: 5 }, { price: 1 }];
map(products, getPrices); // [10,5,1]
```

### Flow

Each function consumes the return value of the function that came before.

```javascript
const flow =
  (...args) =>
  init =>
    reduce(args, (memo, fn) => fn(memo), init);
```

Example usage:

```javascript
const getPrice = partial(pluck, "price");
const discount = x => x * 0.9;
const tax = x => x + x * 0.075;
const getFinalPrice = flow(getPrice, discount, tax);

// looks like: tax(discount(getPrice(x)))
// -> get price
// -> apply discount
// -> apply taxes to discounted price

const products = [{ price: 10 }, { price: 5 }, { price: 1 }];

map(products, getFinalPrice); // [9.675, 4.8375, 0.9675]
```

### Compose

The same as flow, but arguments are applied in the reverse order. Compose matches up more naturally with how functions are written. Using the same data as defined for the **flow** function:

```javascript
const compose = (...args) => flow(...reverse(args));
```

Example usage:

```javascript
const getFinalPrice = compose(tax, discount, getPrice);

// looks like: tax(discount(getPrice(x)))

map(products, getFinalPrice); // [9.675, 4.8375, 0.9675]
```

### Min

Return the smallest number in an array. Returns **Infinity** if array supplied is empty.

```javascript
const min = ([x, ...xs], result = Infinity) =>
  def(x) ? (x < result ? min(xs, x) : result) : result;
```

Example usage:

```javascript
const array = [0, 1, 2, 3, 4, 5];

min(array); // 0
```

### Max

Return the largest number in an array. Returns **-Infinity** if array supplied is empty.

```javascript
const max = ([x, ...xs], result = -Infinity) =>
  def(x) ? (x > result ? max(xs, x) : max(xs, result)) : result;
```

Example usage:

```javascript
const array = [0, 1, 2, 3, 4, 5];

max(array); // 5
```

### Factorial

Returns the factorial of a number. Uses an accumulator to allow replacing of stack frames to allow larger factorials to be returned.

```javascript
const factorial = (x, acum = 1) => (x ? factorial(x - 1, x * acum) : acum);
```

Example usage:

```javascript
factorial(5); // 120
```

### Fibonacci

Returns the Fibonacci number at the given place.

```javascript
const fib = x => (x > 2 ? fib(x - 1) + fib(x - 2) : 1);
```

Example usage:

```javascript
fib(15); // 610
```

### Quicksort

Sort an array from smallest to largest. This is done by re-ordering the array so that it contains two sub-arrays, one with smaller values, the other with larger values. The above steps are recursively applied to each sub-array until there are no arrays left, which is flatten to return a sorted array.

```javascript
const quicksort = xs =>
  length(xs)
    ? flatten([
        quicksort(filter(tail(xs), x => x <= head(xs))),
        head(xs),
        quicksort(filter(tail(xs), x => x > head(xs))),
      ])
    : [];
```

This can also be implemented using **partition**, but requires variable assignment.

```javascript
const quicksort = array => {
  if (!length(array)) return [];
  const [less, more] = partition(tail(array), x => x < head(array));
  return flatten([quicksort(less), head(array), quicksort(more)]);
};
```

Example usage:

```javascript
const array = [8, 2, 6, 4, 1];

quicksort(array); // [1,2,4,6,8]
```

### Everything as a Reduction

Many of the functions above can be converted into reductions, which should increase performance in most, if not all cases. This also shows the flexibility of the **reduce** function.

```javascript
const reduce = ([x, ...xs], f, memo, i = 0) =>
  def(x) ? reduce(xs, f, f(memo, x, i), i + 1) : memo;

const reverse = xs => reduce(xs, (memo, x) => [x, ...memo], []);

const length = xs => reduce(xs, (memo, x) => memo + 1, 0);

const map = (xs, fn) => reduce(xs, (memo, x) => [...memo, fn(x)], []);

const filter = (xs, fn) => reduce(xs, (memo, x) => (fn(x) ? [...memo, x] : [...memo]), []);

const reject = (xs, fn) => reduce(xs, (memo, x) => (fn(x) ? [...memo] : [...memo, x]), []);

const first = (xs, n) => reduce(xs, (memo, x, i) => (i < n ? [...memo, x] : [...memo]), []);

const last = (xs, n) =>
  reduce(xs, (memo, x, i) => (i >= length(xs) - n ? [...memo, x] : [...memo]), []);

const merge = spreadArg(xs => reduce(xs, (memo, x) => [...memo, ...x], []));

const flatten = xs =>
  reduce(xs, (memo, x) => (x ? (isArray(x) ? [...memo, ...flatten(x)] : [...memo, x]) : []), []);

const add = spreadArg(([x, ...xs]) => reduce(xs, (memo, y) => memo + y, x));

const divide = spreadArg(([x, ...xs]) => reduce(xs, (memo, y) => memo / y, x));

const multiply = spreadArg(([x, ...xs]) => reduce(xs, (memo, y) => memo * y, x));
```

Example usage:

```javascript
reverse([1, 2, 3]); // [3,2,1]
length([1, 2, 3]); // 3
map([1, 2, 3], double); // [2,3,4]
filter([1, 2, 3, 4], even); // [2,4]
reject([1, 2, 3, 4], even); // [1,3]
first([1, 2, 3, 4], 3); // [1,2,3]
last([1, 2, 3, 4], 2); // [3,4]
merge([1, 2, 3], [4, 5, 6]); // [1,2,3,4,5,6]
flatten([1, [2, 3, [4, [5, [[6]]]]]]); // [1,2,3,4,5,6]
add(1, 2, 3, 4, 5); // 15
multiply(2, 5, 10); // 100
divide(100, 2, 5); // 10
```

![](https://cdn-images-1.medium.com/max/800/1*4877k4Hq9dPdtmvg9hnGFA.jpeg)

### Wrapping Up

I hope this article helps shed insight on some of the patterns made available with JavaScript and ES6. Many problems that can be solved with iteration/loops, can also be solved functionally through recursion. I hope this article was also able to show you the flexibility of the reduce function.
]]></description>
            <link>https://hungvn.com/blog/functional-trong-javascript-voi-es6-recursive-patterns</link>
            <guid isPermaLink="true">https://hungvn.com/blog/functional-trong-javascript-voi-es6-recursive-patterns</guid>
            <pubDate>Tue, 24 Jul 2018 12:28:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Object, Function, Method, Constructor in JavaScript]]></title>
            <description><![CDATA[
**TL;DR**

Lưu ý một chút về cách trình bày: `.propname` tức là public property có tên là "propname" của một đối tượng

## Bắt đầu với Object, Function và Method

- JavaScript's object giống như một cái túi (hay một vùng nhớ) chứa các property (thuộc tính) ở bên trong nó. Những property trong JavaScript đều public và được lưu trữ theo cấu trúc **Mapping (tức key-value pair)**.
- Function trong JavaScript được xem là first-class object (cũng tương tự như object và ta sẽ gọi nó là **functionObject**).
- Chính vì JavaScript's function được xem như object nên ta có thể return (trả về), pass to parameter (truyền vào function khác thông qua đối số), store in variable (lưu trữ trong biến) or store in Object's property (lưu trữ trong property của Object => lúc đó function được gọi là method),...

## Prototypes

- Prototype của object là một internal property (có thể hiểu là một property nội tại ẩn bên trong), ta sẽ gọi nó là `{Prototype}`. JavaScript standard không cung cấp cách thức để truy xuất `**{Prototype}**` property từ một object. **Lưu ý `{Prototype}` bản thân nó cũng là một object**.
- Giống như bao ngôn ngữ lập trình OOP khác, JavaScript có thể tạo object từ một function được gọi là **constructor**.
- Vì constructor là function và là functionObject nên nó cũng có `{Prototype}` property.
- JavaScript standard cung cấp một public property cho functionObject là `.prototype` để truy xuất prototype của function.**Lưu ý đối tượng được truy xuất thông qua public property `.prototype` không phải là `{Prototype}` property của functionObject**.

### Properties lookup

- JavaScript's object có thể ủy thác một số property của nó cho `{Prototype}`. Và bản thân `{Prototype}` cũng làm tương tự; Tất cả đều hướng đến Build-in `Object.prototype`. **Lưu ý Build-in `Object.prototype` bằng _null_**

```
object --chứa--> {Prototype}
và bản thân {Prototype} cũng là object
{Prototype} --chứa--> {Prototype}'s {Prototype}
và bản thân {Prototype}'s {Prototype} cũng là object
{Prototype}'s {Prototype} --chứa--> {Prototype}'s {Prototype}'s {Prototype}
.....
..... --chứa--> Build-in Object.prototype
(end)
```

- Hiện tượng trên người ta gọi là Inheritance (kế thừa) trong JavaScript thông qua prototype. Do đó JavaScript là một **prototype-base OOP language**
- Ở ví dụ trên, ta thấy xảy ra đệ quy, người ta gọi là `**{Prototype} chain**`. tức duyệt xuyên suốt các `{Prototype}`
- Khi gọi một property ra từ object thì đầu tiên hệ thống sẽ kiểm tra xem property đó có nằm trong object đó không. Nếu không, chúng sẽ chuyển hướng qua tìm property đó trong object's `{Prototype}`. Quá trình đệ quy cứ thế được thực hiện cho đến khi tìm đến Build-in Object.prototype thì dừng lại.

### Setting properties

- Khi một property được set giá trị, property đó không có trong object thì nó sẽ được tạo mới, hệ thống tự động bỏ qua việc tìm kiếm nó trong `{Prototype}`. Property mới được thêm vào object sẽ làm mờ nhạt property trùng tên (nếu có) trong `{Prototype}` chain
- `{Prototype}` của object bị ảnh hưởng khá mạnh bởi public property `.prototype` của constructor. Ta có thể quyết định `{Prototype}` của một object thông qua việc điều chỉnh `.prototype` property của constructor.
- Khi constructor được gọi thực thi (hay nói cách khác function được gọi theo Constructor Format) (xem phần **footnotes**) thì một object mới được sinh ra. `{Prototype}` của object mới và public property `.prototype` của constructor sẽ tham chiếu cùng một đối tượng.

## Tiếp theo sẽ là gì? Ta cùng hình dung

Trước tiên sẽ là mối liên quan giữa public property `.prototype` và `{Prototype}`. hình ellipse biểu diễn object, mũi tên biểu diễn property của object đó tham chiếu đến một object khác. `{Prototype}` chain sẽ được tô mũi tên mày xanh lá.

### 1: Define constructor:

```javascript
function MyConstructor() {}
```

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/rkuzvvigqw_1.png)

Ta dễ dàng thấy MyConstructor được biểu diễn trong hình Ellipse, tức nó là function và là functionObject và sẽ được dùng như constructor.

**Ghi nhớ rằng**: chỉ những public property `.prototype` của functionObject, là những object mặc định sở hữu public property `.constructor`  
Tức là theo ví dụ trên: MyConstructor.prototype là giá trị mặc định cho property `.prototype` của MyConstructor. Và nó mặc định sở hữu property `.constructor` trỏ ngược về MyConstructor

Phần còn lại trong bức ảnh minh họa rõ ràng những khái niệm đã đề cập ở phần đầu bài viết

Bước kế tiếp ta sẽ bỏ qua phần `{Prototype}` chain của MyConstructor cho gọn, vì chúng không thay đổi và cũng không liên quan đến những gì được trình kế tiếp sau đây.

### 2: Assign new prototype property:

```javascript
MyConstructor.prototype = {};
```

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/iafa0yzffc_2.png)

Ta thay `.prototype` mặc định của MyConstructor bằng một đối tượng mới. Đặc biệt đối tượng này không có property `.constructor`

### 3: Call constructor to create new object:

```javascript
var myobject = new MyConstructor();
```

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/1j0lr35ama_3.png)

Như đã trình bày ở mục **setting propertites** của bài viết, ta dễ dàng thấy được `{Prototype}` của myobject và property `.prototype` của MyConstructor tham chiếu đến cùng một đối tượng.

Vậy bây giờ dựa theo mục **properties lookup**, ta thử truy xuất một property bất kì từ myobject. Ta chọn property có tên là constructor, chuyện gì sẽ xảy ra

```javascript
myobject.constructor = ?
```

Đơn giản, áp dụng `{Property}` chain, ta sẽ có ngay đáp án. Bây giờ cùng thu gọn tất cả những đoạn code ta viết lại:

```javascript
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();

myobject.constructor == Object; // true
myobject.constructor.prototype == Object.prototype; // true
```

**Ghi chú**: Nếu nhìn lại ta sẽ hiểu vì sao ngay từ bước **#2** ta lược bỏ đi phần `{Prototype}` của MyConstructor là đúng đắn

### Thế nếu dùng instanceof kết quả như thế nào?

Viết lại nguyên văn:  
 "Javascript provides the instanceof operator that’s intended to check the prototype chain of the object you’re dealing with."

Từ những bước ở trên, ta có thể nghĩ rằng đoạn code sau sẽ trả về false

```javascript
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();

myobject instanceof MyConstructor; // true
```

nhưng thực chất, nó chạy ổn và còn hơn thế nữa:

```javascript
function MyConstructor() {}
MyConstructor.prototype = {};
var myobject = new MyConstructor();

myobject instanceof Object; // true
```

Khi instanceof được gọi, nó **hoạt động dựa trên `{Prototype}` chain. Và nó chẳng đá động hay lệ thuộc vào property** `.constructor`

cùng nhìn lại hình ở bước **#3**

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/38d3vbr9vo_4.png)

Cứ tới một "trạm" tức đối tượng tham chiếu bởi `{Prototype}`, nó check xem đối tượng này được tham chiếu thông qua `.prototype` property của ai.  
Đầu tiên dừng tại đối tượng {}, nó check và phát hiện ra {} được tham chiếu thông qua `.prototype` property của MyConstructor, suy ra:

```javascript
myobject instanceof MyConstructor; // true
```

Tiếp theo dừng tại đối tượng Object.prototype nó phát hiện ra Object.protoype tham chiếu thông qua `.prototype` property của build-in Object, suy ra:

```javascript
myobject instanceof Object; // true
```

Có ổn rồi, nhưng ta vẫn có thể tìm ra những điều bất thường nếu chịu khó mò mẫm:

```javascript
function MyConstructor() {}
var myobject = new MyConstructor();
MyConstructor.prototype = {};

[
  myobject instanceof MyConstructor, // false !
  myobject.constructor == MyConstructor, // true !
  myobject instanceof Object,
]; // true
```

ở đoạn code trên ta đổi thứ tự của hai dòng code, myobject được tạo ra trước sau đó MyConstructor mới đổi giá trị của `.prototype` property.  
Do đó `{Prototype}` chain sẽ trông như vầy:

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/hh0v85pb9l_5.png)

Đúng như dự đoán `{Prototype}` của object sẽ tham chiếu đến đối tượng cũ mà `.prototype` property của MyConstructor từng tham chiếu.

Điều này làm thay đổi `{Prototype}` chain và có thêm sự xuất hiện của `.constructor` property của old `MyConstructor.prototype` dẫn đến `{Prototype}` của object và `.prototype` property của MyConstructor không tham chiếu đến cùng một đối tượng.  
Dừng tại `{Prototype}` đầu tiên là đối tượng old `MyConstructor.prototype`, nó không phát hiện ra đối tượng đó được tham chiếu thông qua `.prototype` property của ai cả. Tiếp tục `{Prototype}` thứ hai, là `Object.prototype` thì quá rõ ràng, suy ra:

```javascript
(myobject instanceof MyConstructor, // false !
  myobject instanceof Object); // true
```

Ngoài ra, thông qua `{Prototype}` chain (xem lại mục **properties lookup**), thì ta thấy `.constructor` property đầu tiên được bắt gặp trong old `MyConstructor.prototype` nên

```javascript
myobject.constructor == MyConstructor, // true !
```

là điều dễ hiểu.

## Một số nhận định

#### Constructors không phải classes

Nhìn lại các class-based OOP language (như Java, C#,...), các classes kế thừa từ những classes khác, và object là instance của những classes đó. Các properties và methods được chia sẻ giữa các instances. Và việc chia sẻ đó bị chi phối bởi **access modifier** (public, private, internal, protected,......)

Javascript cũng có khái niệm kế thừa, chia sẻ properties và methods thông qua prototype. Nhưng thực tế `{Prototype}` của constructor và `{Prototype}` chain của object được tạo ra từ constructor đó, lại hoàn toàn khác biệt, không liên quan đến nhau.

#### Constructors không hoạt động như class-based initializer

Để có được khái niệm kế thừa thông qua prototype, Khi constructor được gọi nó tiến hành liên kết `{Prototype}` property của object với `.prototype` property của chính nó. Những gì còn lại là việc constructor thêm vào một số properties, methods khác cho object

#### Constructors chỉ là functions

Xem lại bước **#1**, ta thấy MyConstructor chẳng khác gì một function bình thường. Vì vậy bất kì user-defined function nào trong Javascript cũng tự động có `.prototype` property tham chiếu đến một đối tượng sở hữu `.constructor` property tham chiếu ngược về function đó

Bất cứ user-defined function nào cũng được gọi thực thi như một constructor bằng cách thêm vào từ khóa new. Cách làm đó sẽ truyền object mới được tạo bởi từ khóa new vào trong constructor function, và phần việc còn lại của constructor thì như đã nói ở bên trên

#### References

(tham khảo từ [bài viết của zeekat/articles](https://zeekat.nl/articles/constructors-considered-mildly-confusing.html) với một số chỉnh sửa theo hiểu biết của bản thân và để phù hợp với Tiếng Việt)  
(xem thêm [constructor in Javascript object](https://stackoverflow.com/questions/1114024/constructors-in-javascript-objects))  
(xem thêm [Javascript inheritance and the constructor property](https://stackoverflow.com/questions/8093057/javascript-inheritance-and-the-constructor-property/8096017#8096017))  
(xem thêm [ECMA-262 lastest version](https://tc39.github.io/ecma262/#sec-fundamental-objects))

#### Footnotes

\[1\]  
John G Harris từng viết trong comp.lang.javascript rằng những gì trình bày ở bên trên cũng tương đối chưa đúng hoàn toàn. Về mặt lý thuyết, host system có thể sẽ đổi `Object.prototype` property bằng một thứ gì đó khác. Một số thảo luận chấp thuận rằng `Object.prototype` chỉ được read-only. Nhưng ở một số browser (firefox) thì ta có thể gán giá trị mới cho `Object.prototype` mà không có lỗi nào xảy ra.

\[2\]  
có 4 cách để gọi thực thi (invocation) một function trong JavaScript  
(_giữ nguyên văn cho dễ hiểu_)

**Function form:**

```javascript
functionObject(arguments);
```

When a function is called in the function form, this is set to the global object.

- that is not very useful (fixed in ES5/Strict)
- an inner function does not get access to the outer this

**Method form:**

```javascript
thisObject.methodName(agurments);
thisObject["methodName"](arguments);
```

When a function is called in the method form, this is set to thisObject, the object containning the function.  
this allows method to have a reference to the object of interest

**Constructor form:**

```javascript
new functionObject(arguments);
```

- When a function is called with the new operator, a new object is created and assigned to this.
- If there is not an explicit return value, then this will be returned.
- Used in the Pseudoclassical style

**Apply form:**

```javascript
functionObject.apply(thisObject, [arguments]);
functionObject.call(thisObject, arguments....);
```

- A function's apply or call method allows for calling the function,explicitly specifying thisObject.
- It can also take an array of parameters or a sequence of paramenters.

```javascript
// the definition of call method
Funtion.prototype.call = function (thisObject) {
  return this.apply(thisObject, Array.prototype.slice.apply(arguments, [1]));
};
```

![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/dnry2vj88r_this.png)
]]></description>
            <link>https://hungvn.com/blog/object-function-method-constructor-in-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/object-function-method-constructor-in-javascript</guid>
            <pubDate>Tue, 24 Jul 2018 12:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Memory Leaks trong Javascript]]></title>
            <description><![CDATA[
## Giới thiệu

Memory leaks là vấn đề mà mọi deveploper đều sẽ gặp phải khi code. Memory leaks sẽ dấn đến việc ứng dụng sẽ chạy chậm hơn, crashes, hay có thể ảnh hưởng đến các ứng dụng khác. Vậy memory leaks là gì?

Memory leaks có thể được định nghĩa là một bộ nhớ (memory) không được sử dụng trong ứng dụng nữa nhưng vì một lý do nào đó mà nó chưa được giải phóng và trả về hệ điều hành hoặc một cái pool chứa các bộ nhớ (memory) chưa sử dụng. Các ngôn ngữ lập trình khác nhau sẽ có các cách khác nhau để quản lý bộ nhớ. Những cách quản lý bộ nhớ này sẽ giúp giảm thiểu khả năng bị memory leaks của chương trình. Tuy nhiên, việc xác định một vùng bộ nhớ có còn được sử dụng hay không lại là một vấn đề khó có thể xác định. Chỉ có developer mới có khả năng quyết định xem là vùng nhớ này nên được giải phóng hay không. Một số ngôn ngữ (như javascript) cung cấp tính năng tự động giải phóng bộ nhớ cho developer, một số khác thì developer cần phải tự mình giải phóng bộ nhớ khi không sử dụng đến nó nữa.

#### Quản lý bộ nhớ trong JS

Javascript là một trong những ngôn ngữ có _garbage collection_. Những ngôn ngữ lập trình như Javascript thế này sẽ thay developer quản lý bộ nhớ bằng cách kiểm tra định kỳ các vùng nhớ được cấp phát trước đó có có thể được "với tới" bởi các phần khác trong ứng dụng. Có thể nói cách khác là những ngôn ngữ như Javascript sẽ giúp biến vấn đề từ _"những vùng nhớ nào vẫn còn cần trong ứng dụng"_ thành _"những vùng nhớ nào có thể được ứng dụng access đến"_. Sự khác biệt của 2 vấn đề là không nhiều nhưng lại rất quan trọng: chỉ developer mới có thể biết được là vùng nhớ nào còn cần để chạy tuy nhiên, việc xác định xem một vùng nhớ có thể vươn tới không trong ứng dụng thì có thể làm tự động bởi thuật toán.

## Memory leaks trong JS

Lý do chính của memory leaks trong các ngôn ngữ có garbage collection là các reference không mong muốn vào bộ nhớ (unwanted references), tức là một vùng nhớ được trỏ đến mà lại không được sử dụng trong ứng dụng. Để có thể hiểu rõ hơn về nó, trước hết ta cần tìm hiểu các hoạt động của garbage collector, cách nó xác định một vùng nhớ có thể được "với tới" (reach) bởi ứng dụng.

#### Mark and sweep

Hầu hết các garbage collector đều sử dụng thuật toán `mark-and-sweep` để thực hiện việc giải phóng bộ nhớ. Thuật toán này bao gồm các bước sau:

1.  Đầu tiên, garbage collector sẽ xây dựng một danh sách các `roots`. `Roots` thực chất là các biến toàn cục mà có reference được lưu trong code. Trong Javascript, `window` chính là một biến toàn cục như vậy. `Window` sẽ luôn hiện hữu trong chương trình nên garbage collector có thể coi nó và tất cả các con của nó luôn hiện hữu.
2.  Tất cả `roots` và con của chúng sẽ được đánh dẫu là đang hoạt động. Tất cả những vùng nhớ mà có thể được vươn tới từ `roots` thì đều được coi là đang hoạt động và không đánh dấu là rác (garbage).
3.  Tất cả các vùng nhớ mà không được đánh dẫu là rác (garbage) thì bây giớ đều sẽ được coi là rác. Bây giờ thì các collector có thể giải phóng các vùng nhớ này.

Mặc dù thuật toán này được tối ưu bởi các GC (garbage collector) hiện đại tuy nhiên cơ chế của nó vẫn không đổi: những vùng nhớ vươn tói được thì được coi là đang hoạt động, những vùng nhớ khác sẽ được coi là rác.

Những tham chiếu không mong muốn (Unwanted references) là những tham chiếu đến các vùng bộ nhớ mà developer biết là nó không được cần đến nữa nhưng vì lý do nào đó mà nó vẫn được giữ lại trong hệ thống. Trong JS, những tham chiếu không mong muốn này là các biến (variables) được giữ đâu đó trong code mà nó sẽ không được sử dụng đến nữa nhưng lại trỏ đến một vùng nhớ mà cần được giải phóng.

Để hiểu được memory leaks trong JS, ta cần biết được là khi nào thì một tham chiếu bị lãng quên.

## 3 loại memory leaks trong JS

### 1: Biến toàn cục

Javascript có một cơ chế là đặt biến mà không cần khai báo. Ví dụ:

```javascript
a = "value";
console.log(a); //"a"
```

Khi một biến được khai báo như trên thì JS sẽ tự động gán nó vào `global` object (`window` trên browser). Nếu như biến này chỉ hoạt động trên phạm vi toàn cục (global scope) thì cũng không có sự khác biệt cho lắm. Tuy nhiên, nếu nó được định nghĩa trong một hàm thì đó lại là chuyện khác. Ví dụ:

```javascript
function foo() {
  bar = "đây là biến toàn cục ẩn";
}
```

Đoạn code trên sẽ tương đương với đoạn code sau trên browser:

```javascript
function foo() {
  window.bar = "đây là biến toàn cục";
}
```

Nếu khai báo `bar` trong phạm vi của hàm `foo` mà lại không sử dụng `var` để khai báo thì biến `bar` sẽ được tạo với phạm vi toàn cục, và đây là một ví dụ điển hình về memory leaks.

Một cách khác mà có thể vô tình tạo ra biến toàn cục đó là thông qua `this`:

```javascript
function foo() {
  this.variable = "có thể là biến toàn cục";
}

foo();
```

Vì `this` trong hàm sẽ trỏ đến biến root toàn cục (`window`) nếu hàm đó được gọi trực tiếp không thông qua object nào khác nên ở ví dụ trên, biến `variable` sẽ được gắn vào phạm vi toàn cục.

Một cách để giảm thiểu những lỗi trên đó là thêm `"use strict;"` vào dòng đầu tiên của file JS. Nó sẽ giúp ngăn chặn việc khai báo biến toàn cục như trên.

**Chú ý khi làm việc với biến toàn cục**

Biến toàn cục không bao giờ được giải phóng bộ nhớ tự động theo thuật toán `mark-and-sweep` ở trên. Vì thế, biến toàn cục chỉ nên được sử dụng để lưu tạm dữ liệu để xử lý. Nếu cần lưu một lượng lớn dữ liệu vào biến toàn cục thì cần đảm bạo là nó sẽ bị gán về null hoặc gán lại dữ liệu khi mà bạn đã sử dụng xong nó.

### 2: Callback và timer bị lãng quên

Sau đây là một ví dụ dẫn đến memory leak khi sử dụng `setInterval`:

```javascript
var data = getData();
setInterval(function(){
  var node = document.getElementById("Node");
  if(node){
	node.innerHTML = JSON.stringify(someResource));
  }
}, 1000);
```

Đây là một ví dụ về một timer bị treo. Timẻ bị treo tức là khi timer tham chiếu đến các node hoặc dữ liệu mà không còn được sử dụng nữa. Ở ví dụ trên, nếu như `node` bị xóa ở một lúc nào đấy thì toàn bộ đoạn code xử lý trong hàm callback của interval sẽ không cần đến nữa. Tuy nhiên, vì interval vẫn còn hoạt động nên các vùng nhớ được sử dụng trong hàm callback của interval cũng không được giải phóng (muốn giải phóng cần dừng interval lại). Tiếp đó, các object từ bên ngoài mà được hàm callback của interval tham chiếu đến cũng không thể được giải phóng vì vẫn có thể vươn tới được thông qua hàm callback kia. Theo ví dụ trên thì đó là `data`.

Một trường hợp có thể dẫn đến leaks đó là do các observers object (DOM và event listener của chúng). Điều này chỉ ảnh hưởng đến các trình duyệt cũ (vd: IE6) vì các trình duyệt mới sẽ tự động làm điều này cho chúng ta. Đây là một bug của GC của IE6 và dẫn đến việc tham chiếu quay vòng.

### 3: Tham chiếu tới các DOM đã bị xóa

Có những lúc bạn muốn lưu các DOM vào một số cấu trúc dữ liệu như mảng hoặc object trong JS code để làm một loạt các tác vụ nào đấy. Ví dụ bạn muốn update dữ liệu của một vài element nào đấy thì việc lưu các element này vào một mảng là hoàn toàn hợp lý. Khi điều này xảy ra thì sẽ có 2 tham chiếu đên DOM element này: một là từ DOM tree, hai là từ đối tượng mảng của JS. Nếu bạn muốn xóa các element này thì bạn cần phải xóa toàn bộ các tham chiếu tới chúng để có thể giải phóng bộ nhớ.

Ví dụ:

```javascript
var elements = {
  button: document.getElementById("button"),
  image: document.getElementById("image"),
  text: document.getElementById("text"),
};

function doStuff() {
  image.src = "http://some.url/image";
  button.click();
  console.log(text.innerHTML);
}

function removeButton() {
  // button là con của body.
  document.body.removeChild(document.getElementById("button"));

  // Ở đây thì button vẫn được tham chiểu đến bởi elements. Nói cách khác là
  // nó vẫn nằm trong bộ nhớ và không thể được giải phóng.
}
```

Còn một vấn đề quan trọng nữa là khi tham chiếu đến một node lá hoặc một inner node của DOM tree, ví dụ như một ô trong bảng (`<td>` của `<table>`). Nếu bạn tham chiếu đến `<td>` này trong JS code thì khi bạn xóa `<table>` chứa node này thì GC sẽ không giải phóng được cả table chứ không phải là chỉ mỗi `<td>` node không được giải phóng. Vì node con còn tham chiếu đến node cha nên nó sẽ được GC coi là vẫn được tham chiếu và bỏ qua nó. Vì thế nên cẩn thận khi tham chiếu đến các DOM.

### 4: Closures

Closures có nghĩa đơn giản là hàm nằm trong phạm vi của một hàm khác có thể tham chiếu tới các biến của hàm bao nó. Vì sao `Closures` có thể gây ra leak, hãy xem ví dụ sau:

```javascript
var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing) console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join("*"),
    someMethod: function () {
      console.log(someMessage);
    },
  };
};
setInterval(replaceThing, 1000);
```

Ví dụ này cho ta thấy mỗi khi `replaceThing` được gọi, `theThing` sẽ tạo ra một object mới chứa một mảng và một closures (`someMethod`). Cùng lúc đó, biến `unused` cũng lưu một closures tham chiếu đên `originalThing` (là object `theThing` được tạo ra từ việc gọi `replaceThing` ở bước trước đó). Một điều quan trọng nữa là khi một scope được tạo ra cho các closures mà có cùng scope cha, chúng sẽ cùng chia sẻ scope đó. Trong ví dụ này thì `someMethod` và `unused` đều chia sẻ cùng một scope. Mặc dù `unused` không được gọi đến nhưng vì nó có tham chiếu đến `originalThing` nên nó sẽ được GC coi là vẫn đang hoạt động. Khi đoạn code này chạy thì bộ nhớ của chương trình sẽ tăng đều đặn và có thể nhìn thấy ngay được. Về bản chất, một linked-list của closures được tạo (với root là `theThing`) khi đoạn code trên được chạy và đó là lý do bộ nhớ bị tăng dần theo thời gian.

## Garbage Collectors (bộ dọn rác)

Mặc dù GCs giúp chúng ta không phải quản lý bộ nhớ bằng tay nữa, tuy nhiên ta cũng sẽ phải đánh đổi lại một vài thứ. Một trong số đó là việc các GCs hoạt động theo một cách khó đoán biết. Thông thường rất khó có thể chắc chắn rằng một hoạt động thu thập các vùng nhớ không được sử dụng được thực thi hay không. Điều này cũng có nghĩa là trong một số trường hợp, số lượng vùng nhớ của một chương trình nhiều hơn số bộ nhớ mà chương trình đó cần. Trong một số trường hợp khác, ứng dụng sẽ bị ảnh hưởng bởi một khoảng thời gian nhỏ chương trình bị delay để thực hiện công việc thu thập bộ nhớ. Hiện nay, hầu hết GC đều hoạt động theo cách là chỉ thực hiện việc thu thập bộ nhớ khi cấp phát bộ nhớ cho chương trình. Nếu không cần cấp phát bộ nhớ, GCs sẽ không hoạt động. Chúng ta sẽ xem xét các tình huống sau:

1.  Chương trình đã cấp phát một số lượng nhỏ bộ nhớ.
2.  Sau đó, hầu hết (hoặc toàn bộ) các phần tử được đánh dấu là không thể vươn tới nữa.
3.  Chương trình không thực hiện việc cấp phát bộ nhớ nữa.

Trong tình huống này, hầu như tất cả các GC sẽ không thực hiện việc thu thập bộ nhớ nữa. Nói cách khác, mặc dù có những phần tử không thể vươn tới được nữa trong chương trình, chúng sẽ không được thu hồi lại bộ nhớ. Đây không hẳn là leaks, tuy nhiên nó vẫn dẫn đến việc chương trình ngốn bộ nhớ.

## Chrome Memory Profiling Tools

`Chrome` cung cấp một tập các công cụ để kiểm tra tình trạng sử dụng bộ nhớ của code JS. Có 2 view quan trọng liên quan đến bộ nhớ đó là: _timeline_ và _profiles_.

#### Timeline View

`Timeline View` có thể giúp ta biết được mô hình sử dụng bộ nhớ của chương trình. Từ đây ta có thể nhìn được việc rò rỉ bộ nhớ, việc bộ nhớ sử dụng tăng liên tục theo thời gian mà không giảm xuống sau mỗi lần GC được chạy. Ví dụ:

![timeline](https://cdn.auth0.com/blog/jsleaks/timeline.png)

Ta có thể thấy được việc bộ nhớ rò rỉ được thể hiện thông qua việc JS heap tăng dần theo thời gian. Mặc dù sau khi được thu thập với một số lượng lớn tại đoạn cuối thì chương trình vẫn sử dụng số lượng bộ nhớ nhiều hơn so với lúc bắt đầu. Số lượng Node cũng cao hơn. Đây là dấu hiệu của việc các node DOM bị rò rỉ đâu đó trong code.o

#### Profiles view

![profiles](https://cdn.auth0.com/blog/jsleaks/profiles.png)

Đây là công cụ sẽ luôn gắn bó với bạn khi phải điều tra về rò rỉ bộ nhớ. `Profiles view` cho phép bạn lấy ảnh chụp (snapshot) về việc sử dụng bộ nhớ của một chương trình Javascript. Nó cũng cho phép bạn ghi lại những lần cấp phát bộ nhớ theo thời gian. Mỗi một loại kết quả sẽ có các danh sách liệt kê khác nhau được đưa ra, tuy nhiên những thứ mà bạn cần quan tâm đó là danh sách tổng hợp (summary list) và danh sách so sánh (comparision list).

`Summary View` sẽ cho ta thấy được tổng quan về các loại objects được khởi tạo và cấp phát cùng với các kích thước tổng hợp (aggregated size): kich thước nông (Shallow size) là tổng kích thước của tất cả các object của một loại cụ thể nào đó và kích thước giữ lại (retained size) bao gồm `shallow size` và kích thước của các object được lưu lại bởi object này. Nó cũng cho ta một thông tin về khoảng cách giữa một object với root.

`Comparision View` cũng cung cấp cùng một thông tin như `summary view` nhưng nó cho phép ta so sánh giữa các snapshot khác nhau.

## Ví dụ: Tìm kiếm rò rỉ dữ liệu trong Chrome

Có 2 kiểu rò rỉ dữ liệu chủ yếu là: rỏ rỉ dẫn đến việc bộ nhớ bị tăng một cách đều đặn theo thời gian và rò rỉ chỉ xảy ra một lần duy nhất và không gây ra việc bộ nhớ bị tăng trong tương lai nữa. Việc tìm rò rỉ dữ liệu mà bộ nhớ bị tăng dần theo thời gian khá là đơn giản và rõ ràng (sử dụng `timeline view`). Tuy nhiên thì đây lại là rò rỉ gây ra nhiều rắc rối nhất: nếu bộ nhớ cứ tăng dần theo thời gian, nó sẽ khiến trình duyệt chạy chậm dận và cuối cùng sẽ dẫn đến việc script bị ngừng chạy. Rò rỉ mà không dẫn đến việc bộ nhớ bị tăng theo thời gian có thể dễ dàng được tìm ra khi bộ nhớ lớn đến một mức độ nào đó. Thông thường những rò rỉ kiểu này không được chú ý quả nhiều. Nói theo một cách khác, những rò rỉ nhỏ mà chỉ xảy ra một lần thường được coi là một vấn đề để tối ưu code. Tuy nhiên, những rò rỉ mà làm bộ nhớ tăng dần theo thời gian thì được coi là bug và nó cần được fix.

Ở đây ta sẽ sử dụng một ví dụ từ [Chrome](https://developer.chrome.com/devtools/docs/demos/memory/example1). Toàn bộ đoạn code như sau:

```javascript
var x = [];

function createSomeNodes() {
  var div,
    i = 100,
    frag = document.createDocumentFragment();
  for (; i > 0; i--) {
    div = document.createElement("div");
    div.appendChild(document.createTextNode(i + " - " + new Date().toTimeString()));
    frag.appendChild(div);
  }
  document.getElementById("nodes").appendChild(frag);
}
function grow() {
  x.push(new Array(1000000).join("x"));
  createSomeNodes();
  setTimeout(grow, 1000);
}
```

Khi `grow` được gọi, nó sẽ bắt đầu tạo một `div` và gán nó vào DOM. Nó cũng sẽ khởi tạo một mảng lớn (1 triệu phần tử) và gán nó vào một mảng được tham chiếu bỏi một biến toàn cục (`x`). Việc này sẽ dẫn đến việc bộ nhớ bị tăng đều đặn và có thể nhận biết được với `Timeline view`.

#### Phát hiện việc bộ nhớ bị tăng đều đặn trong Chrome

Ta sẽ bắt đầu với [ví dụ sau của chrome](https://developer.chrome.com/devtools/docs/demos/memory/example1). Sau khi click vào ví dụ của Chrome, mở Dev Tools, click vào tab `timeline`, tích chọn `memory` và click vào nút `record`. Tiếp đó quay lại trang ví dụ và click vào `The Button` để bắt đầu việc rò rỉ bộ nhớ. Sau một khoảng thời gian thì dừng lại việc record và xem kết quả:

![example-timeline](https://cdn.auth0.com/blog/jsleaks/example-timeline.png)

**Note**: Ví dụ này sẽ khiến bộ nhớ bị tăng mỗi giây. Sau khi dừng việc record thì các bạn có thể đặt breakpoint vào `grow` để dừng việc thực thi script.

Có 2 dấu hiệu lớn trong bức ảnh trên cho thấy việc rò rỉ bộ nhớ: biểu đồ cho `nodes` (đường kẻ màu xanh lá) và biểu đồ cho JS heap (đường kẻ màu xanh đậm). Số lượng node luôn luôn tăng và không bao giờ giảm. Đây là dấu hiệu cảnh báo lớn.

JS heap cũng tăng dần theo thời gian tuy nhiên điều này khó nhìn ra hơn do hiệu ứng từ GC. Các bạn có thể thấy là bộ nhớ tăng sau lại giảm một cách liên tục. Điểm quan trọng cần chú ý ỏ đây là sau mỗi lần bộ nhớ được giảm thì kích thước của JS heap vẫn lớn hơn so với lần giảm trước đấy. Nói cách khác, mặc dù GC đã thành công thu thập được rất nhiều bộ nhớ, một vài trong số đó bị rò rỉ.

Bây giờ ta đã chắc chắn chương trình của mình bị rò rỉ bộ nhớ, ta cần phải tìm ra nguyên nhân của nó.

#### Tạo 2 snapshot

Để tìm ra nguyên nhân rò rỉ, ta sẽ sử dụng đến công cụ `profiles` của Chrome. Cụ thể hơn, ta sẽ sử dụng tính năng `Take Heap Snapshot`.

Đầu tiên, reload lại trang và tạo một snapshot ngay sau khi load xong trang. Ta sẽ sử dụng snapshot này làm cơ sở. Sau đó, click vào `The Button` một lần nũa, chờ khoảng một vài giây, tạo một snapshot khác. Sau đó tạo breakpoint để dừng việc rò rỉ bộ nhớ lại.

Có 2 cách mà ta có thể sử dụng để kiểm tra sự khác nhau giữa 2 snapshot. Thứ nhất là sử dụng chức năng `Summary` rồi bắt đầu từ phía bên phải chọn `Objects allocated between Snapshot 1 and Snapshot 2`. Hoặc chọn `Comparision` thay cho `Summary`. Trong cả 2 trường hợp, ta sẽ thấy một danh sách các object được khởi tạo giữa 2 snapshot.

![example-snapshots](https://cdn.auth0.com/blog/jsleaks/example-snapshots-1.png)

Trong trường hợp này thì việc tìm ra leaks rất đơn giản. Hãy xem `Size Delta` của `(string)`. 8MB với 58 object mới. Điều này rất đáng nghi ngờ: object mới được tạo nhưng không được giải phóng và 8MB bị chiếm mất.

Nếu ta mở danh sách khởi tạo của `(string)` ta sẽ thấy có một vài object lớn được khởi tạo bên cạnh các object nhỏ. Nếu ta chọn một trong số các object lớn này thì ta sẽ thấy một vài điểm thú vị trong mục `retainers`:

![example-snapshots](https://cdn.auth0.com/blog/jsleaks/example-snapshots-2.png)

Ta thấy rằng object được chọn là một phần tử của mảng. Tiếp đó ta biết được mảng này được tham chiếu bởi biến `x` nằm ở trong `window`. Điều này cho ta thấy được toàn bộ con đường từ object lớn của chúng ta liên kết thế nào với root (`window`). Ta đã tìm được một nguyên nhân dẫn đến rò rỉ và nơi nó được tham chiếu.

Vi dụ này khá đơn giản: object lớn được khỏi tạo thế này không thường xuyên xuất hiện trong chương trinh. Tuy nhiên trong chương trình này cũng có xuất hiện việc rò rỉ DOM có kích cỡ nhỏ hơn. Những node này có thể tìm thấy đươc thông qua snapshot tuy nhiên đối với những site lớn, mọi chuyện sẽ trở nên rắc rối hơn nhiều. Các phiên bản Chrome hiên tại có cung cấp một tính năng đó là: `Record Heap Allocations`

#### Record Heap Allocations

Ta se bắt đầu với viêc để cho đoạn script tiếp tục được chạy và quay lại tab `Profiles` của Chrome Dev Tools. Ấn nút `Record Heap Allocations`. Khi mà tool đang chạy, các bạn sẽ thấy một vài vạch xanh trên biểu đồ ở phía trên đầu. Nó thể hiện việc khởi tạo object khi chạy chương trình.

![example-recordedallocs-overview](https://cdn.auth0.com/blog/jsleaks/example-recordedallocs-overview.png)

Ta có thể thấy được tính năng của công cụ này: chọn một khoảng thời gian để xem object nào được khởi tạo trong khoảng thời gian này. Ta đặt khoảng thời gian này gần các vạch xanh đậm nhất có thể. Chỉ có 3 hàm khởi tạo được show trong danh sách: một trong số đó liên quan đến rò rỉ do `(string)` ở phía trên, tiếp theo là liên quan đến việc khởi tạo DOM và cái cuối cùng là khởi tạo `Text`.

Chon một trong những hàm khởi tạo của `HTMLDivElement` trong danh sách và chọn `Allocation stack`.

![example-recordedallocs-selected](https://cdn.auth0.com/blog/jsleaks/example-recordedallocs-selected.png)

Từ ảnh trên ta thấy được là phần tử được khởi tạo bởi `grow` -\> `createSomeNodes`. Nếu ta để ý kỹ mỗi vạch trên biểu đồ, ta sẽ thấy là hàm khởi tạo `HTMLDivElement` được gọi nhiều lần. Nếu ta quay trở lại với snapshot `comparision view`, ta sẽ thấy là nó chỉ khởi tạo object mà không xóa chúng đi. Nói cách khác là nó luôn khởi tạo object mà không cho phép GC thu thập một vài trong số chúng. Giờ khi ta đã biết objects bị rò rỉ ở đâu (`createSomeNodes`), ta có thể quay trở lại code để sửa lại nó.

#### Các tính năng hữu ích khác

Thay vì sử dụng `Summary view`, ta có thể sử dụng `Allocation view`:

![example-recordedallocs-list](https://cdn.auth0.com/blog/jsleaks/example-recordedallocs-list.png)

Giao diện này cho ta thấy một danh sách các hàm và bộ nhớ khởi tạo liên quan đến chúng. Ta có thể thấy ngay là `grow` và `createSomeNodes` là nổi bật hơn cả. Khi chọn `grow` ta sẽ thấy đối tượng khởi tạo liên quan được gọi đến. Ta có thể để ý thấy `(string)` `HTMLDivElement` và `Text` là những hàm khởi tạo của các đối tượng bị rò rỉ.

**Note**: để sử dụng được tính năng này, vào `Dev Tools` -\> Settings và enable `record heap allocation stack traces` trước khi record.
]]></description>
            <link>https://hungvn.com/blog/memory-leaks-trong-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/memory-leaks-trong-javascript</guid>
            <pubDate>Tue, 24 Jul 2018 11:41:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Làm thế nào để thành thạo CSS Grid trong nháy mắt]]></title>
            <description><![CDATA[
### Giới thiệu

Đây KHÔNG phải là một bài viết để học "mọi thứ" về css grid.
Bài viết này hướng đến những người muốn có kết quả nhanh chóng và hiệu quả.
Trong bốn phần của bài viết này, tôi sẽ chỉ cho bạn 20% cần thiết để làm được 80% những gì bạn có thể làm với CSS Grid layout.

Hãy cùng tìm hiểu!

### Tại sao chỉ 20%?

![](https://cdn-images-1.medium.com/max/1600/1*LPf5rSOWKaSKTOUwkqfK0w.png)

Bất cứ khi nào, một lập trình viên tìm kiếm sự hiệu quả - sự lười biếng sẽ giúp anh ta.

CSS Grid layout rất phức tạp. Theo ý kiến của tôi, nó phức tạp hơn Flexbox. (tôi đã mất vài tuần để tìm hiểu flexbox)

Không hẳn bởi vì nó "khó" mà do CSS Grid có tới 18 thuộc tính mới cộng với những khái niệm mà bạn chưa bao giờ nghe tới trước đó.

Vậy, bạn cần biết tất cả những thuộc tính mới này ngay bây giờ? Ngay lập tức?

Không, bạn không cần!

Bạn chỉ cần học một vài thuộc tính cần thiết ngay lúc này để tạo ra kết quả mong muốn. Những thuộc tính khác có thể học sau. Đó là định nghĩa về "hiệu quả" của tôi.

---

### 1\. CSS Grid layout là gì ?

Nếu bạn mới học bố cục trong CSS, CSS Grid có thể khá xa lạ với bạn.

Bạn đã nghe nói tới Flexbox chưa?

Tôi thích coi CSS Grid như là một người anh (hoặc cha) của Flexbox.

Xử lý các bố cục trong CSS được coi là một công việc khó khăn và không hấp dẫn. Flexbox đã làm cho mọi thứ dễ dàng hơn - nhưng CSS Grid thậm chí còn tốt hơn.

### Cái chúng ta sẽ xây dựng.

Chúng ta sẽ học cách áp dụng 20% kiến thức học được để xây dựng bố cục responsive của một ứng dụng âm nhạc

![a responsive music app, catty music](https://cdn-images-1.medium.com/max/2000/1*ripUP4LuXPQ851Zlq79bWQ.gif)

### Phần 1: 10% bạn cần biết - Các thuật ngữ cơ bản

Chúng ta hãy nhìn vào những điều đầu tiên bạn bắt buộc phải biết.

---

#### Grid Container là gì?

Mỗi bố cục các trang web hoặc ứng dụng bạn tạo ra (hoặc thấy) về bản chất là những chiếc hộp được đặt trong những đường ranh giới xác định.

![gif by chris bannister](https://cdn-images-1.medium.com/max/1600/1*uFGh3Vo2i9MneYvjqJNhRw.gif)

Hiểu đơn giản, grid chỉ là "những đường kẻ". Những đường kẻ ngang và dọc xác định vị trí của các phần tử được thiết kế khác nhau.

Bạn sẽ quen với grid nếu bạn đã sử dụng các phần mềm thiết kế như photoshop hoặc sketch.

Trong bối cảnh của CSS Grid layout, một Grid container là phần tử cha chứa tất cả các phần tử nằm trong grid. Grid container xác định vị trí ban đầu của các đường kẻ trong grid, cả dọc và ngang.

#### Grid Line là gì?

Giả sử bạn có một bố cục như thế này:

![supposed grid layout](https://cdn-images-1.medium.com/max/2000/1*xcID2GAZoYqhb4LYjN6Qug.png)

Bố cục bao gồm một grid container với các phần tử ở bên trong

![a bit of explanation](https://cdn-images-1.medium.com/max/2000/1*9K74dULhLERm5_3a37Byqw.png)

Grid lines chính là những đường kẻ ngang và dọc phân chia grid thành các ô.

#### Grid Cell là gì?

Grid cell là đơn vị nhỏ nhất trong grid layout. Bất kỳ khoảng trống nào được xác định bởi 4 đường grid line.

![The “small boxes” of grid items may be referred to as grid cells.](https://cdn-images-1.medium.com/max/2000/1*7X_NTZG0ikpVwsaB0qfdAw.png)

#### Grid Area

Một grid area có thể giống như một grid cell (giống như ở phần trước). Hoặc cũng có thể trải rộng trên nhiểu hoặc tất cả grid cell trong grid.

Trong hình vẽ dưới đây, grid area trải rộng trên 4 ô.

![](https://cdn-images-1.medium.com/max/2000/1*_4ZnWO3zlt82VMHQ_3VNXA.png)

#### Grid Track là gì?

Một grid track có thể xem như một tên gọi khác cho các cột và các dòng. Nó là khoảng trống giữa 2 grid line bất kỳ.

Hình dưới đây là ví dụ về grid tracks

![](https://cdn-images-1.medium.com/max/800/1*oan28239S-v0oJZECQPKIA.png)

![](https://cdn-images-1.medium.com/max/800/1*-tby4L7UaQavuy6uc0H1LQ.png)

![grid tracks](https://cdn-images-1.medium.com/max/800/1*xkbT0CjkBWb-5S_hxcBvGw.png)

Vì vậy, chúng tôi đã phân loại được tất cả trong phần đầu tiên.

### Phần 2: 10% còn lại mà bạn cần biết về CSS grid.

Bây giờ bạn đã hiểu các thuật ngữ cơ bản, giống như một đứa trẻ mạo hiểm, hãy bắt đầu!

#### Làm thế nào để định nghĩa một Grid?

Giống như Flexbox, mọi thứ bắt đầu với display: grid hoặc display: inline-grid cho phiên bản inline.

Ví dụ, để biến một div thành một grid container:

```css
div {
  display: grid;
}
```

#### Làm thế nào để tạo các cột và dòng?

Để tạo các cột và các dòng trong một grid container, chúng ta sẽ sử dụng 2 thuộc tính mới: `grid-template-columns` và `grid-template-rows`.

Vậy sử dụng chúng như thế nào? Khá đơn giản.

`grid-template-columns` định nghĩa vị trí của các cột. `grid-template-rows` định nghĩa vị trí của các dòng.

Bạn truyền giá trị vào các thuộc tính này, và chúng tạo ra các dòng và các cột.

Xem ví dụ:

```css
grid-template-columns: 100px 200px 300px;
```

Đoạn code này sẽ tạo thành 3 cột mới trong grid container. Cột đầu tiên có độ rộng 100px, cột tiếp theo 200px và cột cuối 300px.

![grid-template-columns: 100px 200px 300px](https://cdn-images-1.medium.com/max/2000/1*OGJmxXekTwSlW-aoTeSXEw.png)

```css
grid-template-rows: 100px 200px 300px;
```

Đoạn code này sẽ tạo 3 dòng mới trong grid container như hình dưới đây:

![grid-template-rows: 100px 200px 300px](https://cdn-images-1.medium.com/max/2000/1*TcGMy7iMxXoRbqs8hL0NHw.png)

Bây giờ đặt chúng cùng nhau, bạn sẽ có một grid hoàn chỉnh với các dòng và cột đã được định nghĩa.

```css
grid-template-columns: 100px 200px 300px
grid-template-rows: 100px 200px 300px
```

### Phần 3: Bắt tay vào Code - CSS Grid

Bây giờ chúng ta hãy thực hiện các bước để xây dựng bản sao của ứng dụng âm nhạc nổi tiếng, nhạc catty

Để phát triển nhanh chóng, tôi sẽ sử dụng [Codepen](http://www.codepen.io). Tạo một dự án mới và hãy bắt đầu.

### Làm thế nào để tạo ra bộ khung cho ứng dụng Catty Music

Sau khi đã tạo một project trên codepen. Chúng ta sẽ tạo một tài liệu html cơ bản:

```html
<body>
  <aside></aside>
  <main></main>
  <footer></footer>
</body>
```

Có mục đích khi chọn cấu trúc này. Bạn sẽ sớm nhận ra điều đó.

Bây giờ style tài liệu.

```css
body {
  display: grid;
  min-height: 100%;
}
```

Đoạn code này sẽ biến body thành một grid-container.

Bây giờ chúng ta cần tạo cấu trúc các dòng và cột trong grid.

### Làm thế nào để tạo ra các dòng và các cột cho ứng dụng Catty Music

Tạo các dòng và cột là khá dễ dàng.

Kết quả cuối cùng chúng cần đạt được là:

![final layout we seek.](https://cdn-images-1.medium.com/max/2000/1*VFkE679czY0Tb49R9GNvyg.png)

Tuy nhiên, ban đầu khi thiết lập grid chúng ta cần 2 dòng và 2 cột.

![initial grid setup](https://cdn-images-1.medium.com/max/2000/1*80Qn4c32kqbQzMVh-AcAoQ.png)

#### Đây là một vài thứ cần chú ý về thiết lập Grid

**Columns:**

1.  Cột đầu tiên phải có độ rộng cố định là 50px.
2.  Cột thứ 2 phải chiếm toàn bộ độ rộng còn lại của dòng.

**Rows:**

3. Dòng thứ 2 phải có chiều cao cố định là 100px.
4. Dòng đầu tiên phải chiếm toàn bộ chiều còn lại của grid.

#### Giải pháp của một người ít kinh nghiệm.

Nếu bạn KHÔNG có kinh nghiệm với CSS, bạn có thể viết như thế này:

```css
body {
   ...
   grid-template-rows: 100% 100px;
   grid-template-columns: 50px 100%;
}
```

Vấn đề với giải pháp này là bạn đã vô tình tạo ra một grid với chiều rộng là 100% + 50px và chiều cao là 100% + 100px.

Cái chúng ta muốn là chiều rộng và chiều cao là 100%. Vì thế hướng tiếp cần này là sai.

#### Giải pháp của người đã có kinh nghiệm

Nếu đã có một vài kinh nghiệm với CSS, bạn có thể làm một vài thứ thông minh hơn như thế này:

```css
body {
   ...
   grid-template-rows: calc(100% - 100px) 100px;
   grid-template-columns: 50px calc(100%-50px)
}
```

Cách này khá thông minh. Nhưng có một vấn đề - nó rất khó để bảo dưỡng.

Ví dụ, nếu vì một lý do nào đó bạn phải thay đổi độ rộng cố định, bạn cũng phải thay đổi định nghĩa calc.

#### Giải pháp hiệu quả nhất

May mắn là CSS Grid có một đơn vị mới giúp chúng ta giải quyết vấn đề ở trên một cách dễ dàng đó là đơn vị. [factional(fr)](https://medium.com/flexbox-and-grids/the-css-fractional-unit-fr-in-approachable-plain-language-fdc47bd387f7)

Đơn vị fractional giải quyết vấn đề tự động phân bố khoảng trống.

Nếu bạn có grid với 3 cột như ở dưới, đơn vị fractional sẽ tự động phân bổ các khoảng trống bằng nhau.

![](https://cdn-images-1.medium.com/max/1600/1*1TWb0kZ4nn6uvykRLMGtOw.png)

INếu vì một vài lý do bạn thêm nhiều phần tử hơn - đừng lo lắng. Đơn vị fr sẽ phân bổ lại các khoảng trống bằng nhau.

![](https://cdn-images-1.medium.com/max/1600/1*D5ILayU5dx_la2wnyn6ZYw.png)

Cuối cùng, nếu bạn đã có một phần tử với độ rộng cố định, bạn có thể lấy toàn bộ khoảng trống còn lại với đơn vị fr. Như thế này:

```css
body {
   ...
   grid-template-rows: 1fr 100px;
   grid-template-columns: 50px 1fr;
}
```

And that is it — done!

### Đặt tên và xác định vị trí bởi Grid Areas

Chúng ta đã tạo ra hệ thống grid. Bây giờ là lúc để sử dụng nó.

Mục đích của phần này học cách xác định vị trí các phần tử trong grid sử dụng grid areas.

Nhắc lại một chút, một grid area là bất kỳ khoảng trống được bao bởi 4 grid line.

![The “small boxes” of grid items may be referred to as grid cells.](https://cdn-images-1.medium.com/max/2000/1*7X_NTZG0ikpVwsaB0qfdAw.png)

#### Làm thế nào để sử dụng grid areas?

Nơi hợp lý để bắt đầu là đặt tên grid areas
Hãy để tôi giải thích.
Xem xét khối lệnh dưới đây:

```html
<div class="aside"></div>
<div class="main"></div>
<div class="footer"></div>
```

3 divs - đơn giản. Bằng cách này, Nó là ngữ nghĩa tốt hơn để sử dụng tags aside main và footer. Tôi sẽ giữ mọi thứ đơn giản.

Bây giờ hãy xem đoạn code này:

```css
.main {
  grid-area: content;
}
.footer {
  grid-area: footer;
}
.aside {
  grid-area: sidebar;
}
```

#### Chuyện gì đang xảy ra ở đây

Nếu biết một chút về Javascript, hay bất kỳ ngôn ngữ lập trình nào khác, thì khái niệm về biến sẽ không phải là mới với bạn.

Trong Javascript, chúng ta có thể nói:

```javascript
var gridArea = "content";
```

Cái chúng ta làm ở phía trên là, lưu chuỗi `content` vào biến `gridArea`

Khai báo CSS ở phần trước tương tự như vậy.

> Mọi phần tử trong grid có thể được gán tới một vùng trong grid container.

Tuy nhiên, trước khi làm điều đó, chúng ta bắt buộc phải gán mỗi phần tử trong grid với một tên gọi. Giống như các biến trong Javascript.

```css
.main {
  grid-area: content;
}
.footer {
  grid-area: footer;
}
.aside {
  grid-area: sidebar;
}
```

Đoạn code ở trên nói rằng, class `.main` có tên là `content`. Class `.footer` có tên là `footer`. Cuối cùng, class `.aside` có tên là `sidebar`

Bây giờ các grid items được gán tên cho mỗi vùng.

Trong lập trình, các biến được thiết lập để được sử dụng ở nơi khác. Bây giờ, hãy sử dụng tên grid area.

#### Vị trí Grid area

Một người đàn ông trẻ có một cái bánh nướng. Anh ta có 3 đứa con và phải chia cho mỗi đứa một phần. Ai là người chia bánh thì hợp lý nhất?

Chính người đàn ông đó!

Người đàn ông trẻ cắt bánh và chia cho mỗi đứa trẻ một phần.

![yummy!](https://cdn-images-1.medium.com/max/1600/1*xN-041OZXzMZvCJ76WRtfQ.jpeg)

Đây là lý do tôi kể câu chuyện này.

Giống như chiếc bánh, toàn bộ khoảng trống trong grid là của ai?

Chính là grid container!

Giống như người đàn ông trẻ, grid container có 3 đứa con `.aside` `.main` và `.footer`. Bây giờ grid container phải chọn cách chia toàn bộ khoảng trống trong grid cho 3 đứa con này.

Và một điều nữa.

Vì tất cả những đứa trẻ đều có tên, người đàn ông trẻ có thể nói: "hey Brian đây là phần của con hoặc hey Emma của con là phần này."

Dễ dàng để xác định ai sở hữu phần nào của chiếc bánh, bằng cách gán mỗi phần với tên của mỗi người.

Mỗi phần tử trong grid đều đã có tên bằng cách sử dụng thuộc tính grid-area.

Bây giờ, hãy chia bánh!

#### Thuộc tính grid-template-areas

Bây giờ grid container phải chia "bánh". Gán mỗi vùng tới mỗi phần tử tương ứng.

Có nhiều cách để làm điều đó, nhưng thuộc tính `grid-template-areas` là cách dễ dàng nhất để làm đó. nó chính là cái bạn cần biết để làm việc hiệu quả.

#### Thuộc tính grid-template-areas làm việc như thế nào?

Hãy xem đoạn code dưới đây:

```css
body {
  grid-template-areas:
    "sidebar  content"
    "footer   footer";
}
```

Cái quái gì vậy?

Không cần phải bị choáng ngợp. Trong phần này, tôi sẽ giải thích nó hoạt động như thế nào - theo thuật ngữ rõ ràng.

Thuộc tính grid-template-areas cung cấp một cấu trúc rất trực quan của grid.

Hãy xem lại đoạn code trên một lần nữa:

```css
body {
  grid-template-areas:
    "sidebar  content"
    "footer   footer";
}
```

Bạn có thể thấy toàn bộ giá trị của thuộc tính là tên của các phần tử trong grid!

`sidebar` `content` và `footer` là tên của các phần tử trong grid. Khai báo ở trên gán mỗi vùng trong grid với một phần tử tương ứng.

![](https://cdn-images-1.medium.com/max/2000/1*NjMwDa_1b1vHkAbpXI_f7w.png)

Hình ảnh trên sẽ giúp bạn hiểu grid được chia như thế nào.

`footer` sẽ chiếm toàn bộ dòng bên dưới. `sidebar` và `content` sẽ chiếm cột đầu tiên và thứ 2 của dòng bên bên.

Đến đây chúng ta có:

```css
body {
  display: grid;
  grid-template-columns: 40px 1fr;
  grid-template-rows: 1fr 90px;
  grid-template-areas:
    "sidebar  content"
    "footer  footer";
}
```

Kết quả sẽ như dưới đây:

![STEP 1: https://codepen.io/ohansemmanuel/pen/bRWrPE](https://cdn-images-1.medium.com/max/2000/1*LNfazbNhUOy6YBEE7Sr_Uw.png)

Tôi đã thêm màu sắc để hỗ trợ hình ảnh. Phần màu đỏ đại diện cho `.footer`, hai phần còn lại, phần `.main` và `.sidebar`.

### Làm cho bố cục responsive - Định nghĩa lại Grid areas với Media Queries

![gif by Muharrem Senyil](https://cdn-images-1.medium.com/max/1600/1*9H_Ylq3VVHRLQRTZZLYbQQ.gif)

Các Grid area mà bạn đã tạo trong grid container có thể thay đổi tùy theo kích thước màn hình của người sử dụng.

Dưới đây là hình ảnh ứng dụng trên màn hình điện thoại.

![Catty Music, on mobile](https://cdn-images-1.medium.com/max/2000/1*Gd8H2uQF3-TVi4lq7g1UAw.png)

Chúng ta sẽ refactor lại code theo hướng tiếp cận mobile first.

Mobile first đơn giản là làm cho style mặc định của bạn là dành cho các thiết di động. Sau đó bạn sẽ tạo ra các thay đổi cho các màn hình lớn hơn thông qua các media query.

Đặt một phần code hiện nay trong một định nghĩa media query. Như dưới đây:

```css
@media only screen and (min-width: 600px) {
  body {
    grid-template-columns: 50px 1fr;
    grid-template-areas:
      "sidebar  content"
      "footer   footer";
  }
}
```

Bạn sẽ để đoạn code mặc định bên ngoài media query

```css
body {
  display: grid;
  grid-template-rows: 1fr 100px;
}
```

Tại sao chúng ta đặt grid-template-rows: 1fr 100px; bên ngoài media query?

Bởi vì cả màn hình di động và desktop chúng ta đều có 2 dòng.

Tuy nhiên, trên màn hình desktop. Sidebar là 50px trong định nghĩa grid-template-columns. Còn trên các thiết bị di động sidebar không tồn tại.

Vì thế, chúng ta sẽ định nghĩa lại khai báo `grid-template-columns` cho di động.

Bây giờ với các thiết bị di động chúng ta sẽ sử dụng style này là mặc định:

```css
body {
   grid-template-areas: "content"
                        "footer"
```

Khá đơn giản phải không? Hãy để tôi giải thích.

### Dòng chảy (hướng) của Grid

Đoạn code cho di động như thế này:

```css
body {
   grid-template-areas: "content"
                        "footer"
```

Bởi mặc định, một grid sẽ sắp xếp các phần tử trên các dòng.

Vì thế khai báo ở phía trên sẽ sắp xếp content trên một dòng và footer trên một dòng khác.

Dưới đây là kết quả - sidebar sẽ ẩn trên màn hình di động:

![STEP 2: https://codepen.io/ohansemmanuel/pen/qjVvjJ?editors=1100](https://cdn-images-1.medium.com/max/2000/1*WeVXg_bAwa5UKqdZHiwQ7w.gif)

Với rào cản ban đầu của sự hiểu biết cách hoạt động của grids và thiết lập responsive grid, chúng ta đã xong bố cục ứng dụng!

### Thêm nội dung vào trong Grid

Khi kết thúc phần này chúng ta sẽ có một bố cục ứng dụng âm nhạc hoàn chỉnh. Bây giờ hãy tập trung và việc sắp xếp nội dung trong grid.

#### 1\. The Sidebar

Điều này có vẻ dễ nhất để bắt đầu. Hãy đi tìm nó.

Sidebar bao gồm 8 icon cách đều nhau dọc theo toàn bộ chiều dài của sidebar.

Hãy chèn các icon vào sidebar:

```html
<div class="aside">
  <i class="fa fa-bars"></i>
  <i class="fa fa-home"></i>
  <i class="fa fa-search"></i>
  <i class="fa fa-volume-up"></i>
  <i class="fa fa-user"></i>
  <i class="fa fa-spotify"></i>
  <i class="fa fa-cog"></i>
  <i class="fa fa-soundcloud"></i>
</div>
```

Kết quả sẽ như thế này:

![https://codepen.io/ohansemmanuel/pen/BZmbza](https://cdn-images-1.medium.com/max/2000/1*DY1tA49VLEOy0I5Fb_HmlQ.png)

Các icon cũng sẽ ẩn trên màn hình di động. Và chỉ hiển thị trên các màn hình lớn hơn. Đây là hướng tiếp cận mobile first.

```css
.aside i {
  display: none;
}
@media only screen and (min-width:600px) {
  .aside i {
    display: block;
  }
```

Các biểu tượng được hiển thị, nhưng được căn chỉnh chưa đều.

#### Sắp xếp các icon

Các thẻ `i` là các phần tử `inline` -- điều đó giải thích tại sao 2 icon lại hiển thị cạnh nhau trên một dòng.

Hãy sắp xếp chúng.

> Các phần tử con của grid container cũng có thể trở thành các grid container. Tại sao không?

#### Bước 1: Biến Sidebar thành một Grid Container

Điều này sẽ cung các tính năng căn chỉnh của grid.

Khi sidebar chỉ hiển thị trên các màn hình lớn hơn, đừng quên đặt nó trong media query.

```css
@media only screen and (min-width: 600px) {
  .aside {
    display: grid;
  }

  .aside i {
    border: 1px solid red;
  }
}
```

Tôi thêm border cho mỗi icon - để chúng ta dễ phân biệt.

![](https://cdn-images-1.medium.com/max/2000/1*QcpsRWdU5Q01YC-C2Et11w.png)

Chuyện gì đang xảy ra ở đây?

Chúng ta KHÔNG thiết lập bất kỳ dòng hay cột trong sidebar. Nhưng chúng ta thấy các icon được sắp xếp khá tốt. Grid tự động thiết lập điều đó.

Đây là vị trí mặc định của các item trong một grid -- trên cùng một dòng.

Một grid cũng có thể sắp xếp các phần tử sử dụng `justify-items` hay `align-items`.

`justify-items` sẽ sắp xếp các phần tử theo chiều ngang.

`align-items` sẽ sắp xếp các phần tử theo chiều dọc.

Áp dụng điều này cho sidebar, và chúng ta có một bổ cục các icon hoàn hảo:

```css
.aside {
     ...
     justify-items: center;
     align-items: center;
  }
```

Bạn vẫn cảm thấy khó hiểu, hãy xem video dưới đây:

<YouTube id="pN2rGbEfNw8" />

Bây giờ chúng ta đã một bố cục hoàn hảo dành cho các icon trong sidebar.

![https://codepen.io/ohansemmanuel/pen/MorYJq?editors=1100](https://cdn-images-1.medium.com/max/2000/1*gwdH9pKxjMw7MnO8vPmTgw.png)

`justify-items` hay `align-items` có thể có các giá trị:

- stretch
- start
- end
- center

Nếu đã từng làm việc với Flexbox, bạn sẽ quen với chúng.

Chúng ta sẽ thêm nhiều nội dung hơn vào thiết kế hiện tại.

Thêm 2 thẻ div vào main section:

```html
<div class="main">
  <div class="main__header"></div>
  <div class="main__body"></div>
</div>
```

**NB:**

1.  `main__header` sẽ chứa music art và playbacks:

![.main__header](https://cdn-images-1.medium.com/max/2000/1*K2ikIxNuiWo8tfY-5RvBXg.png)

2. `main__body `sẽ chứa chi tiết:

![.main__body](https://cdn-images-1.medium.com/max/2000/1*hc80JsuD3IsxxwrAijFWzQ.png)

Trong phần này chúng ta sẽ tập trung vào `main__header`

Đầu tiên, thêm đoạn code html này:

```html
<div class="main__header">
  <div class="img">
    <img src="http://bit.ly/2sc2NJd" />
  </div>
  <section class="details">
    <div>
      <p>CattyBoard Top 100 Single Charts (11.06.36)</p>
      <p class="sm--hide">Unknown Artist</p>
      <p class="sm--hide">2016 . Charts . 100 songs</p>
    </div>
    <div>
      <i class="fa fa-play"> &nbsp;Play all</i>
      <i class="fa fa-plus"> &nbsp;Add to</i>
      <i class="fa fa-ellipsis-h">&nbsp;&nbsp;More</i>
    </div>
  </section>
</div>
```

Chú ý cấu trúc của tài liệu

`main__header` có hai con trực tiếp. Một `div` chứa một hình ảnh và `section` chứa thông tin chi tiết của album.

Kết quả của đoạn code trên khá xấu xí:

![incomplete header](https://cdn-images-1.medium.com/max/1600/1*uhNqMg2RUv_bo5371BrOfQ.png)

Hãy làm cho nó đẹp hơn.

Cái chúng ta cần là một grid với các phần tử được sắp xếp phù hợp.

Hãy sử dụng những kiến thức về grid areas

Đầu tiên, định nghĩa grid area:

```css
.main__header > .img {
  grid-area: img;
}
.main__header > .details {
  grid-area: dtls;
}
```

`div` chứa hình ảnh được đặt tên là `img`. Phần chứa thông tin chi tiết của album được đặt tên là `dtls`.

Bây giờ, định nghĩa grid:

```css
.main__header {
  display: grid;
  grid-template-areas:
    "img"
    "dtls";
}
```

`.main__header` trở thành một grid container, có 2 phần tử xếp chồng lên nhau đầu tiên là `img` tiếp theo là `dtls`. Bởi vì chúng ta đang theo hướng tiếp cận mobile first.

Tại thời điểm này, không có nhiều thay đổi.

![I have included borders and made the text whitish for visual aid.](https://cdn-images-1.medium.com/max/1600/1*h60PmaHUtZAMZrC5xrRtbA.png)

Đây không phải là cái chúng ta muốn trên di động.

Với màn hình di động, các phần tử nên được căn giữa.

```css
@media screen and (max-width: 600px) {
  .main__header {
    justify-items: center;
  }
}
```

Kết quả sẽ như dưới đây:

![](https://cdn-images-1.medium.com/max/1600/1*9Yi3TudvNbbTdYtDBsqL1w.png)

Tiếp theo hãy làm cho text trong `.details` căn giữa:

```css
@media screen and (max-width: 600px) {
  .main__header > .details {
    text-align: center;
  }
}
```

![](https://cdn-images-1.medium.com/max/1600/1*Dj_iJrYWYA4lpQdxuzx4Cw.png)

Đã khá gần với mục tiêu chỉ cần thêm một vài điều chỉnh.

Đoạn text `Unknown Artist` và `2016` . `Charts` . `100 songs` nên ẩn trên di động. Ảnh cũng nên nhỏ hơn.

```css
@media screen and (max-width: 600px) {
  .sm--hide {
    display: none;
  }
  .img > img {
    width: 150px;
  }
}
```

Class `.sm--hide` sẽ ẩn trên di động. Chỉ cần thêm class tới phần tử mong muốn. Như thế này:

```html
<p class="sm--hide">Unknown Artist</p>
<p class="sm--hide">2016 . Charts . 100 songs</p>
```

Và chúng ta có:

![](https://cdn-images-1.medium.com/max/1600/1*3EldPliJB9kqZmu9B1UaRg.png)

Màn hình di động đã xong. Giờ hãy thêm style cho những màn hình lớn hơn.

Với màn hình lớn hơn, chúng ta cần một grid 2 cột. Style sẽ như thế này:

```css
@media only screen and (min-width: 600px) {
  .main__header {
    grid-template-columns: 250px 1fr;
    grid-template-areas: "img dtls";
  }
}
```

Grid đã được định nghĩa lại với 2 cột. Một có độ rộng cố định là 250px và cột kia chiếm toàn bộ khoảng trống còn lại.

![https://codepen.io/ohansemmanuel/pen/gReOQJ?editors=1100](https://cdn-images-1.medium.com/max/1600/1*iFRIMSqQYAl2AhHBgsCjdw.gif)

Tiến trình hiện tại của chúng ta [here](https://codepen.io/ohansemmanuel/pen/gReOQJ?editors=1100).

### Phần 4: Kết hợp CSS Grid với Flexbox

Trong phần này bạn sẽ học cách sử dụng Flexbox và Grid cùng nhau.

Hai module này đã thay đổi cách xử lý bố cục trong CSS. Và cách hiệu quả nhất là sử dụng cả 2 module cùng nhau.

Hãy đi vào chi tiết.

Với phần hiển thị thông tin chi tiết của album chúng ta sẽ sử dụng flexbox.

![](https://cdn-images-1.medium.com/max/2000/1*hc80JsuD3IsxxwrAijFWzQ.png)

#### Làm sao để biết chỗ nào sẽ sử dụng Flexbox?

Quy tắc chung là sử dụng Grid cho bố cục toàn bộ trang, còn Flexbox dành cho UI bên trong các phần tử con.

Một phần tử con có thể là một flex container. Một phần tử con của flex container cũng có thể là một grid container.

Tôi giả sử rằng bạn đã biết về [flexbox](https://medium.freecodecamp.org/understanding-flexbox-everything-you-need-to-know-b4013d4dc9af).

Như thường lệ, hãy bắt đầu bằng html

Dưới đây là một div, với một danh sách các bài hát. Danh sách các bài hát có các đoạn có chứa tên bài hát, nghệ sĩ, thời lượng của bài hát và "catty cloud sync".

```html
<div class="main__body">
  <div>
    <p>1. One Dance</p>
    <p>Crake feat CatKid &amp; Cyla</p>
    <p>2:54</p>
    <p><span>CATTY CLOUD SYNC</span></p>
  </div>
  <div>
    <p>2. Panda</p>
    <p>Cattee</p>
    <p>4:06</p>
    <p><span>CATTY CLOUD SYNC</span></p>
  </div>
  <div>
    <p>3. Can't Stop the Feeling!</p>
    <p>Catin Cimberlake</p>
    <p>3:56</p>
    <p><span>CATTY CLOUD SYNC</span></p>
  </div>
  <div>
    <p>4. Work From Home</p>
    <p>Cat Harmony feat Colla</p>
    <p>3:34</p>
    <p><span>CATTY CLOUD SYNC</span></p>
  </div>
</div>
```

Đây là cái chúng ta có:

![](https://cdn-images-1.medium.com/max/1600/1*lz7cE6DLCPeX-S6bwCVRJw.gif)

`main__body` là một phần tử của grid. Chúng ta có thể biến nó thành flex container nếu điều đó hữu ích.

Trong trường hợp của chúng ta, mỗi thẻ div là con trực tiếp của `main__body` cần trở thành một flex container. Chúng chứa tên bài hát, nghệ sĩ, thời gian và "catty cloud sync".

```css
.main__body > div {
  display: flex;
}
```

Bây giờ chia chiều rộng cho các phần tử con:

```css
.main__body > div p {
  flex: 0 0 25%;
}
```

![https://codepen.io/ohansemmanuel/full/pwLEBL/](https://cdn-images-1.medium.com/max/1600/1*F7_nB62n6q9TV9aDJJ23tA.png)

Bạn sẽ đồng ý với tôi rằng tại thời điểm này, các yếu tố cần thiết cho bố cục đã hoàn thành.

Tuy nhiên, tôi đã thực hiện một vài thay đổi. Bạn có thể xem kết quả cuối cùng [here](https://codepen.io/ohansemmanuel/full/QgxEqz/)

Bạn sẽ nhận thấy rằng tôi vẫn để trống footer. Đó là bài tập cho bạn. Lời khuyên của tôi là sử dụng flexbox. Nó sẽ giúp bạn hiểu cách cả hai module này làm việc cùng nhau.

---

Với một vài thuộc tính của grid, bạn đã xây dựng một bố cục thực sự. Khá ấn tượng. Bạn cũng học được kỹ năng vô giá khi kết hợp CSS Grid với Flexbox.
]]></description>
            <link>https://hungvn.com/blog/lam-the-nao-de-thanh-thao-css-grid-trong-nhay-mat</link>
            <guid isPermaLink="true">https://hungvn.com/blog/lam-the-nao-de-thanh-thao-css-grid-trong-nhay-mat</guid>
            <pubDate>Tue, 10 Jul 2018 08:10:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về Proxy trong ES6]]></title>
            <description><![CDATA[
Nói về ES6 có lẽ chúng ta đã quá quen thuộc với các khái niệm như const và let, hàm mũi tên, class hay [những tính năng hay ho hấp dẫn khác](https://ehkoo.com/bai-viet/tong-hop-tinh-nang-noi-bat-es6). Ngoài ra, ES6 cũng kèm theo những tính năng ít người biết hơn nhưng cũng rất thú vị, và một trong số đó là Proxy.

### Proxy là gì?

Proxy là một class được giới thiệu từ ES6, cho phép bạn can thiệp và thay đổi hành vi của một đối tượng (object). Các hành vi này bao gồm: truy xuất/thiết lập thuộc tính của một đối tượng, thay đổi prototype, gọi hàm, khởi tạo đối tượng bằng từ khóa new… Để hiểu rõ hơn về khái niệm, bạn có thể xem qua ví dụ sau:

```javascript
const u = { name: "Công Tằng Tôn Nữ Tạ Thị Tòn Ten" };

// Thiết lập proxy cho đối tượng `u`
const p = new Proxy(u, {
  // `get` là một trap, sẽ được gọi khi truy xuất đến thuộc tính
  // của đối tượng
  get(target, prop, receiver) {
    // Thay đổi hành vi khi truy xuất đến một thuộc tính: Nếu là
    // chuỗi, chuyển sang chữ hoa
    if (typeof target[prop] === "string") return target[prop].toUpperCase();

    return target[prop];
  },
});

console.log(p.name); // CÔNG TẰNG TÔN NỮ TẠ THỊ TÒN TEN
p.email = "ta.thi@ton.ten";
console.log(p.email); // TA.THI@TON.TEN
```

Chúng ta có thể áp dụng Proxy cho bất cứ object nào trong JavaScript, kể cả mảng, hàm hay một proxy khác.

> **Có thể bạn thừa biết**
> Một hàm trong JavaScript là một thể hiện của lớp Function.

Hiện tại Proxy đã được hỗ trợ bởi các trình duyệt xịn (nghĩa là không có IE đó) và node.js v6 trở đi.

> **Tin vắn**
> Phiên bản 5.0 của [MobX](https://github.com/mobxjs/mobx) đã hoàn toàn sử dụng ES6 Proxy.

### Sử dụng như thế nào?

Trước hết, hãy xem qua những thuật ngữ thông dụng khi làm việc với Proxy:

- **target**: là đối tượng sẽ được áp dụng proxy vào
- **traps**: là những phương thức giúp bạn thay đổi hành vi của đối tượng
- **handler**: là một object chứa các traps, được đưa vào hàm dựng của lớp Proxy

Để khởi tạo proxy, bạn dùng new Proxy(target, handler) như bên dưới:

```javascript
const p = new Proxy(target, handler);
```

Chúng ta sẽ cùng đi qua những traps thông dụng.

#### handler.get() và handler.set()

Như tên gọi, handler.get() và handler.set() cho phép bạn can thiệp khi truy xuất và thiết lập giá trị một thuộc tính của đối tượng.

```javascript
// property: tên của thuộc tính được truy xuất
// receiver: đối tượng sau khi đã được gắn proxy
handler.get(target, property, receiver);

// value: giá trị sẽ được thiết lập cho thuộc tính
// handler.set() phải trả về một giá trị boolean. Nếu là true thì xem như thiết lập
// thành công, ngược lại nếu là false thì xảy ra lỗi TypeError.
handler.set(target, property, value, receiver);
```

Chúng ta có thể dùng handler.set() để kiểm tra tính đúng đắn dữ liệu (data validation) trên thuộc tính của đối tượng. Chẳng hạn như:

```javascript
const u = { age: null };
const p = new Proxy(u, {
  set(target, prop, val) {
    if (prop === "age" && typeof val !== "number") throw new TypeError("Age must be a number");

    target[prop] = val;
    return true;
  },
});

p.age = "10"; // Error: Age must be a number
p.age = 10; // OK!
```

#### `handler.defineProperty()` và `handler.deleteProperty()`

`handle.defineProperty(target, property, descriptor)` là trap được kích hoạt khi sử dụng `Object.defineProperty()`. Phương thức này đòi hỏi phải trả về một giá trị boolean. Ví dụ:

```javascript
const p = new Proxy(
  { foo: 1, bar: true },
  {
    defineProperty(target, property, descriptor) {
      if (property.startsWith("_")) throw new Error("Properties starting with _ are not allowed");
      return Object.defineProperty(...arguments);
    },
  }
);

p._hello = 1; // Error
Object.defineProperty(p, "_hello", { value: 1 }); // Error

p.hello = 1;
Object.defineProperty(p, "hello", { value: 1 });
```

> descriptor là một object quy định hành vi của thuộc tính được khai báo. Chi tiết về descriptor bạn có thể xem ở trang [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) hoặc hóng bài viết tiếp theo của Ehkoo.

`handle.deleteProperty(target, property)` sẽ được kích hoạt khi thực hiện delete một thuộc tính. Phương thức này phải trả về true nếu quá trình xóa được chấp nhận. Ví dụ:

```javascript
const p = new Proxy(
  { foo: 1, bar: true },
  {
    deleteProperty(target, property) {
      delete target[property];
      console.log(`${property} was removed`);
      return true;
    },
  }
);

delete p.foo; // foo was removed
delete p.bar; // bar was removed
```

#### `handler.has()`

`handler.has()` sẽ được kích hoạt khi sử dụng in. Phương thức này cũng đòi hỏi phải trả về một giá trị boolean. Ví dụ:

```javascript
const p = new Proxy(
  { _foo: 1, bar: true },
  {
    has(target, property) {
      if (property.startsWith("_")) return false;
      return property in target;
    },
  }
);

console.log("bar" in p); // true
console.log("_foo" in p); // true
```

#### `handler.apply()`

`handler.apply(target, thisArg, args)` là trap dành cho các hàm, sẽ được khởi động khi hàm được gọi. Ví dụ:

```javascript
const sum = (a, b) => a + b;
const f = new Proxy(sum, {
  apply(target, thisArg, args) {
    const [a, b] = args;
    return target.call(thisArg, a * 2, b * 2);
  },
});

f(1, 2); // 6
```

#### `handler.construct()`

`handler.construct(target, args)` là trap sẽ được gọi khi khởi tạo đối tượng bằng new. Ví dụ:

```javascript
class User {
  constructor(username) {
    this.username = username;
  }
}

const PUser = new Proxy(User, {
  construct(target, args) {
    const [username] = args;
    return new target(username.toUpperCase());
  },
});

const u = new PUser("pikalong");
console.log(u.username); // PIKALONG
```

#### `handler.getPrototypeOf()` và `handler.setPrototypeOf()`

Như tên gọi, hai traps này sẽ được kích hoạt khi sử dụng `Object.getPrototypeOf()` và `Object.setPrototypeOf()` trên đối tượng.

> **Ghi chú**
> Bên cạnh những traps được giới thiệu ở đây, còn có một số traps khác mà bạn có thể tham khảo ở trang [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy).

### Viết thử nào

Bạn có dùng thử [chai](http://www.chaijs.com/) chưa? Thư viện này hỗ trợ viết kiểm chứng (assertion) theo phong cách BDD/TDD, giống như thế này:

```javascript
// chai.expect
expect(foo).to.be.a("string");
expect(foo).to.equal("bar");
expect(foo).to.have.lengthOf(3);

// hoặc chai.should
foo.should.be.a("string");
foo.should.equal("bar");
foo.should.have.lengthOf(3);
```

Cách thiết kế này rõ ràng giúp cho chương trình trở nên mạch lạc và dễ theo dõi vì câu kiểm chứng được viết như một câu tiếng Anh vậy. Chúng ta có thể bắt chước chai và thử viết một lớp Thing có những khả năng sau:

```javascript
// Khởi tạo một đối tượng của lớp Thing với tên là "Phương"
const t = new Thing("Phương");
t.name; // 'Phương'

// Khai báo các thuộc tính boolean
t.is_a.singer;
t.is_not_a.man;

// Kiểm tra thuộc tính
t.is_a_singer; // true
t.is_a_man; // false

// Khai báo phương thức
t.can.sing("Yêu hay không yêu không yêu hay yêu nói một lời");
t.sing(); // Phương sings: Yêu hay không yêu không yêu hay yêu nói một lời
```

> Đây là một phần trong bài [The builder of things](https://www.codewars.com/kata/5571d9fc11526780a000011a) được lấy từ Codewars. Sau khi đọc hết bài viết này thì bạn hãy thử giải thử thách trên xem sao, bảo đảm kết quả không làm bạn thất vọng đâu.
> Ngoài ra nếu bạn có tham gia Codewars thì đừng quên gia nhập clan Ehkoo nhé ;)

Đầu tiên, để truy xuất thuộc tính name, chúng ta có thể nghĩ đến giải pháp “vô cùng rõ ràng và ngây thơ” sau:

```javascript
class Thing {
  constructor(name) {
    this.name = name;
  }
}
```

Đoạn code trên hoàn toàn hợp lý, nhưng sẽ không giúp chúng ta giải quyết những yêu cầu tiếp theo của bài toán. Phân tích kỹ một chút ta có thể thấy việc dùng Proxy là không thể tránh khỏi. Do đó để cài đặt t.name bằng Proxy, ta có thể viết lại thành:

```javascript
class Thing {
  constructor(name) {
    this.state = { name };
    return proxify(this, this.state);
  }
}

// Hàm proxify() nhận vào một target và một object chứa state.
// State này sẽ được sử dụng để giải quyết những yêu cầu tiếp theo.
function proxify(target, state) {
  return new Proxy(target, {
    get(target, prop, receiver) {
      // Nếu truy xuất đến thuộc tính `name`, lấy ra dữ liệu trong state
      if (prop === "name") return state[prop];

      // Còn lại thì sử dụng hành vi mặc định
      return target[prop];
    },
  });
}

const t = new Thing("Phương");
console.log(t.name); // Phương
console.log(t.age); // undefined
```

Vậy là tạm ổn phần lấy name. Chúng ta xem tiếp đến hành vi tiếp theo của lớp Thing.

```javascript
t.is_a.singer;
t.is_not_a.man;

t.is_a_singer; // true
t.is_a_man; // false
```

Hành vi này cho phép khai báo thuộc tính boolean trên đối tượng bằng cách sử dụng is*a cho giá trị true và is_not_a cho giá trị false. Sau đó ta có thể kiểm tra thuộc tính bằng cách truy xuất đến `is_a*${prop}`. Để cài đặt hành vi này, chúng ta có thể làm như sau:

1.  Khai báo thêm một khóa booleans: `{}` cho state. Khóa này đóng vai trò như một bảng tham chiếu giữa tên thuộc tính boolean và giá trị của nó, chẳng hạn như `{ singer: true, man: false }`. Ngoài ra chúng ta cũng cần thêm vào state một cờ inBooleanMode: false.
2.  Nếu prop là is_a hoặc is_not_a, bật cờ inBooleanMode: true
3.  Nếu cờ inBooleanMode đang bật, thuộc tính tiếp theo sẽ là thuộc tính boolean. Do đó ta cập nhật booleans của state thành `{ ...booleans, [prop]: state.booleanValue }`

![](https://res.cloudinary.com/duqeezi8j/image/upload/v1530343401/ehkoo/proxy_iah0182.png)

```javascript
function enterBooleanMode(receiver, state, booleanValue) {
  // Bật cờ
  state.inBooleanMode = true
  // Lưu lại giá trị boolean tùy thuộc vào là `is_a` hay `is_not_a`
  state.booleanValue = booleanValue
  return receiver
}

function setBoolean(receiver, state, prop) {
  state.booleans = {...state.booleans, [prop]: state.booleanValue }
  // Reset lại các giá trị
  state.inBooleanMode = false
  state.booleanValue = null

  return receiver
}

get(target, prop, receiver) {
  // Đặt ở đây để tránh trường hợp gọi t.is_a.is_a
  if (state.inBooleanMode) return setBoolean(this, state, prop)

  if (prop === 'name') return state[prop]
  if (prop === 'is_a') return enterBooleanMode(receiver, state, true)
  if (prop === 'is_not_a') return enterBooleanMode(receiver, state, false)
  if (prop.startsWith('is_a_')) return state.booleans[prop.replace('is_a_', '')]

  return target[prop]
}
```

Kiểm tra thử.

```javascript
const t = new Thing("Phương");

t.is_a.singer;
t.is_not_a.man;
console.log(t.is_a_singer); // true
console.log(t.is_a_man); // false
```

Để cài đặt hành vi tiếp theo, chúng ta cũng có thể làm tương tự như khai báo thuộc tính boolean bằng cách đặt thêm một cờ inDefineMethodMode và bật/tắt cờ này tương ứng. Bên cạnh đó chúng ta cũng đặt thêm một khóa methods trong state để chứa các phương thức được khai báo thông qua can.

```javascript
get(target, prop, receiver) {
  // ...
  if (state.inDefineMethodMode) return setMethod(receiver, state, prop)
  if (prop === 'can') return enterDefineMethodMode(receiver, state)

  // Lấy ra phương thức được khai báo bởi `t.can`
  if (state.methods[prop]) return state.methods[prop]
  // ...
}
```

Ở đây có một chút khó khăn. Có thể thấy trong t.can.sing(phrase), sing phải là một hàm. Do đó giá trị trả về của setMethod() có thể được viết như sau:

```javascript
function setMethod(receiver, state, prop) {
  // Đừng quên tắt cờ sau khi cài đặt method
  state.inDefineMethodMode = false;

  return phrase => {
    // Tạo ra hàm mới
    const f = () => `${state.name} ${prop}: ${phrase}`;
    // Lưu vào danh sách các phương thức được khai báo bởi `t.can`
    state.methods = { ...state.methods, [prop]: f };
  };
}

t.can.sing("Yêu hay không yêu không yêu hay yêu nói một lời");
console.log(t.sing()); // Phương sing: Yêu hay không yêu không yêu hay yêu nói một lời
```

Vậy là được rồi. Chúng ta chỉ còn một bước nữa là chia “sing” sang ngôi thứ ba số ít "sings", nhưng thôi cái này để bạn tự làm nhé. Bạn có thể xem đầy đủ mã nguồn [ở đây](https://repl.it/repls/MiniCornyEditors).

### Kết

Proxy là một công cụ mạnh mẽ, giúp cho việc lập trình meta trong JavaScript trở nên dễ dàng hơn. Hi vọng bài viết này đã giúp bạn hiểu rõ hơn về Proxy và có thể ứng dụng nó trong công việc.

#### Tham khảo

_Proxy - MDN_ - [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)

_ES6 Proxies in Depth_ - [https://ponyfoo.com/articles/es6-proxies-in-depth](https://ponyfoo.com/articles/es6-proxies-in-depth)
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-ve-proxy-trong-es6</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-ve-proxy-trong-es6</guid>
            <pubDate>Sun, 08 Jul 2018 15:57:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu Map và Set trong Javascript]]></title>
            <description><![CDATA[
Được giới thiệu từ ES6, Map, Set, WeakMap, và WeakSet là những cấu trúc dữ liệu giúp thao tác trên tập hợp. Bài viết này sẽ giới thiệu cách hoạt động cũng như các ứng dụng của chúng.

### Map

_Map_, _mảng kết hợp_ (associate arrays) hay _từ điển_ (dictionary/dict) là những thuật ngữ dùng để chỉ một cấu trúc dữ liệu, cho phép bạn ánh xạ từ một _khóa_ (key) tương ứng với một _giá trị_ (value). Trong JavaScript, chúng ta có thể sử dụng _object_ để thể hiện cấu trúc này.

```javascript
const dict = {
  hello: "Xin chào",
  bye: "Tạm biệt",
};

console.log(dict["hello"]); // Xin chào
```

Tuy nhiên, nếu dùng _object_ thì bạn chỉ có thể dùng _chuỗi_ làm _khóa_. Ngoài ra, cách này cũng có một số [hạn chế khác](http://speakingjs.com/es5/ch17.html#_pitfalls_using_an_object_as_a_map). Lớp Map do ES6 giới thiệu sẽ giúp giải quyết những vấn đề này. Với Map, bạn có thể sử dụng bất cứ dạng dữ liệu nào để làm _khóa_.

```javascript
const obj = { bar: 2 };
const dict = new Map();
dict.set("foo", 123).set(obj, "hello world");

dict.get("foo"); // 123
dict.get(obj); // 'hello world'

// Lấy giá trị của một khóa không tồn tại
dict.get("wat"); // undefined
```

Bạn cũng có thể truyền vào hàm dựng của Map một mảng các cặp giá trị dạng [key, value], ví dụ như sau:

```javascript
const dict = new Map([
  ["foo", 123],
  [obj, "hello world"],
]);
```

Như đã nói ở trên, bạn có thể dùng bất cứ dạng dữ liệu gì để làm _khóa_ cho Map, kể cả mảng, object, hàm, hay NaN.

```javascript
const arr = [1];
const f = () => {};
dict.set(arr, "an array").set(f, "a function").set(NaN, "not a number");
```

Bản thân Map sử dụng phương thức so sánh [SameValueZero](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#A_model_for_understanding_equality_comparisons) để tìm _khóa_ và giá trị tương ứng. SameValueZero hoạt động tương tự như ===, nhưng xem các giá trị NaN bằng nhau, cũng như +0 bằng -0.

> **Đố-hẻm-vui**: Đố bạn kết quả của các biểu thức sau là gì?
>
> NaN == NaN
> NaN === NaN
> Object.is(NaN, NaN)

Do SameValueZero nên hai _object_ khác nhau sẽ là hai _khóa_ riêng biệt.

```javascript
const o1 = {};
const o2 = {};

dict.set(o1, "Ô Một").set(o2, "Ô Hai");
dict.get(o2); // Ô Hai
dict.get({}); // undefined
```

Nếu trong map đã có sẵn _khóa_, dữ liệu mới sẽ bị ghi đè lên.

```javascript
const m = new Map();
m.set("foo", 1);
m.set("foo", 2);

m.get("foo"); // 2
```

Để duyệt qua các _khóa_ và giá trị trong Map, bạn có thể dùng:

```javascript
const dict = new Map([
  ["foo", 1],
  ["bar", 2],
]);

dict.keys(); // ['foo', 'bar']
dict.values(); // [1, 2]
dict.entries(); // [ ['foo', 1], ['bar', 2] ]
dict.forEach(
  function (value, key, map) {
    console.log(`${key} has ${value}`);
  } /* thisArgs bạn có thể truyền vào tham chiếu cho `this` ở đây */
);

// Sử dụng for..of cùng với destructuring
for (let [key, value] of dict) {
  console.log(`${key} has ${value}`);
}
```

Bạn cũng có thể dùng toán tử spread ... với Map

```javascript
const dict = new Map([
  ["foo", 1],
  ["bar", 2],
]);
console.log([["wut", 3], ...dict]);
// [ [ 'wut', 3 ], [ 'foo', 1 ], [ 'bar', 2 ] ]
```

Một số thao tác khác với Map.

```javascript
const dict = new Map([
  ["foo", 1],
  ["bar", 2],
]);

// Đếm số cặp giá trị trong map
dict.size; // 2

// Kiểm tra trong map có khóa "foo" hay không
dict.has("foo"); // true
dict.has("wut"); // false

// Xóa một khóa, trả về boolean nếu thành công, false nếu thất bại
dict.delete("wut"); // false
dict.delete("foo"); // true

// Xóa hết các cặp giá trị của map
dict.clear();
```

> **Tại sao lại là size mà không phải length?**
> Một số độc giả tinh ý sẽ nhận ra chúng ta dùng size thay vì length để đếm số cặp giá trị trong map. Lý do là vì: length dùng cho những chuỗi có thể index (đánh số) được, ví dụ với _mảng_ ta có thể arr[3]. Ngược lại, size dành cho những cấu trúc không có thứ tự như Map và Set.

### Set

Set là tập hợp các giá trị không bị trùng lặp, nghĩa là trong một _set_ không thể có hai giá trị bằng nhau.

```javascript
const s = new Set();
set.add("red").add("blue").add("sweet").add("you");

s.size; // 4
```

Bạn cũng có thể truyền một _mảng_ vào hàm dựng của Set.

```javascript
const s = new Set(["red", "blue", "sweet", "red", "you"]);
console.log(s); // Set (4) {'red', 'blue', 'sweet', 'you'}
```

Bạn cũng có thể thấy giá trị 'red' bị trùng lặp đã được loại bỏ. Chúng ta có thể áp dụng Set để tạo ra một _mảng_ chứa những phần tử duy nhất.

```javascript
const a = ["red", "blue", "sweet", "red", "you"];
const b = [...new Set(a)];
console.log(b); // [ 'red', 'blue', 'sweet', 'you' ]
```

Cũng tương tự như Map, Set sử dụng SameZeroValue để so sánh các phần tử với nhau.

```javascript
const obj = {};
const s = new Set([NaN, {}, obj]);
s.has(NaN); // true
s.has(obj); // true
s.has({}); // false
```

Để duyệt qua các phần tử của Set, bạn có thể dùng các phương thức như với Map.

```javascript
const s = new Set([1, 2, 3, 4, 5]);

// Vì Set không có khái niệm keys nên kết quả của `s.keys()` và `s.values()` là như nhau.
s.keys();
s.values();

s.entries();
s.forEach(function (value, key, setReference) {}, thisArg);

for (let el of s) {
  console.log(el);
}
```

Một số thao tác khác trên Set.

```javascript
const s = new Set([1, 2, 3, 4, 5]);

// Xóa một phần tử trong set
s.delete(3); // Set (4) {1, 2, 4, 5}

// Xóa hết phần tử trong set
s.clear();
```

### WeakMap và WeakSet

ES6 cũng giới thiệu hai lớp WeakMap và WeakSet. So với Map, các _khóa_ của WeakMap bắt buộc phải là _object_, và chúng sẽ bị giải phóng khỏi bộ nhớ (garbage-collecting – “hốt rác”) đầu tiên nếu không có tham chiếu nào.

WeakMap có các phương thức tương tự như Map, ngoại trừ việc bạn không thể duyệt qua WeakMap bằng .keys(), .values(), .entries() hay for..of. Bạn cũng không thể .clear(), vì lý do an toàn dữ liệu.

Một ứng dụng của WeakMap là dùng để chứa dữ liệu private mà không gây ra rò rỉ bộ nhớ.

```javascript
const privates = new WeakMap();

class User {
  constructor() {
    const data = { phoneNumber: 123 };
    privates.set(this, data);
  }

  getPhoneNumber() {
    const data = privates.get(this);
    return data.phoneNumber;
  }
}
const u = new User();
console.log(u); // {}
console.log(u.getPhoneNumber()); // 123
```

Tương tự như WeakMap, WeakSet cũng chỉ có thể chứa _object_, và nếu một phần tử trong WeakSet không có tham chiếu tới, nó sẽ bị giải phóng khỏi bộ nhớ.

### Kết luận

Với những cải tiến so với _object_ thông thường, Map sẽ là công cụ hữu hiệu để lưu trữ dữ liệu dạng (khóa, giá trị). Trong khi đó, Set giúp bạn lưu trữ chuỗi dữ liệu mà không lo lắng về việc trùng lắp giá trị.

#### Tham khảo

[1] Axel Rauschmayer. ECMAScript 6: maps and sets. [http://2ality.com/2015/01/es6-maps-sets.html](http://2ality.com/2015/01/es6-maps-sets.html)

[2] Keyed Collections - JavaScript | MDN. [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections)

[3] Steve Brownlee. WeakMap for JavaScript Private Data. [https://www.stevebrownlee.com/weakmap-javascript-private-data/](https://www.stevebrownlee.com/weakmap-javascript-private-data/)
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-map-va-set-trong-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-map-va-set-trong-javascript</guid>
            <pubDate>Sun, 08 Jul 2018 15:12:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tổng hợp những tính năng ES6 nổi bật]]></title>
            <description><![CDATA[
Việc hầu hết những tính năng hay ho hấp dẫn của ES6 đều đã được [các trình duyệt hỗ trợ](https://kangax.github.io/compat-table/es6/) quả là tin vui cho giới lập trình web. Nhờ nó mà nhà phát triển có thể xây dựng ứng dụng trực tiếp bằng ES6, không cần phải thông qua các công cụ chuyển đổi như [Babel](http://babeljs.io/) hay [Bublé](https://buble.surge.sh/guide/) nữa, giúp ứng dụng trở nên gọn nhẹ hơn, giảm thiểu kích thước tập tin khi chuyển đến người sử dụng.

### Nội dung

1.  let và const
2.  Hàm mũi tên (arrow functions)
3.  Chuỗi bản mẫu (template strings)
4.  Object chân phương (object literals)
5.  Phân rã biến (destructuring)
6.  Rest và Spread
7.  Giá trị mặc định cho tham số
8.  Lớp (class)
9.  Promise

### 1\. let và const

Ngày xa xưa ấy, bạn khai báo biến trong JavaScript bằng var, giống như ví dụ dưới đây.

```javascript
var foo = 1;
function printFoo(shouldDo) {
  if (shouldDo) {
    var foo = 2;
  }
  return foo;
}
console.log(printFoo(false)); // undefined
console.log(printFoo(true)); // 2
```

Biến được khai báo với var sẽ có tầm vực bên trong hàm gần nhất (function scope), và sẽ được đẩy lên đầu của tầm vực (hoisting). Đó là lý do tại sao foo lại có giá trị undefined trong dòng console.log đầu tiên.

ES6 giới thiệu let và const như hai cách khai báo biến mới, hỗ trợ tầm vực theo khối (block scope) và không thực hiện hoisting.

```javascript
let foo = 1;
function printFoo(shouldDo) {
  if (shouldDo) {
    let foo = 2;
    console.log("Value of foo in scope", foo); // 2
  }
  console.log("foo is out of block scope", foo); // 1
  return foo;
}
console.log(printFoo(false)); // 1
console.log(printFoo(true)); // 1
```

Điểm khác biệt giữa let và const là với const, bạn không thể gán giá trị mới cho biến sau khi khai báo, trong khi điều này lại có thể với let.

```javascript
let foo = 2;
foo = 3;
console.log(foo); // 3

const baz = 2;
baz = 3; // Error: Assignment to constant variable.
```

const mang ý nghĩa “constant” chứ không phải "immutability". Nghĩa là với các biến là object hay array, bạn vẫn có thể thay đổi giá trị bên trong của chúng.

```javascript
const obj = { foo: 2 };
obj.foo = 5;
obj.bar = 3;
console.log(obj); // { foo: 5, bar: 3 }

const arr = [1];
arr.push(2);
console.log(arr); // [1, 2]

// Tuy vậy bạn không thể gán một đối tượng khác cho obj/arr
obj = { baz: 4 }; // Error: Assignment to constant variable.
arr = []; // Error: Assignment to constant variable.
```

> **Tính tương thích:** [Được hỗ trợ](http://caniuse.com/#feat=let,const) trên tất cả trình duyệt, kể cả IE11.
> **Lời khuyên:** Dùng const cho tất cả khai báo biến vì nó sẽ giúp bạn hạn chế trường hợp “vô tình” thay đổi giá trị của biến. Chỉ dùng let trong trường hợp bất khả kháng, và tránh xa var.

### 2\. Hàm mũi tên

Hàm mũi tên – (fat) arrow functions – là một kiểu cú pháp rút gọn cho khai báo hàm trong JavaScript. Trước ES6, bạn khai báo một hàm trong JavaScript với từ khóa function.

```javascript
function add(x, y) {
  return x + y;
}

// Hàm add() ở trên là syntactic sugar cho...
var add = function (x, y) {
  return x + y;
};
```

> “Syntactic sugar” là cú pháp làm cho ngôn ngữ trở nên dễ đọc và dễ hiểu hơn, theo kiểu nó làm cho ngôn ngữ “ngọt ngào hơn” (sweeter) với lập trình viên.

Với hàm mũi tên trong ES6, bạn có thể viết lại thành:

```javascript
const add = (x, y) => {
  return x + y;
};

// Bạn cũng có thể viết dưới dạng biểu thức (expression), hàm mũi
// tên sẽ tự động trả giá trị về (auto-return).
const add = (x, y) => x + y;
```

Hàm mũi tên cũng hữu dụng để giải quyết vấn đề muôn thuở trong JavaScript: “which this is this?” – khái niệm con trỏ this. Với ES5, bạn hay gặp trường hợp giống như thế này:

```javascript
"use strict";
function App() {
  this.count = 0;
  setInterval(function () {
    console.log(this.count++);
  }, 1000);
}

var a = new App();
```

Trước ES6, mỗi khai báo hàm đều có một giá trị this tách biệt. Điều này làm cho đoạn code ở trên không hoạt động, vì this.count bên trong hàm của setInterval mang giá trị undefined. Cách giải quyết thông thường là đặt một biến self, that hay \_this để giữ reference, hoặc sử dụng Function.prototype.bind.

```javascript
function App() {
  this.count = 0;
  var self = this;
  setInterval(function () {
    console.log(self.count++);
  }, 1000);
}

// hoặc
function App() {
  this.count = 0;

  function counter() {
    console.log(this.count++);
  }

  setInterval(counter.bind(this), 1000);
}
```

Với hàm mũi tên trong ES6, giá trị của this chính là this trong tầm vực gần nhất với nó (lexical this). Do đó chúng ta không cần phải khai báo biến tạm hay dùng .bind nữa.

```javascript
function App() {
  this.count = 0;

  setInterval(() => console.log(this.count++), 1000);
}
```

Hàm mũi tên cũng rất hữu ích khi thao tác trên mảng và tiến hành chuyển đổi dữ liệu, giúp mã nguồn dễ đọc và rõ ràng hơn.

```javascript
const subtotal = products
  .filter(product => product.price > 500)
  .reduce((acc, product) => acc + product.price, 0);
```

> **Tính tương thích:** Trừ IE11, tất cả các trình duyệt còn lại đều hỗ trợ.
> **Lời khuyên:** Nếu có dùng đến this thì hàm mũi tên rất hữu dụng. Trường hợp không dùng thì…cũng hữu dụng luôn vì mã nguồn gọn gàng dễ đọc hơn. Với những trường hợp bạn muốn bao đóng giá trị của this chỉ gói gọn trong hàm của nó, dùng function.

### 3\. Chuỗi bản mẫu

Chuỗi bản mẫu (template strings) là chuỗi chân phương (string literals) nhưng cho phép đính kèm biểu thức. Nó cũng cho phép khai báo chuỗi trên nhiều dòng. Để sử dụng, bạn dùng ký tự backtick ` (dấu huyền). Ví dụ như là:

```javascript
const name = "John";

const greetings = `Hello ${name},
The result of 1 + 1 is ${1 + 1}, and the time is now ${Date.now()}.`;
```

Vì chuỗi bản mẫu cũng chỉ là chuỗi nên bạn có thể gọi đến những phương thức của String.prototype.

```javascript
`Hello World`.substr(0, 5).toUpperCase();
```

> **Tính tương thích:** Trừ IE11, tất cả các trình duyệt còn lại đều hỗ trợ.
> **Lời khuyên:** Dùng chuỗi bản mẫu khi bạn cần gắn biểu thức hay chuỗi có nội dung ở nhiều dòng. Còn lại thì vẫn dùng chuỗi bình thường với ' hay ".

### 4\. Object chân phương (object literals)

Object chân phương (object literals) chỉ đơn giản là khai báo một object trong JavaScript như bạn đã làm bao năm nay.

```javascript
var birthYear = 2000;
var obj = {
  name: "John",
  birthYear: birthYear,
  getAge: function (currentYear) {
    return currentYear - obj.birthYear;
  },
};
```

ES6 nâng cấp object chân phương, cho phép bạn khai báo tắt thuộc tính của object với biến cùng tên, và khai báo phương thức cho object.

```javascript
const birthYear = 2000;
const obj = {
  name: "John",
  birthYear, // khai báo tắt birthYear: birthYear
  getAge(currentYear) {
    // `this` được gán trực tiếp vào bản thân object
    return currentYear - this.birthYear;
  },
};
```

Một lưu ý với this là khi bạn dùng hàm mũi tên, this sẽ được lấy từ this trong tầm vực gần với nó nhất, chứ không trỏ đến đối tượng hiện tại. Do đó…

```javascript
{
  getAge: currentYear => currentYear - this.birthYear;
}
```

…sẽ không chạy như mong muốn, vì có thể this.birthYear mang giá trị undefined. Để sử dụng hàm mũi tên bạn phải viết lại như trước ES6.

```javascript
{
  getAge: currentYear => currentYear - obj.birthYear;
}
```

Ngoài ra từ ES6 bạn cũng có thể khai báo thuộc tính cho object một cách linh động bằng cách sử dụng cú pháp [].

```javascript
const attr = "foo";
const year = 2017;
const obj = { [attr]: 1, ["now" + year]: "wow" };
console.log(obj); // { foo: 1, now2017: 'wow' }
```

> **Tính tương thích:** Được hỗ trợ bởi tất cả trình duyệt
> **Lời khuyên:** Tính năng khai báo tắt thuộc tính của object cực ký hữu dụng => nên dùng. Nếu không bận tâm đến this thì bạn có thể dùng hàm mũi tên khi khai báo phương thức cho object để mã nguồn gọn gàng sạch đẹp hơn.

### 5\. Phân rã biến

Phân rã biến – destructuring – theo mình là tính năng tiện dụng nhất của ES6\. Tính năng này giúp bạn tách biến từ thuộc tính của đối tượng hay phần tử trong các đối tượng có thể duyệt với for, như mảng hoặc chuỗi. Chẳng hạn như:

```javascript
const user = { name: 'John', age: 21 };
const { name } = user;
console.log(name); // 'John'

const arr = [1, 2, 3];
const [first, second] = arr;
console.log(first, second); // 1, 2

const str = 'Hello';
const [first, second] = str;
console.log(first, second); // 'H', 'e'
```

Bạn cũng có thể phân rã các thuộc tính lồng nhau.

```javascript
const userList = [
  {
    name: "John",
    age: 21,
    products: [
      { name: "Creamy Crustacean Omelette", price: 1200 },
      { name: "Galdin Gratin", price: 2300 },
    ],
  },
];

const [
  {
    products: [{ price }],
  },
] = userList;
console.log(price); // 1200
```

Với mảng hay chuỗi, bạn có thể bỏ qua phần tử không mong muốn khi phân rã.

```javascript
const arr = [1, 2, 3];
const [first, , third] = arr;
console.log(first, third); // 1, 3

const str = "Hello";
const [fst, , , , lst] = str;
console.log(fst, lst); // 'H', 'o'
```

Phân rã biến cũng rất thường gặp khi bạn sử dụng ES6 module.

```javascript
import { Component } from "react";

import { render } from "react-dom";
```

> **Tính tương thích:** Trừ IE11, tất cả các trình duyệt còn lại đều hỗ trợ.

### 6\. Rest và spread

Rest – phần còn lại – là một bổ sung của phân rã biến mảng ở trên. Bạn dùng ba dấu chấm ... để biểu thị rest.

```javascript
const [first, second, ...others] = [1, 2, 3, 4, 5];

console.log(first, second, others);
// 1
// 2
// [3, 4, 5]
```

Rest cũng được dùng khi khai báo hàm có thể nhận nhiều tham số

```javascript
const foo = (...args) => console.log("You passed", args);
console.log(foo(1, 2, 3)); // You passed[ 1, 2, 3 ]

const bar = (x, y, ...rest) => console.log(rest, x, y);
```

Bạn lưu ý biến args ở trên khác với biến đặc biệt arguments vốn có sẵn bên trong hàm. arguments là một đối tượng giống Array, với những thuộc tính đặc biệt như callee, trong khi args chỉ là một mảng bình thường.

Spread – rải – là thao tác ngược lại với rest, giúp bạn kết hợp một mảng đã có sẵn thành mảng mới.

```javascript
const arr = [3, 4, 5];
const newArr = [1, 2, ...arr, 6];
console.log(newArr); // [1, 2, 3, 4, 5, 6]
```

Spread rất hữu ích để thay thế các thao tác thên mảng, như .concat().

```javascript
const head = [1, 2];
const tail = [3, 4, 5];
console.log([...head, ...tail]); // [1, 2, 3, 4, 5]
```

Spread cũng rất ngon khi thay thế cho Function.prototype.apply.

```javascript
const mul = (x, y, z) => x * y * z;
const params = [1, 2, 3];

// Thay thế cho
// mul.prototype.apply(null, params)
mul(...params);
```

Rest/spread cũng có thể hoạt động trên object, tương tự như Object.assign(), nhưng bạn lưu ý tính năng vẫn đang được [đề xuất](https://github.com/tc39/proposal-object-rest-spread) (proposal). Về phía trình duyệt, có Firefox và Chrome là hỗ trợ, trong khi Edge và Safari hoàn toàn không hoạt động.

```javascript
const user = { name: "John" };

// ES5
const userWithAgeEs5 = Object.assign({}, user, { age: 21 });

// Thời đại mới với spread
const userWithAge = { ...user, age: 21 };
console.log(userWithAge); // { name: 'John', age: 21 }

// Và rest
const { name, ...others } = userWithAge;
console.log(others); // { age: 21 }
```

> **Tính tương thích:** Trừ IE11, tất cả các trình duyệt còn lại đều hỗ trợ rest và spread với mảng hay chuỗi. Với spread object, Edge và Safari chưa hỗ trợ.

### 7\. Giá trị mặc định cho tham số

Khi khai báo hàm, tính năng này cho phép bạn thiết lập giá trị mặc định của tham số khi nó không được truyền giá trị hoặc có giá trị undefined.

```javascript
function getDiscountedPrice(price, discountRate = 0.1) {
  return price * (1 + discountRate);
}
```

Dĩ nhiên bạn có thể dùng bất cứ giá trị nào làm giá trị mặc định.

```javascript
function processItems(items = []) {
  return items.map(transformItemData);
}

// hoặc dùng biến
const DISCOUNT_RATE = 0.1;
const getDiscountedPrice = (price, discountRate = DISCOUNT_RATE) => price * (1 + discountRate);
```

### 8\. Lớp (class)

Với ES5, chúng ta sử dụng function để tạo lớp và thêm các phương thức vào lớp bằng cách mở rộng prototype.

```javascript
function Foo(x) {
  this.x = x;
}

Foo.prototype.add = function (y) {
  return this.x + y;
};

var f = new Foo(3);
console.log(f.add(2)); // 5
```

ES6 mang đến cú pháp mới giúp tạo lớp trực tiếp và dễ dàng hơn.

```javascript
class Foo {
  constructor(x) {
    this.x = x;
  }

  add(y) {
    return this.x + y;
  }

  // Khai báo phương thức tĩnh (static method)
  static whoAmI() {
    return "I am a Foo class";
  }
}

const f = new Foo(3);
console.log(f.add(2)); // 5
console.log(Foo.whoAmI()); // I am a Foo class
```

Bạn cũng có thể kế thừa từ lớp khác bằng từ khóa extends.

```javascript
class Bar extends Foo {
  constructor(x, y) {
    // Gọi đến hàm dựng của lớp cha
    super(x);
    this.y = y;
  }

  calculate() {
    return this.add(4) + this.y;
  }
}

const f = new Bar(3, 4);
console.log(f.calculate()); // 11
```

Ngoài ra với bạn cũng có thể dùng hàm mũi tên khi khai báo phương thức trong lớp. Điều này giúp đảm bảo this luôn trỏ đến đối tượng hiện tại. Cú pháp này đặc biệt thông dụng trong các ứng dụng React, tuy nhiên **vẫn chưa được hỗ trợ mặc định** bởi các trình duyệt, nên bạn phải dùng Babel để chuyển đổi mã nguồn.

```javascript
class Button extends React.Component {
  state = { name: "Fabulous button" };

  doClick = e => {
    e.preventDefault();
    // 'You clicked Fabulous button'
    console.log(`You clicked ${this.state.name}`);
  };

  render = () => {
    return <button onClick={this.doClick} />;
  };
}
```

> **Tính tương thích:** Trừ IE11, tất cả các trình duyệt còn lại đều hỗ trợ lớp căn bản.

### 9\. Promise

Nếu bạn chưa biết Promise là gì thì [click vào đây](https://kipalog.com/posts/Promise-la-khi-gi-).

Vì Promise đã được công nhận như một phần của đặc tả ECMAScript 6 nên các trình duyệt có nghĩa vụ phải hỗ trợ mặc định. So với những thư viện chuyên biệt như [bluebird](http://bluebirdjs.com) hay [q](https://github.com/kriskowal/q) thì phiên bản mặc định có ít tính năng hơn, nhưng cũng vừa đủ để dùng. Quan trọng là không cần thư viện thứ ba.

```javascript
const showUser = user => console.log(`Your name is ${user.name}`);

const getUserData = userId =>
  new Promise((resolve, reject) => {
    return RemoteApi.get(`/users/${userId}`, (err, response) => {
      if (err) return reject(err);
      resolve(response);
    });
  });

getUserData(123)
  .then(response => response.data)
  .then(showUser)
  .catch(err => console.error("Oh no", err));
```

Promise còn có các hàm tĩnh khác:

##### Promise.all(iterator)

Nhận vào một mảng các promises và chỉ resolve khi tất cả promises trong mảng được resolve.

##### Promise.race(iterator)

Nhận vào một mảng các promises và resolve/reject ngay khi một trong các promises trong mảng resolve/reject.

##### Promise.resolve()

Trả về một promise được tự động resolve.

##### Promise.reject()

Trả về một promise được tự động reject.

> **Tính tương thích:** Trừ IE11, tất cả các trình duyệt còn lại đều hỗ trợ.

### Kết

ES6 mang đến những tính năng tuyệt vời cho lập trình viên, giúp cho làm việc với JavaScript trở nên dễ thở hơn, đồng thời nâng cao hiệu suất, cải thiện mã nguồn và giảm dung lượng tập tin khi truyền tải trên mạng. Nếu ứng dụng của bạn hướng đến các trình duyệt hiện đại, đừng chần chờ gì, hãy dùng ES6 ngay hôm nay.
]]></description>
            <link>https://hungvn.com/blog/tong-hop-nhung-tinh-nang-es6-noi-bat</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tong-hop-nhung-tinh-nang-es6-noi-bat</guid>
            <pubDate>Sun, 08 Jul 2018 08:08:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Chi phí của Javascript]]></title>
            <description><![CDATA[
Khi các website chúng ta xây dựng ngày càng phụ thuộc vào JavaScript, thỉnh thoảng chúng ta cũng phải trả giá cho những gì được gửi về phía người dùng, theo những cách không dễ nhìn thấy . Trong bài viết này, tôi sẽ nói về lý do tại sao một chút **kỷ luật** có thể giúp nếu bạn muốn website của mình có thể tải và phản ứng một cách nhanh chóng trên các thiết bị di động.

> tl;dr: less code = less parse/compile + less transfer + less to decompress
>
> Dài quá ngại đọc: ít mã lệnh = ít thời gian phân tách/biên dịch + ít dung lượng trao đổi + ít phải giải nén

### 1\. Kết nối mạng

Khi nghĩ về chi phí cho JavaScript, hầu hết các lập trình viên nghĩ về mặt **chi phí tải và thực thi mã lệnh**. Kết nối Internet của người dùng càng chậm thì gửi nhiều bytes JavaScript về phía họ càng lâu.

![](https://cdn-images-1.medium.com/max/1600/1*U00XcnhqoczTuJ8NH8UhOw.png)

Điều này cũng có thể là một vấn đề với cả những nước đã phát triển, vì **kết nối mạng đang sử dụng** của một người dùng có thể không thật sự là 3G, 4G hay WiFi. Bạn có thể đang vào mạng WiFi của một quán cà phê, nhưng đang kết nối với một hotspot di động với tốc độ 2G.

Bạn có thể **giảm** chi phí truyền tải JavaScript bằng cách:

- **Chỉ chuyển đến người dùng phần mã lệnh cần thiết**. Kỹ thuật chia mã (code-splitting) có thể hữu ích ở đây.
- [**Tối giản hóa**](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer) mã lệnh (sử dụng Uglify cho ES5, [babel-minify](https://github.com/babel/minify) hay [uglify-es](https://www.npmjs.com/package/uglify-es) cho ES2015)
- [**Nén mã lệnh**](https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/optimize-encoding-and-transfer) tới mức tối đa, bằng cách dùng [Brotli](https://www.smashingmagazine.com/2016/10/next-generation-server-compression-with-brotli/) ~ [q11](https://twitter.com/paulcalvano/status/924660429846208514), Zopfli hay gzip. Brotli hoàn toàn qua mặt gzip khi xét về tỉ lệ nén. Giải thuật này đã giúp cho CertSimple giảm 17% dung lượng nén tập tin JS, và LinkedIn tiết kiệm 4% thời gian tải.
- **Xóa mã lệnh không dùng tới**. Với [DevTools code coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes), bạn có thể nhận dạng phần mã nào không được thực thi. Để loại bỏ mã nguồn không cần thiết, bạn có thể sử dụng kỹ thuật [“rung cây”](https://webpack.js.org/guides/tree-shaking/) (tree-shaking) của Webpack, các kỹ thuật tối ưu hóa nâng cao của [Closure Compiler](https://developers.google.com/closure/compiler/), và các plugin hỗ trợ tỉa tót mã lệnh như lodash-babel-plugin hay ContextReplacementPlugin của Webpack dành cho các thư viện như moment.js. Sử dụng babel-preset-env và browserlist để tránh tình trạng chuyển đổi những tính năng ES2015 đã được hỗ trợ mặc định trong các trình duyệt. Những lập trình viên nhiều kinh nghiệm có thể phân tích các bản đóng gói (bundles) của Webpack và tìm cách bỏ đi những thư viện phụ thuộc không cần thiết.
- **Lưu bộ đệm để giảm tải các yêu cầu mạng**. Xác định thời gian sống tối ưu cho các tập tin JS (max-age) và cung cấp các token thẩm định (ETag) để tránh phải truyền tải những bytes không cần thiết. Lưu bộ đệm bằng Service Worker có thể giúp ứng dụng của bạn trở nên chủ động hơn trong trường hợp mất kết nối, đồng thời cho phép bạn truy xuất đến những tính năng đặc biệt, chẳng hạn như [bộ đệm lưu trữ mã trong V8](https://v8project.blogspot.com/2015/07/code-caching.html). Hãy tìm hiểu về lưu đệm dài hạn với kỹ thuật băm tên tập tin (filename hashing).

![](https://cdn-images-1.medium.com/max/2000/1*8Spf9To8dzTG3Xy9s57oVA.png)

### 2\. Phân tách/Biên dịch

Sau khi đã tải, một trong những chi phí JavaScript **nặng nề** nhất là thời gian để một trình xử lý JS tiến hành phân tách/biên dịch mã nguồn. Trong Chrome DevTools, phân tách và biên dịch là những phần trong thời gian “Scripting” màu vàng, có thể thấy trong bảng Performance.

![](https://cdn-images-1.medium.com/max/1600/1*_4gNDmBlXxOF2-KmsOrKkw.png)

Phần Bottom-Up/Call Tree cho phép xem chính xác thời gian phân tách và biên dịch mã:

![](https://cdn-images-1.medium.com/max/1600/1*GdrVt_BTTzzBOIoyZZsQZQ.png)

_Trong bản Performance của Chrome DevTools, tìm đến phần Bottom-Up. Khi Runtime Call Stats trong V8 được kích hoạt, chúng ta có thể thấy thời gian cần thiết của những tiến trình như Phân Tách và Biên Dịch_

Nhưng mà, tại sao điều này lại quan trọng?

![](https://cdn-images-1.medium.com/max/1600/1*Dirw7RdQj9Dktc-Ny6-xbA.png)

**Mất nhiều thời gian để phân tách/biên dịch mã nguồn có thể làm chậm đi đáng kể thời gian người dùng có thể tương tác với website. Bạn càng gửi xuống nhiều tập tin JavaScript, trình duyệt càng tốn thời gian để phân tách và biên dịch trước khi website của bạn có thể tương tác được.**

![](https://cdn-images-1.medium.com/max/1600/1*6Y665hpxfWNMu2EXu3VGlw.png)

> Ăn byte nào trả byte đó, **JavaScript ngày càng trở nên đắt đỏ cho trình duyệt để xử lý hơn là một bức hình hay web font có cùng dung lượng tương ứng** – _Tom Dale - tác giả của Ember.js_

So với JavaScript, cũng có nhiều chi phí tham gia vào quá trình xử lý một bức ảnh có dung lượng tương tự (chúng vẫn cần phải được giải mã!) nhưng đối với phần cứng của thiết bị di động trung bình, có vẻ như tác động của JS có phần tiêu cực hơn đến khả năng tương tác của website.

![](https://cdn-images-1.medium.com/max/2000/1*PRVzNizF9jQ_QADF5lQHpA.png)

<small>
  _Các byte của JavaScript và hình ảnh cần đến những chi phí rất khác nhau. Hình ảnh thường không
  chặn luồng chính (main thread) hay ngăn cản tương tác với các giao diện trong quá trình giải mã và
  hiển thị lên màn hình (rasterization). Ngược lại JS có thể làm chậm quá trình tương tác vì các chi
  phí phân tách, biên dịch và thực thi._
</small>

Khi chúng ta nói về phân tách và biên dịch bị chậm, ngữ cảnh rất quan trọng – vì ở đây chúng ta đang nói về những chiếc điện thoại ở phân khúc trung bình. Người dùng bình dân có thể dùng những thiết bị với CPUs và GPUs chậm chạp, hoàn toàn không có bộ đệm L2/L3 và thậm chí còn bị giới hạn bộ nhớ.

> Năng lực mạng và năng lực của thiết bị thường không đi chung với nhau. Một người dùng sử dụng kết nối Fiber siêu tốc không nhất thiết phải có CPU tốt nhất để phân tách và thực thi JavaScript được gửi đến. Điều ngược lại cũng chính xác…kết nối cùi mía, nhưng CPU lại nhanh như điện. – Kristofer Baxter, LinkedIn.

Trong bài [JavaScript Start-up Performance](https://medium.com/reloading/javascript-start-up-performance-69200f43b201), tôi có lưu ý về chi phí phân tách một tập tin JavaScript (đơn giản) đã được giải nén có dung lượng khoảng 1MB trên phần cứng bình dân và cao cấp. **Thời gian phân tách/biên tịch mã lệnh giữa chiếc điện thoại nhanh nhất với chiếc điện thoại trung bình khác nhau từ 2 đến 5 lần.**

![](https://cdn-images-1.medium.com/max/2000/1*8BQ3bCYu1AVvJWPR1x8Yig.png)

<small>
  _**Thời gian phân tách một bản đóng gói JavaScript có dung lượng 1MB (~250KB gzipped)** giữa các
  thiết bị máy tính cá nhân và di động thuộc nhiều dòng khác nhau. Khi nhìn vào chi phí cho việc
  phân tách, chúng ta phải xem xét khi tập tin đã **được giải nén**, chẳng hạn như ~250KB gzipped
  khi giải nén thì khoảng 1MB._
</small>

Đối với những trang trong thực tế, như CNN.com thì sao?

**Trên một chiếc iPhone 8 cao cấp thì mất khoảng 4 giây để phân tách/biên dịch JS trên CNN.com, so với khoảng 13 giây cho một chiếc điện thoại bình dân (Moto G4)**. Điều này có thể tác động rõ ràng đến khả năng tương tác của người dùng với website.

![](https://cdn-images-1.medium.com/max/2000/1*7ysArXJ4nN0rQEMT9yZ_Sg.png)

<small>
  _So sánh thời gian phân tách mã nguồn trên chip A11 Bionic của Apple với Snapdragon 617 trên các
  thiết bị Android bình dân_
</small>

Điều này nêu bật tầm quan trọng của việc kiểm thử ứng dụng trên các phần cứng **trung bình** (như chiếc Moto G4) thay vì chiếc điện thoại trong túi của bạn. Nói gì thì nói, ngữ cảnh cũng quan trọng: **tối ưu hóa cho thiết bị và điều kiện kết nối mà người dùng _của bạn_ có.**

![](https://cdn-images-1.medium.com/max/1600/1*6oEpMEi_pjRNjmtN9i2TCA.png)

Các ứng dụng phân tích thống kê (analytics) có thể đưa ra một cái nhìn về [dòng thiết bị di động](https://crossbrowsertesting.com/blog/development/use-google-analytics-find-devices-customers-use/) mà người dùng thực tế của bạn đang sử dụng. Thông tin này đem đến cơ hội để hiểu hơn về các điều kiện giới hạn của CPU/GPU trên các thiết bị đó.

**Mà có thật là chúng ta đang gửi xuống người dùng quá nhiều JavaScript không? Hên xui :)**

Bằng cách sử dụng HTTP Archive (với khoảng 500K websites) để phân tích hiện trạng JavaScript trên các thiết bị di động, chúng ta có thể thấy rằng 50% website cần đến hơn 14 giây để có thể tương tác. Những trang này bỏ ra đến hơn 4 giây chỉ để phân tách và biên dịch JS.

![](https://cdn-images-1.medium.com/max/1600/1*sVgunAoet0i5FWEI9NSyMg.png)

Thời gian để tải và xử lý JS và các tài nguyên khác đóng một vai trò ở đây, và có lẽ không quá ngạc nhiên khi người dùng phải chờ một lúc trước khi cảm giác website đã có thể sử dụng. Rõ ràng chúng ta có thể làm tốt hơn.

**Loại bỏ những phần JavaScript không quan trọng trong trang có thể giảm thiểu thời gian truyền tải, quá trình phân tách và biên dịch vốn ngốn CPU, và cả việc ngốn bộ nhớ. Nó cũng làm cho website trở nên có thể tương tác được nhanh hơn.**

### 3\. Thời gian thực thi

Chi phí không chỉ nằm ở quá trình phân tách và biên dịch. **Quá trình thực thi JavaScript** (chạy mã lệnh sau khi đã phân tách/biên dịch) là một trong những thao tác phải xảy ra trong luồng chính. Thời gian thực thi quá lâu có thể làm trì hoãn thời gian người dùng có thể tương tác với website.

![](https://cdn-images-1.medium.com/max/1600/1*ec0wEKKVl7iQidBks3oDKg.png)

> If script executes for more than 50ms, time-to-interactive is delayed by the entire amount of time it takes to download, compile, and execute the JS — Alex Russell
>
> Nếu một đoạn mã phải thực thi trong hơn 50ms, thời gian để tương tác bị trì hoãn bằng nguyên cả thời gian cần thiết để tải, biên dịch và thực thi JS – Alex Russell

Để giải quyết vấn đề này, JavaScript tận dụng khả năng chia nhỏ thành từng phần (small chunks) để tránh không khóa hoàn toàn luồng chính. Bạn hãy tìm hiểu để xem có thể giảm thiểu công việc trong quá trình thực thi hay không.

### 4\. Một số khuôn mẫu để giảm thiểu chi phí truyền tải JavaScript

Khi bạn đang tìm cách để giảm thiểu thời gian truyền tải, phân tách và biên dịch JavaScript, có vài khuôn mẫu có thể hữu ích, như kỹ thuật chia nhỏ theo định tuyến (route-based chunking) hay còn gọi là [PRPL](https://developers.google.com/web/fundamentals/performance/prpl-pattern/).

PRPL là một kỹ thuật để tối ưu hóa khả năng tương tác trên website bằng cách chia nhỏ mã nguồn và lưu bộ đệm một cách quyết liệt.

![](https://cdn-images-1.medium.com/max/2000/1*VgdNbnl08gcetpqE1t9P9w.png)

Hãy xem những tác động nó có thể mang lại.

Chúng ta phân tính thời gian tải của những trang web di động thông dụng và các ứng dụng web tăng tiến (Progressive Web Apps – PWAs) bằng cách sử dụng Runtime Call Stats trong V8\. Như chúng ta có thể thấy, thời gian phân tách (phần màu cam) chiếm một phần lớn trong tổng thời gian của các website này.

![](https://cdn-images-1.medium.com/max/2000/1*9BMRW5i_bS4By_JSESXX8A.png)

[Wego](https://wego.com/), một trang sử dụng PRPL, xoay xở để giữ cho thời gian phân tách ở mức thấp, giúp cho website có thể tương tác nhanh hơn. Những trang còn lại cũng đã thực hiện kỹ thuật chia mã và dự toán hiệu suất (performance budgeting) để giảm chi phí JS.

### 5\. Những chi phí khác

JavaScript cũng có thể tác động đến hiệu suất của website theo những hướng khác:

- Bộ nhớ. Website có thể cảm thấy bị giựt (jank) hay tạm dừng thường xuyên do bộ gom rác (garbage collector - GC) hoạt động. Khi trình duyệt tiến hành thu hồi bộ nhớ, quá trình thực thi JS bị tạm dừng. Do đó khi trình duyệt thu hồi bộ nhớ quá thường xuyên, tiến trình JS cũng bị dừng liên tục hơn chúng ta mong muốn. Lập trình viên cần tránh bị rò rỉ bộ nhớ và tiến trình dừng của GC để website có thể hoạt động ổn định hơn.
- Trong quá trình chạy, mã JavaScript chạy quá lâu có thể khóa luồng chính, làm cho website trở nên không tương tác được. Bằng cách chia nhỏ công việc ra thành từng phần (sử dụng requestAnimationFrame() hay requestIdleCallback() để phân lịch) có thể giúp giảm thiểu các vấn đề về tương tác.

### 6\. Kỹ thuật Khởi động Tăng tiến (progressive bootstrapping)

Nhiều website xem tính ẩn hiện của nội dung trên trang là một chi phí đắt đỏ khi tối ưu hóa tính tương tác. Để có thể thực hiện tiến trình vẽ đầu tiên (first paint) một cách nhanh chóng, lập trình viên thường sử dụng kỹ thuật tạo nội dung trước ở phía server (server-side rendering - SSR), sau đó “nâng cấp” bằng cách gắn các hàm xử lý sự kiện sau khi JavaScript đã được tải về.

Nhưng hãy cẩn thận – kỹ thuật này cũng có chi phí riêng của nó. Bạn 1) nhìn chung sẽ gửi xuống một tập tin HTML _nặng ký hơn_ và có thể ảnh hưởng đến tính tương tác của site, hoặc 2) có thể đưa người dùng vào một vùng thung lũng huyền bí (uncanny valley) nơi một nửa trải nghiệm không thật sự có thể tương tác được, cho đến khi JavaScript hoàn tất quá trình xử lý.

Kỹ thuật Khởi động Tăng tiến có thể là một hướng tiếp cận tốt hơn. Bạn chỉ cần gửi xuống một trang vừa đủ có thể hoạt động, bao gồm chỉ HTML/JS/CSS cần thiết cho định tuyến hiện tại. Khi các tài nguyên khác đã được tải xong, ứng dụng có thể lazy-load vào và mở ra các chức năng khác.

![Kỹ thuật Khởi động Tăng tiến](https://cdn-images-1.medium.com/max/2000/1*zY03Y5nVEY21FXA63Qe8PA.png)

**Kỹ thuật tải mã lệnh tương ứng với những gì đang được hiển thị chính là cứu cánh. PRPL và Khởi động Tăng tiến là hai khuôn mẫu giúp đạt được mục tiêu này.**

### Kết luận

**Kích thước tập tin khi truyền tải rất quan trọng đối với những kết nối mạng cấp thấp. Thời gian phân tách mã nguồn lại quan trọng đối với những thiết bị có giới hạn về CPU. Chúng ta cần phải giữ cho các chỉ số này ở mức thấp.**

Nhiều nhóm phát triển đã thành công trong việc làm theo các dự toán hiệu suất nghiêm ngặt, để giảm thiểu thời gian truyền tải và phân tách/biên dịch. Bạn có thể xem hướng dẫn “[Can You Afford It?: Real-world Web Performance Budgets](https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/)” của Alex Russell về dự toán hiệu suất cho các thiết bị di động.

![](https://cdn-images-1.medium.com/max/1600/1*U8PJVNrA_tYADQ6_S4HUYw.png)

Nếu bạn đang phát triển một website hướng đến các thiết bị di động, hãy cố gắng hết sức để xây dựng nó trên phần cứng tiêu biểu, giữ cho thời gian phân tách/biên dịch JavaScript ở mức thấp, và thu nhận một dự toán hiệu suất để chắc chắn rằng nhóm của bạn luôn theo sát chi phí JavaScript.

### Tìm hiểu thêm

<YouTube id="_srJ7eHS3IM" />

<small>
  _Bài nói chuyện của tôi ở Chrome Dev Summit 2017 về chi phí cho JavaScript. Phần sau của bài nói
  có nhắc đến những ví dụ thực tế từ các trang như Pinterest hay Tinder._
</small>

- [JavaScript Start-up Performance](https://medium.com/reloading/javascript-start-up-performance-69200f43b201)
- [Solving the web performance crisis ](https://nolanlawson.github.io/frontendday-2016/) —  Nolan Lawson
- [Can you afford it? Real-world performance budgets](https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/)  —  Alex Russell
- [Evaluating web frameworks and libraries ](https://twitter.com/kristoferbaxter/status/908144931125858304) —  Kristofer Baxter
- [Kết quả thử nghiệm của Cloudflare cho giải thuật nén Brotli](https://blog.cloudflare.com/results-experimenting-brotli/) (lưu ý là nén Brotli động ở chất lượng cao có thể làm chậm quá trình hiển thị trang lần đầu tiên nên bạn cần đánh giá một cách thận trọng. Có khi bạn sẽ muốn nén theo phương pháp tĩnh hơn.)
- [Performance Futures ](https://medium.com/@samccone/performance-futures-bundling-281543d9a0d5) —  Sam Saccone

_Chân thành cám ơn Nolan Lawson, Kristofer Baxter và Jeremy Wagner vì những phản hồi của mọi người._
]]></description>
            <link>https://hungvn.com/blog/chi-phi-cua-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/chi-phi-cua-javascript</guid>
            <pubDate>Sat, 07 Jul 2018 15:01:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[10 mẹo CSS hữu ích bạn nên biết]]></title>
            <description><![CDATA[
**Pagespeed Optimization** (tối ưu hóa tốc độ trang) là một công việc mà hầu như mọi Web developer đều quan tâm và nên biết, mục đích của nó là đưa nội dung website đến với người xem nhanh nhất có thể.

Front-end developer thường làm việc với HTML, CSS, Javascript và các hình ảnh. Do đó, đây cũng là các đối tượng chính để chúng ta tối ưu tốc độ tải trang cho website. Tốc độ tải trang của website ngoài các yếu tố liên quan do server thì còn phụ thuộc vào kích thước và số lượng file phải tải về, do đó càng giảm được kích thước file lẫn số lượng file cần phải tải về thì cũng đồng thời tăng tốc độ tải file và giảm số lượng request lên server.

Ở bài này mình sẽ giới thiệu với các bạn 10 mẹo CSS hữu ích giúp giảm kích thước, số lượng file CSS, tối ưu file CSS và phát triển CSS dễ dàng hơn, nội dung bài gồm những phần sau:

1.  [Hạn chế sử dụng @import](#01-han-che-su-dung-import)
2.  [Sử dụng cách viết ngắn gọn (shorthand properties)](#02-su-dung-cach-viet-ngan-gon)
3.  [Khai báo class bổ trợ (Helper classes)](#03-khai-bao-class-bo-tro)
4.  [Hạn chế sử dụng CSS trong element của HTML (inline CSS attributes in HTML elements)](#04-han-che-su-dung-inline-css-trong-elements)
5.  [Giảm số lượng file CSS (Combine external CSS)](#05-giam-so-luong-file-css)
6.  [Giảm kích thước file CSS](#06-giam-kich-thuoc-file-css)
7.  [Áp dụng OOCSS (Object Oriented CSS)](#07-ap-dung-ky-thuat-oocss)
8.  [Đặt tên class và id một cách khoa học](#08-to-chuc-class-va-id-mot-cach-khoa-hoc)
9.  [Ngôn ngữ tiền xử lý CSS (CSS Preprocessor)](#09-ngon-ngu-tien-xu-ly-css)
10. [Sử dụng Koala-app khi làm việc với CSS](#10-gioi-thieu-so-luoc-koala-app)

## 1\. Hạn chế sử dụng @import

Hạn chế sử dụng @import hoặc tốt nhất là không nên sử dụng @import trong file CSS, vì nó sẽ **làm chậm quá trình tải** và **không sử dụng được khả năng tải file đồng thời của browser**. Để dễ hiểu bạn hãy xem ví dụ sau:

Mình có 2 file CSS là a.css và b.css được nhúng vào trang web như sau:

```html
<link rel="stylesheet" type="text/css" href="a.css" />
<link rel="stylesheet" type="text/css" href="b.css" />
```

Trong file b.css, bạn import file c.css:

```css
@import url(c.css);
```

Kết quả khi browser tải trang sẽ như thế này:

HTML downloada.cssb.cssc.css

Chú thích:

- Request 1: browser gửi request để lấy HTML về
- Request 2: browser gửi request để lấy a.css
- Request 3: browser gửi request để lấy b.css
- Request 4: browser gửi request để lấy c.css

Như các bạn thấy ở hình trên, để tải được c.css thì browser phải chờ để tải xong a.css.

**Lý do**: Vì browser khi đã tải xong b.css và bắt đầu đọc nội dung bên trong thì thấy **@import** yêu cầu phải tải thêm c.css, lúc này browser phải đứng chờ cho nhóm proccess trước đó chạy xong (trong trường hợp này là chờ a.css) thì mới bắt đầu tải tiếp c.css và tiếp tục render sau khi đã tải xong.

Trong khi đó nếu bạn loại bỏ @import url(c.css) trong b.css đi và nhúng trực tiếp c.css vào trang HTML

```html
<link rel="stylesheet" type="text/css" href="a.css" />
<link rel="stylesheet" type="text/css" href="b.css" />
<link rel="stylesheet" type="text/css" href="c.css" />
```

thì bạn sẽ có kết quả như sau:

HTML downloada.cssb.cssc.css

Lúc này browser sẽ bắt đầu tải file đồng thời không cần phải chờ cho a.css tải xong, sẽ rút ngắn được thời gian tải file xuống.

Như tiêu đề mình nói rằng nên **Hạn chế** sử dụng @import, vậy một câu hỏi nhỏ đặt ra là **khi nào thì nên dùng @import?**.

Theo mình thì khi **những định nghĩa CSS cần lệ thuộc vào một định nghĩa ở file CSS khác trước – thì khi đó nên dùng @import**, ví dụ bạn sử dụng các bộ thư viện reset CSS như [Normalize.css](https://necolas.github.io/normalize.css/), bạn cần reset tất cả các định nghĩa CSS về một chuẩn chung trước khi viết định nghĩa CSS tiếp theo – lúc này bạn sẽ dùng @import để import file Normalize.css vào trong file định nghĩa CSS của bạn, lý do sử dụng @import ở đây là để tránh cơ chế tải file đồng thời của browser và bắt buộc browser phải tải và áp định nghĩa CSS của Normalize.css trước rồi mới đến các định nghĩ CSS ở bên dưới @import.

Một câu hỏi tiếp theo **Nếu nhất thiết phải dùng @import như ví dụ trên, thì các nào khác để giải quyết thay vì dùng @import hay không?**.

Tất nhiên là có cách, đó là bạn copy toàn bộ nội dung của file Normalize.css vào trong file CSS của bạn, hay còn gọi là **Combine external CSS** mình sẽ giới thiệu phía bên dưới.

## 2\. Sử dụng cách viết ngắn gọn

Sử dụng cách viết ngắn gọn (shorthand properties) để dễ dàng thiết lập một số thuộc tính chỉ trên một dòng, đây cũng là một cách để bạn dễ dàng kiểm soát – theo dõi code của mình, đồng thời cũng hỗ trợ giảm số lượng ký tự trong file css và giảm kích thước file.

Lấy ví dụ đơn giản về cách thiết lập thuộc tính hình ảnh cho background

```css
background-color: #000;
background-image: url(bg-image.jpg);
background-repeat: no-repeat;
background-attachment: fixed;
background-position: center center;
```

Bạn có thể viết thành

```css
background: #000 url(bg-image.jpg) no-repeat fixed center center;
```

Cấu trúc shorthand của thuộc tính background như sau

```css
background: <color> <image> <repeat> <attachment> <position>;
```

Ngoài background thì còn có một số thuộc tính khác cũng có thể sử dụng shorthand như margin, padding, border, outline, … bạn có thể tham khảo thêm trên [Mozilla Developer Network (MDN)](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties). Ở cuối trang này có danh sách các thuộc tính có thể áp dụng shorthand.

Bên cạnh đó, nếu bạn thích khai báo mã màu HEX thì đối với một số mã màu thông dụng bạn cũng có thể viết ngắn gọn lại ví dụ như #FFF thay cho #FFFFFF hay #000 thay cho #000000\. Bạn có thể tham khảo cách chuyển đổi tại [CSS Color Converter](http://maettig.com/?page=PHP/CSS_Color_Converter).

## 3\. Khai báo class bổ trợ

Class bổ trợ (Helper classes) là những class được định nghĩa sẵn một số thuộc tính đơn giản và thường hay sử dụng. Ví dụ như text-align, font-weight, color… Class bổ trợ trong quá trình viết HTML các bạn chỉ cần thêm class đó vào mà không cần phải định nghĩa lại thuộc tính. Cách làm này khá hữu dụng khi bạn sử dụng một CSS framework và cần custom “rất ít” thuộc tính, hoặc bạn không chọn được tên class phù hợp cho element đó, hay element đó không cần xác định class để làm gì đó với javascript.

Điểm lợi của việc này ngoài việc bạn không cần định nghĩa lại một số thuộc tính không cần thiết, thì nếu CSS càng nhiều thì bạn sẽ tiết kiệm được khá nhiều thuộc tính cần khai báo lại và sẽ giảm được kích thước file CSS. Ví dụ:

Mình có các element sau cần viết CSS và mình đang dùng framework bootstrap:

```html
<p class="text-center">
  <button type="button" class="btn btn-success btn-md text-uppercase">Show More</button>
</p>
```

Thay vì mình cần phải viết CSS như sau để custom lại theo ý mình

```css
p {
  text-align: center;
  padding-top: 20px;
}
p > button {
  background-color: #fff;
  padding-right: 30px;
  padding-left: 30px;
}
```

Thì mình sẽ khai báo class bổ trợ để có thể tái sử dụng cho nhiều trường hợp khác về sau ( Những class có sẵn của bootstrap mình sẽ không liệt kê vào, vì hiện giờ mình cần custom các element này )

```css
.padding-top-20 {
  padding-top: 20px;
}
.padding-right-30 {
  padding-right: 30px;
}
.padding-left-30 {
  padding-left: 30px;
}
.btn.btn-bg-white {
  background-color: #fff;
}
```

Như vậy trong HTML mình sẽ khai báo như sau

```html
<p class="padding-top-20 text-center">
  <button
    type="button"
    class="btn btn-success btn-md btn-bg-white text-uppercase padding-right-30 padding-left-30"
  >
    Show More
  </button>
</p>
```

Như vậy thì về sau những class này mình có thể tái sử dụng rất nhiều lần ở rất nhiều element, và mình có thể bỏ đi khá nhiều công đoạn phải gõ lại code CSS khi có phát sinh thêm element mới.

Điều này mình học hỏi từ bootstrap và cảm thấy nó khá là hay. Bạn có thể tham khảo thêm các [helper class](https://getbootstrap.com/css/#helper-classes) hoặc [typography](https://getbootstrap.com/css/#type) của bootstrap để hiểu rõ hơn.

## 4\. Hạn chế sử dụng Inline CSS trong các elements

Ở đây, mình chỉ khuyên các bạn nên hạn chế sử dụng, vì điều này sẽ làm các bạn khó kiểm soát code CSS của mình. “Vạn bất đắc dĩ” cần giải quyết nhanh (hotfix) thì hãy dùng hoặc nếu chỉ dùng một lần hoặc là CSS động từ javascript thì có thể chấp nhận được.

Theo như [Google Pagespeed Insights](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery#CSSattributes) thì việc này sẽ làm code bị lặp lại không cần thiết và vi phạm [Chính sách Bảo mật Nội dung của W3](https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery#CSSattributes), trong một số trường hợp thì các attribute này sẽ bị chặn.

## 5\. Giảm số lượng file CSS

Gom các file CSS lại với nhau (Combine external CSS) là việc dễ làm nhất, thay vì phải viết thành nhiều file như header.css, navigation.css, footer.css… vào trong văn bản HTML thì bạn hãy gom các file này thành một file duy nhất. Nội dung file này sẽ chứa toàn bộ nội dung của các file trên, như vậy bạn sẽ giảm được nhiều request đến server và giảm tải cho server khá nhiều.

Thay vì sử dụng như vầy

```html
<link rel="stylesheet" href="/css/header.css" />
<link rel="stylesheet" href="/css/navigation.css" />
<link rel="stylesheet" href="/css/footer.css" />
```

Nên gom chúng lại thành

```html
<link rel="stylesheet" href="/css/style.css" />
```

## 6\. Giảm kích thước file CSS

Giảm kích thước file CSS được thực hiện bằng cách loại bỏ các khoảng trắng không cần thiết, dấu xuống hàng, dấu chấm phẩy cuối cùng trong class hoặc id… Công đoạn này còn được gọi là **minify**. Để tiện phân biệt giữa file chưa minify và file đã minify thì bạn nên thêm **.min** vào tên file đã minify. Ví dụ style.css sau khi minify sẽ thành style.min.css.

Bạn có thể truy cập vào [Clean CSS](http://www.cleancss.com/css-minify/) để thực hiện minify css hoặc sử dụng tool Koala-app mình sẽ giới thiệu bên dưới để tự động xuất file minify trong quá trình viết code.

## 7\. Áp dụng kỹ thuật OOCSS

**OOCSS** (Object Oriented CSS) – CSS hướng đối tượng, thật ra hướng đối tượng ở đây có nghĩa là bạn gom các thuộc tính giống nhau của 2 class cùng áp dụng cho một element thành một class để giảm thiểu sự lặp lại. Ví dụ:

Thay vì khai báo 2 class cho button như sau

```css
.btn-primary {
  display: inline-block;
  padding: 6px 12px;
  margin-bottom: 0;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.42857143;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  border: 1px solid transparent;
  border-radius: 4px;
  color: #fff;
  background-color: #337ab7;
  border-color: #2e6da4;
}

.btn-success {
  display: inline-block;
  padding: 6px 12px;
  margin-bottom: 0;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.42857143;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  border: 1px solid transparent;
  border-radius: 4px;
  color: #fff;
  background-color: #5cb85c;
  border-color: #5cb85c;
}
```

Mình sẽ gom một số thuộc tính của 2 class này thành một class khác có tên là btn:

```css
.btn {
  display: inline-block;
  padding: 6px 12px;
  margin-bottom: 0;
  font-size: 14px;
  font-weight: 400;
  line-height: 1.42857143;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  border: 1px solid transparent;
  border-radius: 4px;
}

.btn.btn-primary {
  color: #fff;
  background-color: #337ab7;
  border-color: #2e6da4;
}

.btn.btn-success {
  color: #fff;
  background-color: #5cb85c;
  border-color: #5cb85c;
}
```

Như vậy nếu sau này có thay đổi gì về một số thuộc tính chung của 2 class thì mình chỉ cần thay đổi class btn thì sẽ dễ dàng và nhanh hơn.

## 8\. Tổ chức class và id một cách khoa học

Việc này để hỗ trợ bạn sau này khi xem lại code của mình dễ dàng hơn và không bị rối với cách đặt tên của mình, đồng thời cũng dễ dàng nếu có áp dụng một số CSS preprocessor hay BEM.

Thay vì đặt tên

```css
.titlepost {
}

.headerpost {
}

.contentpost {
}
```

thì nên đặt thành

```css
.post {
}

.post-title {
}

.post-header {
}

.post-content {
}
```

hoặc tổ chức thành

```css
.post {
}

.post > .title {
}

.post > .header {
}

.post > .content {
}
```

## 9\. Ngôn ngữ tiền xử lý CSS

**Tiền xử lý CSS** (CSS Preprocessor) – là một cách mở rộng của CSS hoặc cũng có thể coi nó là một ngôn ngữ riêng. Mục đích của CSS preprocessor là để bạn dễ dàng cấu trúc các đoạn code CSS, giảm thời gian phải viết đi viết lại một đoạn code, dễ dàng áp dụng OOCSS… Nói cách khác bạn có thể hiểu CSS preprocessor gần như là một ngôn ngữ lập trình vì nó cũng có biến, kế thừa class, và dễ dàng tạo ra một thư viện riêng cho bạn quản lý, kế thừa và tái sử dụng ở những dự án khác.

CSS preprocessor hiện nay có rất nhiều nhưng phổ biến nhất hiện nay là [**Less**](http://lesscss.org/) và [**Sass.**](http://sass-lang.com/) Ở đây mình giới thiệu các bạn về Sass vì mình đang sử dụng nó thay cho Less, và CSS framework phổ biến – [Bootstrap, kể từ phiên bản 4 đã chuyển từ Less qua Sass](https://blog.getbootstrap.com/2015/08/19/bootstrap-4-alpha/). Về Sass các bạn xem [hướng dẫn cài đặt trên trang chủ](http://sass-lang.com/install).

Khi bắt đầu với một dự án có áp dụng Sass, việc đầu tiên mình thường làm là cấu trúc CSS thành nhiều file nhỏ để tránh nhồi nhét CSS vào một file và dễ dàng cho việc quản lý, tìm kiếm khi cần thiết. Mình thường cấu trúc các file Sass như sau:

```
scss
|-- style.scss
|-- _variable.scss
|-- _helper.scss
|-- _mixins.scss
|-- components
|-- -- _header.scss
|-- -- _footer.scss
|-- mixins
|-- -- button.scss
|-- -- label.scss
```

Trong file style.scss nội dung như sau:

```scss
@import "variable";
@impprt "helper";
@import "mixins";

// Components
@import "components/header";
@import "components/footer";
```

Chú thích:

- \_variable.scss: variable chứa các thông tin về các biến dùng chung
- \_helper.scss: helper sẽ chứa/import các class helper
- \_mixins.scss: mixins sẽ chứa/import các class custom hoặc class được tái sử dụng nhiều lần

Nội dung file \_helper.scss như mình đã nói sẽ tạo ra các class helper, nhưng ở đây mình áp dụng tính chất của Scss để tạo ra các class với ít dòng code nhất:

```scss
$numbersPX:
  "10" 10px,
  "15" 15px,
  "20" 20px,
  "25" 25px,
  "30" 30px;

// padding
@each $i in $numbersPX {
  .padding-#{nth($i, 1)} {
    padding: nth($i, 2) !important;
  }
  .padding-top-#{nth($i, 1)} {
    padding-top: nth($i, 2) !important;
  }
  .padding-bottom-#{nth($i, 1)} {
    padding-bottom: nth($i, 2) !important;
  }
  .padding-right-#{nth($i, 1)} {
    padding-right: nth($i, 2) !important;
  }
  .padding-left-#{nth($i, 1)} {
    padding-left: nth($i, 2) !important;
  }
}
```

khi Sass complier ra file CSS thì mình sẽ thu được kết quả như sau

```css
.padding-10 {
  padding: 10px !important;
}
.padding-top-10 {
  padding-top: 10px !important;
}
.padding-bottom-10 {
  padding-bottom: 10px !important;
}
.padding-right-10 {
  padding-right: 10px !important;
}
.padding-left-10 {
  padding-left: 10px !important;
}
.padding-15 {
  padding: 15px !important;
}
.padding-top-15 {
  padding-top: 15px !important;
}
.padding-bottom-15 {
  padding-bottom: 15px !important;
}
.padding-right-15 {
  padding-right: 15px !important;
}
.padding-left-15 {
  padding-left: 15px !important;
}
.padding-20 {
  padding: 20px !important;
}
.padding-top-20 {
  padding-top: 20px !important;
}
.padding-bottom-20 {
  padding-bottom: 20px !important;
}
.padding-right-20 {
  padding-right: 20px !important;
}
.padding-left-20 {
  padding-left: 20px !important;
}
.padding-25 {
  padding: 25px !important;
}
.padding-top-25 {
  padding-top: 25px !important;
}
.padding-bottom-25 {
  padding-bottom: 25px !important;
}
.padding-right-25 {
  padding-right: 25px !important;
}
.padding-left-25 {
  padding-left: 25px !important;
}
.padding-30 {
  padding: 30px !important;
}
.padding-top-30 {
  padding-top: 30px !important;
}
.padding-bottom-30 {
  padding-bottom: 30px !important;
}
.padding-right-30 {
  padding-right: 30px !important;
}
.padding-left-30 {
  padding-left: 30px !important;
}
```

## 10\. Giới thiệu sơ lược Koala App

[Koala app](http://koala-app.com) là một ứng dụng GUI hỗ trợ biên dịch Less, Sass, Compass và CoffeeScript sang CSS và JS. Koala App chạy được trên cả 3 môi trường Mac OS, Linux và Windows nên rất tiện nếu bạn cần thay đổi qua lại giữa các hệ điều hành. Ngoài ra, Koala App còn hỗ trợ minify cho cả CSS và JS.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2016/01/image01-700x453.png)

Sử dụng Koala App rất đơn giản, bạn chỉ cần mở lên và ấn dấu + trên đầu chương trình để chọn thư mục chứa các file cần xử lý, và Koala App sẽ tự động scan toàn bộ các folder bên trong và theo dõi khi có thay đổi.

Nếu bạn “siêng” thì có thể tham khảo cách để tự cấu hình project để Koala-app hoạt động theo ý mình [tại đây](https://github.com/oklai/koala/wiki/Using-project-settings).

Trên đây là những mẹo CSS rút ra từ kinh nghiệm làm việc của mình. Nếu bạn còn những mẹo hay khác thì đừng ngại chia sẻ bên dưới nhé.
]]></description>
            <link>https://hungvn.com/blog/10-meo-css-huu-ich-ban-nen-biet</link>
            <guid isPermaLink="true">https://hungvn.com/blog/10-meo-css-huu-ich-ban-nen-biet</guid>
            <pubDate>Wed, 27 Jun 2018 08:01:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tối ưu hiệu suất render để website mượt hơn]]></title>
            <description><![CDATA[
**Optimizing Performance** (tối ưu hóa hiệu suất) cho website là một công việc mà bất kỳ front-end developer nào cũng nên biết, mục đích là để trang web đáp ứng được 3 tiêu chí:

1.  **NHẸ**: Giảm kích thước trang web và các thành phần đi kèm như javascript, css, hình ảnh… nhằm đảm bảo **thời gian tải xuống ngắn hơn**. Chúng ta có thể dùng các bộ minify cho javascript, css…, nén các tập tin hình ảnh, font chữ, svg… ngoài ra còn có các kĩ thuật như code splitting, browser caching, HTTP caching…
2.  **NHANH** **Hiển thị nội dung trang web càng sớm càng tốt** bằng cách: chia cấu trúc DOM hợp lý, hạn chế blocking CSS/JS, hạn chế chỉnh sửa DOM tree, chia các file ra thành nhiều module, tải resource bất đồng bộ, tối ưu hóa các selector của CSS và JS…
3.  **MƯỢT**: Sau khi nội dung trang web đã được tải về và hiển thị thì việc tiếp theo là **bảo đảm các hiệu ứng animation, transition, scrolling… phải mượt**, không bị lag và giật (jank).

Trong 3 tiêu chí này, có 2 tiêu chí mà front-end developer chúng ta hằng ngày đều thực hiện là **nhẹ và nhanh**. Bằng cách sử dụng các framework (angularjs, reactjs…) và các bộ build tool (grunt, gulp, webpack…), các resource trong project ở môi trường production lúc nào cũng được minify và đóng gói đầy đủ, gọn gàng.

Do đó, trong bài này tôi sẽ hướng dẫn cho bạn cách đáp ứng được tiêu chí thứ 3, đó là **MƯỢT**, thứ mà ít có framework hay công cụ nào có thể hỗ trợ bạn được.

[![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image05-700x455.png)](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image05.png)

Trên thực tế, các web page yêu cầu độ mượt cao thường là các webpage có nhiều hiệu ứng, chuyển động, ví dụ như các trang landing page, giới thiệu sản phẩm, HTML5 game, hoặc các ứng dụng có animation chạy trên các thiết bị có cấu hình thấp. Bạn có thể xem qua một số trang sau:

- [http://world.mathigon.org/](http://world.mathigon.org/)
- [http://matthew.wagerfield.com/parallax/](http://matthew.wagerfield.com/parallax/)

## Làm thế nào để web page “mượt”?

Mượt ở đây chính là “Rendering Performance”, để tối ưu hiệu suất render chúng ta phải hiểu được quá trình render của browser.

### 60

… là số khung hình trên một giây mà các thiết bị phổ biến hiện nay hỗ trợ (60fps). Để cho trang web mượt thì tốc độ render phải đáp ứng được con số này. Tức là trong **1 giây** chúng ta phải cho ra **60 khung hình**. Với mỗi khung hình, chúng ta có 1 / 60 = 16,66 mili giây. Trên thực tế, browser còn có một số tác vụ khác phải làm bên cạnh việc render, vì thế chúng ta trừ hao còn lại khoảng 16ms.

Bất cứ animation hay transition nào, muốn đảm bảo được tốc độ 60fps thì phải cũng phải đảm bảo trong vòng **16ms phải render được một khung hình**, nếu không thì sẽ bị hiện tượng “frame skip”, hiệu ứng sẽ bị giật, lag.

### Cần phải làm những gì trong 16ms đó?

Để cho ra được 1 khung hình, đây là các việc mà browser phải thực hiện (**the pixel pipeline**):

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image19-700x107.png)

Giải thích ngắn gọn:

**1\. JavaScript**: là hoạt động execute code của javascript.

```javascript
document.getElementById("my-element").style.width = "300px";
```

**2\. Style calculation**: tính toán các thuộc tính theo các quy tắc từ file CSS (hoặc thẻ `<style>`, thuộc tính style).

```html
<div id="my-element" style="width: 300px">Hello</div>
```

**3\. Layout**: browser thực hiện “chia vùng” cho các element khi hiển thị trên màn hình, dựa trên các thuộc tính đã tính toán được từ bước Style.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image28.png)

**4\. Paint**: tô màu cho từng pixel, bao gồm việc: vẽ chữ (render font), hình ảnh, màu, vẽ các hiệu ứng CSS như border, box-shadow… Việc tô màu này được thực hiện trên nhiều “layer” cùng một lúc (phần sau sẽ giải thích rõ hơn về layer). Đây là bước chiếm nhiều thời gian nhất.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image23.png)

**5\. Composite**: gộp các layer đã được vẽ (ở bước Paint) và hiển thị lên màn hình theo đúng thứ tự của các layer đó.

Như vậy, chỉ với 16ms browser phải thực hiện 5 bước như trên để có thể render ra được 1 khung hình. Vậy để đảm bảo mọi thứ đều hoàn thành dưới 16ms, việc chúng ta cần làm là tối ưu từng bước. Cụ thể là:

- **JavaScript:**

- Dùng requestAnimationFrame.
- Dùng Web workers, Micro-task cho các tác vụ nặng.
- Profiling with Chrome DevTools.

- **Style:**
- Giảm độ phức tạp của selector
- Giảm số lượng element bị ảnh hưởng

- **Layout:**
- Hạn chế kích hoạt layout
- Sử dụng Flexbox
- Hạn chế forced synchronous layout.

- **Paint:**
- Paint là tác vụ xử lý lâu nhất
- Box-shadow, large image không tốt cho paint
- Tạo và quản lý layer hợp lý

- **Composite:**
- Sử dụng transform và opacity
- Quản lý các layer bằng Chrome DevTools

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image22-250x203.png)

## Từng bước tối ưu hiệu suất render

### Bước 1: Javascript

#### 1.1\. Sử dụng requestAnimationFrame để thực hiện các thay đổi trên UI.

Khi thực hiện các thay đổi trên UI bằng JavaScript, bạn sẽ muốn thực hiện nó ngay vào lúc bắt đầu của frame, lúc đó browser sẽ có được toàn bộ 16ms để thực hiện các thay đổi (JavaScript ⇒ Style ⇒ Layout ⇒ Paint ⇒ Composite). Để làm được điều này bạn cần dùng hàm requestAnimationFrame. Hàm này có chức năng “hẹn giờ” chạy vào đúng thời điểm của frame tiếp theo.

```javascript
/**
 * If run as a requestAnimationFrame callback, this
 * will be run at the start of the frame.
 */
function updateScreen(time) {
  // Make visual updates here.
}
requestAnimationFrame(updateScreen);
```

Một số đoạn code trên mạng hoặc trong các framework thường sử dụng hàm setTimeout, tuy nhiên hàm được gọi bởi setTimeout sẽ không khởi chạy lúc bắt đầu frame, dẫn đến việc không tận dụng hết được khoảng thời gian 16ms, do đó gây ra hiện tượng frame skip, gây giật, lag.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image071-700x300.png)

#### 1.2\. Chuyển các tác vụ nặng sang Web workers

Đối với các tác vụ nặng như encode/decode, xử lý dữ liệu lớn… chúng ta nên chuyển tác vụ đó sang [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/basic_usage). Web Workers hoạt động trên một thread riêng biệt, sẽ giúp giảm tải cho UI Thread và giúp tiết kiệm được thời gian xử lý.

```javascript
var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);

// The main thread is now free to continue working on other things...

dataSortWorker.addEventListener("message", function (evt) {
  var sortedData = evt.data;
  // Update data on screen...
});
```

Tuy nhiên, Web Workers không thể tương tác với DOM tree, do đó một số tác vụ không thể chuyển qua Web Workers được. Trong trường hợp này ta có thể áp dụng phương pháp “micro-task”: chia nhỏ task ra, sau đó sử dụng requestAnimationFrame để cập nhật UI. Lúc này, nếu mỗi task nhỏ có thời gian thực thi bé hơn 16ms thì sẽ tránh được hiện tượng giật, lag như khi chạy cả task lớn.

```javascript
var taskList = breakBigTaskIntoMicroTasks(monsterTaskList);
requestAnimationFrame(processTaskList);

function processTaskList(taskStartTime) {
  var taskFinishTime;

  do {
    // Assume the next task is pushed onto a stack.
    var nextTask = taskList.pop();

    // Process nextTask.
    processTask(nextTask);

    // Go again if there’s enough time to do the next task.
    taskFinishTime = window.performance.now();
  } while (taskFinishTime - taskStartTime < 3);

  if (taskList.length > 0) requestAnimationFrame(processTaskList);
}
```

#### 1.3\. Sử dụng Chrome DevTools để “điều tra” JavaScript execution

Chrome DevTools là công cụ cực kỳ hữu ích. Ở tab “Timeline” của Chrome DevTools, bạn có thể kiểm tra được độ mượt của web page bằng cách:

1.  Nhấn nút Record (hoặc Ctrl + R trên Windows, Command + R trên Mac)
2.  Thực hiện animation / transition trên trang web chính
3.  Nhấn nút Stop Record.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image24-700x515.png)

Chrome DevTools sẽ hiển thị toàn bộ các thông tin liên quan đến các tác vụ JavaScript ⇒ Style ⇒ Layout ⇒ Paint ⇒ Composite. Bạn có thể kiếm tra để xem tác vụ nào chiếm nhiều thời gian nhất và gây ra frame skip.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image06.png)

### Bước 2: Style calculation

Cố gắng giữ cho selector của bạn càng đơn giản càng tốt, và giảm số lượng element bị ảnh hưởng bởi selector, ví dụ:

Nên:

```css
.title {
  /* styles */
}
```

Không nên:

```css
.box:nth-last-child(-n + 1) .title {
  /* styles */
}
```

Không nên:

```css
*,
*:before,
*:after {
  /* styles */
}
```

Nên:

```css
body {
  /* styles */
}
```

Việc sử dụng các selector này cần phải cân bằng giữa việc code gọn gàng đẹp đẽ và hiệu suất. Khi sử dụng các selector phức tạp thì browser cần phải thực hiện nhiều tính toán, nhưng nếu chỉ sử dụng các selector đơn giản thì lại khiến code của chúng ta khó quản lý.

Giải pháp ở đây là chúng ta nên sử dụng một số kỹ thuật quản lý style như: [BEM (Block, Element, Modifier)](https://bem.info/), [PostCSS](https://github.com/postcss/postcss). Các công cụ này sẽ giúp chúng ta vừa dễ quản lý code CSS ở môi trường dev, và cũng vừa đảm bảo hiệu suất ở môi trường production sau khi build.

### Bước 3: Layout

#### 3.1\. Hạn chế kích hoạt tính toán layout

Việc thay đổi một số thuộc tính CSS của element có thể kích hoạt browser tính toán lại layout của element đó.

```css
.box {
  width: 20px;
  height: 20px;
}

/**
 * Changing width and height
 * triggers layout.
 */
.box--expanded {
  width: 200px;
  height: 350px;
}
```

Khi một element bị thay đổi layout thì thường là các element khác cũng sẽ bị thay đổi theo (kích thước, vị trí…). Do đó nếu trang của bạn có nhiều element và việc kích hoạt layout diễn ra quá thường xuyên thì hoàn toàn không tốt cho performance.

Bạn có thể sử dụng Chrome DevTools để kiểm tra xem web page của bạn có bị kích hoạt layout quá nhiều hay không.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image02-700x489.png)

Ví dụ trong hình này, bạn có thể thấy sự kiện Layout chiếm tới 20.636ms, vượt qua con số 16ms và tất nhiên là sẽ dẫn đến frame skip, số lượng element cần tính toán lại layout là 1618 (rất nhiều).

Để biết được những thuộc tính nào sẽ kích hoạt Layout (và lý do vì sao), bạn có thể tra cứu ở trang [http://csstriggers.com/](http://csstriggers.com/) – công cụ do một Googler viết cho mục đích tra cứu.

#### 3.2\. Sử dụng các thuộc tính mới của CSS3

CSS3 có cung cấp một số thuộc tính mới không những giúp chúng ta canh chỉnh layout dễ hơn mà còn giúp tăng hiệu suất rất nhiều. Điển hình là Flexbox, việc sử dụng flexbox để canh chỉnh layout sẽ dễ hơn so với cách dùng float truyền thống.

Xem bài hướng dẫn tuyệt vời về Flexbox: [http://css-tricks.com/snippets/css/a-guide-to-flexbox/](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)

Về hiệu suất, dưới đây là 2 hình ảnh đo hiệu suất của việc kích hoạt layout trên 1300 elements.

Sử dụng Float:

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image16-700x476.png)

Sử dụng Flexbox:

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image14-700x454.png)

Có thể thấy con số “Self Time” giảm từ **~14ms** chỉ còn **~3.5ms**, đó là một sự thay đổi rất đáng kể.

#### 3.3\. Hạn chế kích hoạt layout sớm

Hãy xem xét đoạn code sau: thay đổi kích thước của 3 elements

```javascript
// Read
var h1 = element1.clientHeight;

// Write (invalidates layout)
element1.style.height = h1 * 2 + "px";

// Read (triggers layout)
var h2 = element2.clientHeight;

// Write (invalidates layout)
element2.style.height = h2 * 2 + "px";

// Read (triggers layout)
var h3 = element3.clientHeight;

// Write (invalidates layout)
element3.style.height = h3 * 2 + "px";
```

Khi một element (DOM) được ghi giá trị mới thì layout sẽ bị đánh dấu **giá trị hết hiệu lực** (invalidates) và sẽ được tính toán lại tại một thời điểm nào đó. Để đảm bảo performance, browser sẽ thực hiện tính toán lại layout vào **thời điểm bắt đầu của frame tiếp theo**.

Tuy nhiên nếu trong thời gian **frame hiện tại chưa kết thúc**, ta muốn lấy giá trị kích thước của element thì lúc này browser buộc phải thực hiện **tính toán layout lại sớm hơn** so với thông thường để có thể trả về kết quả. Hiện tượng này gọi là “forced synchronous layout” – tạm dịch “kích hoạt layout sớm”, và nó gây ra vấn đề về performance khi ta phải thực hiện nhiều tác vụ hơn trong 1 frame.

Để giải quyết, cách nhanh nhất là chúng ta sẽ “đọc trước, ghi sau”.

```javascript
// Read
var h1 = element1.clientHeight;
var h2 = element2.clientHeight;
var h3 = element3.clientHeight;

// Write (invalidates layout)
element1.style.height = h1 * 2 + "px";
element2.style.height = h2 * 2 + "px";
element3.style.height = h3 * 2 + "px";

// Document reflows at end of frame
```

Hoặc sử dụng requestAnimationFrame để “hẹn giờ” cho cả 3 thao tác ghi vào frame tiếp theo:

```javascript
// Read
var h1 = element1.clientHeight;

// Write
requestAnimationFrame(function () {
  element1.style.height = h1 * 2 + "px";
});

// Read
var h2 = element2.clientHeight;

// Write
requestAnimationFrame(function () {
  element2.style.height = h2 * 2 + "px";
});
```

Bằng cách này, cả 3 thao tác ghi đều sẽ được thực hiện một lần trong frame tiếp theo, tốt hơn cho hiệu suất.

Bạn sẽ thấy rõ tác dụng của việc hạn chế layout sớm trong một số trường hợp thực tế như sau “Layout thrashing”:

```javascript
// Puts the browser into a read-write-read-write cycle.
for (var i = 0; i < paragraphs.length; i++) {
  paragraphs[i].style.width = box.offsetWidth + "px";
}
```

Như đoạn code trên, layout sẽ liên tục bị trigger và kích hoạt sớm ở trong vòng lặp (read: box.offsetWidth, và write: paragraphs[i].style.width) điều này là thảm họa cho browser

(hình: dấu chấm than vàng là báo hiệu **forced synchronous layout**).

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image17.png)

Nếu đã biết về vấn đề forced synchronous layout, đoạn code trên nên được viết lại như sau:

```javascript
// Read.
var width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth() {
  for (var i = 0; i < paragraphs.length; i++) {
    // Now write.
    paragraphs[i].style.width = width + "px";
  }
}
```

Nếu cảm thấy việc quản lý layout quá phức tạp, bạn có thể tham khảo sử dụng thư viện [FastDOM](https://github.com/wilsonpage/fastdom), thư viện này giúp bạn quản lý các tác vụ read/write để đảm bảo không gây ra forced synchronous layout.

### Bước 4: Paint

#### 4.1\. Dùng Chrome Developer Tools để phát hiện vấn đề performance khi paint

Bất kỳ sự thay đổi nào trên màn hình browser đều yêu cầu quá trình paint, animation, transition, lúc bôi đen đoạn text hay cả con trỏ nhấp nháy ở textbox.

Để biết được browser phải vẽ lại những phần nào trên màn hình, bạn có thể bật chức năng “Show paint rectangles” ở tab “Rendering” trong Chrome Developer Tools.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image18.png)

Những vùng bị vẽ lại sẽ được tô và hiển thị màu xanh lá cây trên màn hình.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image21-700x454.png)

Bạn có thể xem chi tiết hoạt động vẽ của browser bằng cách kích hoạt chế độ “Paint profiler” ở tab “Timeline” khi record.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image03.png)

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image04.png)

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image15-700x454.png)

Ở chế độ này, bạn có thể kiểm tra **quá trình vẽ của tất cả các element** trong web page. Dựa vào các thông tin này bạn có thể phân tích và đưa ra hướng giải quyết phù hợp nếu quá trình paint mất quá nhiều thời gian. Một số yếu tố khiến quá trình paint diễn ra chậm:

- Các hiệu ứng CSS phức tạp: box-shadow, gradient, curves
- Các element chồng đè lên nhau.
- Các hình ảnh có kích thước quá lớn
- …

#### 4.2\. Sử dụng hợp lý các layer

Trên thực tế, quá trình vẽ diễn ra song song trên nhiều các layer khác nhau, việc phân chia các layer hợp lý sẽ giúp tiết kiệm được thời gian vẽ rất nhiều.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image27-700x602.png)

Ví dụ trong trường hợp này, khi bạn cuộn trang thì browser phải vẽ lại layer trên cùng (text), còn layer hình bên dưới có vị trí cố định, không có gì thay đổi nên không cần phải vẽ lại nữa. Các layer này sẽ được gộp lại (ở bước cuối cùng – composite) và hiển thị lên màn hình.

**Làm sao để tạo layer?**

Vẽ – Paint – là tác vụ nặng nhất, chiếm nhiều thời gian nhất trong các bước, do đó bạn có thể thấy rõ được lợi ích của việc **phân chia các layer làm sao cho browser ít phải vẽ lại nhất**.

Một layer (compositor layer) sẽ được tạo khi bạn sử dụng thuộc tính will-change (trên Chrome, Opera, Firefox) thuộc tính này báo hiệu cho browser biết element sẽ có sự thay đổi, do đó sẽ đưa element này vào một layer mới.

```css
.moving-element {
  will-change: transform;
}
```

Đối với các browser không hỗ trợ will-change bạn có thể sử dụng thuộc tính 3D transform để “ép buộc” tạo layer mới:

```css
.moving-element {
  transform: translateZ(0);
}
```

Cần lưu ý, việc tạo layer mới sẽ yêu cầu thêm bộ nhớ và tác vụ để quản lý các layer, do đó bạn không nên tạo quá nhiều layer, và chiến lược tao layer ở đây không cố định mà còn tùy thuộc vào tính chất của các animation, transition có trên website của bạn.

**Không nên:** (layer explosions – tạo ra quá nhiều layer không cần thiết)

```css
* {
  will-change: transform;
  transform: translateZ(0);
}
```

## Bước 5: Composite

Tại bước này, browser sẽ tiến hành gộp các compositor layer đã được vẽ (ở bước 4) và hiển thị lên màn hình.

Trường hợp lý tưởng nhất cho performance là bỏ qua 2 bước Layout và Paint, công việc của browser chỉ là thay đổi các compositor layer để tạo ra một frame.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image20-700x107.png)

Để làm được điều đó, bạn chỉ được thay đổi các thuộc tính mà Compositor có thể xử lý độc lập (mà không cần phải kích hoạt Layout và Paint). Các thuộc tính đó là **transform** và **opacity**.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image12-700x525.png)

Tuy nhiên trên thực tế chúng ta cần phải thay đổi nhiều thuộc tính hơn nữa để đáp ứng được yêu cầu khi animate các hiệu ứng. Do đó, giải pháp chính là phải **<span class="c0">tạo và quản lý được các layer một cách hợp lý</span>**. Để quản lý được các layer, bạn có thể sử dụng công cụ Chrome Developer Tools.

Trong tab “Timeline” đánh dấu vào mục Paint

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image26.png)

Tiến hành record và chọn phần Paint trên kết quả hiển thị

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image08.png)

Ở đây bạn sẽ thấy thẻ “Layer” trong phần thông tin của frame

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image001.png)

Từ đây bạn có thể tra cứu toàn bộ các frame mà web page đang có.

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image13-700x525.png)

Danh sách các layer được liệt kê dưới dạng cây (layer tree), preview dạng 3D, có thông tin về kích thước, bộ nhớ, lý do layer được tạo…

## Tổng kết

Như vậy là ta đã đi từng bước để có thể tối ưu hiệu suất render cho web page:

- **JavaScript**
       – Dùng requestAnimationFrame
       – Dùng Web workers, Micro-task cho tác vụ nặng
       – Profiling with Chrome DevTools

- **Style**
       – Giảm độ phức tạp của selector
       – Giảm số lượng element bị ảnh hưởng

- **Layout**
       – Hạn chế kích hoạt layout
       – Sử dụng Flexbox
       – Hạn chế forced synchronous layout.

- **Paint**
       – Paint là tác vụ xử lý lâu nhất
       – Box-shadow, large image không tốt cho paint
       – Tạo và quản lý layer hợp lý

- **Composite**
       – Sử dụng transform và opacity
       – Quản lý các layer bằng Chrome DevTools

Sau khi đã thực hiện những bước trên, web page của bạn sẽ hoạt động mượt mà, trơn tru với 60fps. Chúc bạn thành công!

60FPS FOR THE WIN!

# Chuyện ngoài lề

Ở Silicon Straits Saigon, chúng tôi có một bài test dành cho Front-end Developer, đó là implement hiệu ứng scrolling sau (ảnh động, load hơi lâu): [http://bit.ly/1CCYx9y](https://bit.ly/1CCYx9y)

Các bạn có thể vận dụng những kiến thức có được trong bài viết này để “thử sức” với hiệu ứng trên.

Đây là bài làm của tôi, mặc dù không được hoàn hảo nhưng có thể dùng được cho mục đích tham khảo.

Link: [http://trungdq88.github.io/css-stuffs/delay-scroll/](https://trungdq88.github.io/css-stuffs/delay-scroll/)

Timeline Record:

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image05-700x455.png)

Layers (một phần):

![](https://4qr7k2a2xza2vctux33bisalkw-wpengine.netdna-ssl.com/wp-content/uploads/2015/11/image10-700x299.png)

## Các nguồn tham khảo trong bài viết:

Một số hình ảnh và code mẫu:

- Google Developer: [https://developers.google.com/web/fundamentals/performance/](https://developers.google.com/web/fundamentals/performance/)
- Preventing Layout Thrashing:[http://wilsonpage.co.uk/preventing-layout-thrashing/](http://wilsonpage.co.uk/preventing-layout-thrashing/)

Các trang web có hiệu ứng đẹp:

- [http://world.mathigon.org/](http://world.mathigon.org/)
- [http://matthew.wagerfield.com/parallax/](http://matthew.wagerfield.com/parallax/)

Khóa học:

- Udacity Course: Browser Rendering Optimization – Building 60 FPS Web Apps: [https://www.udacity.com/course/browser-rendering-optimization–ud860](https://www.udacity.com/course/browser-rendering-optimization--ud860)

Các nguồn khác:

- Web Workers: [https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/basic_usage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/basic_usage)
- BEM: [https://bem.info/](https://bem.info/)
- PostCSS: [https://github.com/postcss/postcss](https://github.com/postcss/postcss)
- CSS Trigger: [http://csstriggers.com/](http://csstriggers.com/)
- Guide to Flexbox: [http://css-tricks.com/snippets/css/a-guide-to-flexbox/](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)
- FastDOM: [https://github.com/wilsonpage/fastdom](https://github.com/wilsonpage/fastdom)
]]></description>
            <link>https://hungvn.com/blog/toi-uu-hieu-suat-render-de-website-muot-hon</link>
            <guid isPermaLink="true">https://hungvn.com/blog/toi-uu-hieu-suat-render-de-website-muot-hon</guid>
            <pubDate>Tue, 26 Jun 2018 07:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[10 câu hỏi phỏng vấn mà Javascript Developer nên biết]]></title>
            <description><![CDATA[
Tại hầu hết các công ty, người quản lý phải tin tưởng các developers, cho họ tham gia các cuộc phỏng vấn kỹ thuật để đánh giá các kỹ năng ứng cử viên. Nếu bạn làm tốt như một ứng cử viên, bạn sẽ cần phải phỏng vấn. Đây là cách làm.

### It Starts With People

In [“How to Build a High Velocity Development Team”](https://medium.com/javascript-scene/how-to-build-a-high-velocity-development-team-4b2360d34021), Tôi đã nêu một vài điểm đáng để lặp lại:

> “Nothing predicts business outcomes better than an exceptional team. If you’re going to beat the odds, you need to invest here, first.”

Như Marcus Lemonis đã nói, cần tập trung vào 3 P’s:

---

> “People, Process, Product”

---

<YouTube id="37rMZSA6oLk" />

Your early hires should be very strong, senior-level candidates. People who can hire and mentor other developers, and help the mid-level and junior developers you’ll eventually want to hire down the road.

Read [“Why Hiring is So Hard in Tech”](https://medium.com/javascript-scene/why-hiring-is-so-hard-in-tech-c462c3230017) for a good breakdown of the general do’s and don’ts of candidate evaluation.

---

> The best way to evaluate a candidate is a pair programming exercise.

---

Pair program with the candidate. Let the candidate drive. Watch and listen more than you talk. A good project might be to pull tweets from the Twitter API and display them on a timeline.

That said, no single exercise will tell you everything you need to know. An interview can be a very useful tool as well, but don’t waste time asking about syntax or language quirks. You need to see the big picture. Ask about architecture and paradigms — the big decisions that can have a major impact on the whole project.

Syntax and features are easy to Google. It’s much harder to Google for software engineering wisdom or the common paradigms and idioms JavaScript developers pick up with experience.

JavaScript is special, and it plays a critical role in almost every large application. What is it about JavaScript that makes it meaningfully different from other languages?

Here are some questions that will help you explore the stuff that really matters:

#### 1\. Can you name two programming paradigms important for JavaScript app developers?

JavaScript is a multi-paradigm language, supporting **imperative/procedural** programming along with **OOP** (Object-Oriented Programming) and **functional programming**. JavaScript supports OOP with **prototypal inheritance**.

**Good to hear:**

- Prototypal inheritance (also: prototypes, OLOO).
- Functional programming (also: closures, first class functions, lambdas).

**Red flags:**

- No clue what a paradigm is, no mention of prototypal oo or functional programming.

#### 2\. What is functional programming?

Functional programming produces programs by composing mathematical functions and avoids shared state & mutable data. Lisp (specified in 1958) was among the first languages to support functional programming, and was heavily inspired by lambda calculus. Lisp and many Lisp family languages are still in common use today.

Functional programming is an essential concept in JavaScript (one of the two pillars of JavaScript). Several common functional utilities were added to JavaScript in ES5.

**Good to hear:**

- Pure functions / function purity.
- Avoid side-effects.
- Simple function composition.
- Examples of functional languages: Lisp, ML, Haskell, Erlang, Clojure, Elm, F Sharp, OCaml, etc…
- Mention of features that support FP: first-class functions, higher order functions, functions as arguments/values.

**Red flags:**

- No mention of pure functions / avoiding side-effects.
- Unable to provide examples of functional programming languages.
- Unable to identify the features of JavaScript that enable FP.

#### 3\. What is the difference between classical inheritance and prototypal inheritance?

**Class Inheritance:** instances inherit from classes (like a blueprint — a description of the class), and create sub-class relationships: hierarchical class taxonomies. Instances are typically instantiated via constructor functions with the _`new`_ keyword. Class inheritance may or may not use the _`class`_ keyword from ES6.

**Prototypal Inheritance:** instances inherit directly from other objects. Instances are typically instantiated via factory functions or _`Object.create()`._ Instances may be composed from many different objects, allowing for easy selective inheritance.

---

> In JavaScript, prototypal inheritance is simpler &
> more flexible than class inheritance.

---

**Good to hear:**

- Classes: create tight coupling or hierarchies/taxonomies.
- Prototypes: mentions of concatenative inheritance, prototype delegation, functional inheritance, object composition.

**Red Flags:**

- No preference for prototypal inheritance & composition over class inheritance.

#### 4\. What are the pros and cons of functional programming vs object-oriented programming?

**OOP Pros:** It’s easy to understand the basic concept of objects and easy to interpret the meaning of method calls. OOP tends to use an imperative style rather than a declarative style, which reads like a straight-forward set of instructions for the computer to follow.

**OOP Cons:** OOP Typically depends on shared state. Objects and behaviors are typically tacked together on the same entity, which may be accessed at random by any number of functions with non-deterministic order, which may lead to undesirable behavior such as race conditions.

**FP Pros:** Using the functional paradigm, programmers avoid any shared state or side-effects, which eliminates bugs caused by multiple functions competing for the same resources. With features such as the availability of point-free style (aka tacit programming), functions tend to be radically simplified and easily recomposed for more generally reusable code compared to OOP.

FP also tends to favor declarative and denotational styles, which do not spell out step-by-step instructions for operations, but instead concentrate on **what** to do, letting the underlying functions take care of the **how**. This leaves tremendous latitude for refactoring and performance optimization, even allowing you to replace entire algorithms with more efficient ones with very little code change. (e.g., memoize, or use lazy evaluation in place of eager evaluation.)

Computation that makes use of pure functions is also easy to scale across multiple processors, or across distributed computing clusters without fear of threading resource conflicts, race conditions, etc…

**FP Cons:** Over exploitation of FP features such as point-free style and large compositions can potentially reduce readability because the resulting code is often more abstractly specified, more terse, and less concrete.

More people are familiar with _OO_ and imperative programming than functional programming, so even common idioms in functional programming can be confusing to new team members.

FP has a much steeper learning curve than OOP because the broad popularity of OOP has allowed the language and learning materials of OOP to become more conversational, whereas the language of FP tends to be much more academic and formal. FP concepts are frequently written about using idioms and notations from lambda calculus, algebras, and category theory, all of which requires a prior knowledge foundation in those domains to be understood.

**Good to hear:**

- Mentions of trouble with shared state, different things competing for the same resources, etc…
- Awareness of FP’s capability to radically simplify many applications.
- Awareness of the differences in learning curves.
- Articulation of side-effects and how they impact program maintainability.
- Awareness that a highly functional codebase can have a steep learning curve.
- Awareness that a highly OOP codebase can be extremely resistant to change and very brittle compared to an equivalent FP codebase.
- Awareness that immutability gives rise to an extremely accessible and malleable program state history, allowing for the easy addition of features like infinite undo/redo, rewind/replay, time-travel debugging, and so on. Immutability can be achieved in either paradigm, but a proliferation of shared stateful objects complicates the implementation in OOP.

**Red flags:**

- Unable to list disadvantages of one style or another — Anybody experienced with either style should have bumped up against some of the limitations.

**Learn More:**

- [The Two Pillars of JavaScript Part 1](https://medium.com/javascript-scene/the-two-pillars-of-javascript-ee6f3281e7f3) — Prototypal OO.
- [The Two Pillars of JavaScript Part 2](https://medium.com/javascript-scene/the-two-pillars-of-javascript-pt-2-functional-programming-a63aa53a41a4) — Functional Programming.

#### 5\. When is classical inheritance an appropriate choice?

The answer is never, or almost never. Certainly never more than one level. Multi-level class hierarchies are an anti-pattern. I’ve been issuing this challenge for years, and the only answers I’ve ever heard fall into one of several [common misconceptions](https://medium.com/javascript-scene/common-misconceptions-about-inheritance-in-javascript-d5d9bab29b0a). More frequently, the challenge is met with silence.

> “If a feature is sometimes useful
> and sometimes dangerous
> and if there is a better option
> then **always use the better option**.”
> ~ Douglas Crockford

**Good to hear:**

- Rarely, almost never, or never.
- A single level is sometimes OK, from a framework base-class such as React.Component.
- “Favor object composition over class inheritance.”

#### 6\. When is prototypal inheritance an appropriate choice?

There is more than one type of prototypal inheritance:

- **Delegation** (i.e., the prototype chain).
- **Concatenative** (i.e. mixins, _`Object.assign()`_).
- **Functional** (Not to be confused with functional programming. A function used to create a closure for private state/encapsulation).

Each type of prototypal inheritance has its own set of use-cases, but all of them are equally useful in their ability to enable **composition,** which creates **has-a** or **uses-a** or **can-do** relationships as opposed to the **is-a** relationship created with class inheritance.

**Good to hear**:

- In situations where modules or functional programming don’t provide an obvious solution.
- When you need to compose objects from multiple sources.
- Any time you need inheritance.

**Red flags:**

- No knowledge of when to use prototypes.
- No awareness of mixins or _`Object.assign()`._

#### 7\. What does “favor object composition over class inheritance” mean?

This is a quote from [“Design Patterns: Elements of Reusable Object-Oriented Software”](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612). It means that code reuse should be achieved by assembling smaller units of functionality into new objects instead of inheriting from classes and creating object taxonomies.

In other words, use **can-do, has-a,** or **uses-a** relationships instead of **is-a** relationships.

**Good to hear:**

- Avoid class hierarchies.
- Avoid brittle base class problem.
- Avoid tight coupling.
- Avoid rigid taxonomy (forced is-a relationships that are eventually wrong for new use cases).
- Avoid the gorilla banana problem (“what you wanted was a banana, what you got was a gorilla holding the banana, and the entire jungle”).
- Make code more flexible.

**Red Flags:**

- Fail to mention any of the problems above.
- Fail to articulate the difference between composition and class inheritance, or the advantages of composition.

#### 8\. What are two-way data binding and one-way data flow, and how are they different?

Two way data binding means that UI fields are bound to model data dynamically such that when a UI field changes, the model data changes with it and vice-versa.

One way data flow means that the model is the single source of truth. Changes in the UI trigger messages that signal user intent to the model (or “store” in React). Only the model has the access to change the app’s state. The effect is that data always flows in a single direction, which makes it easier to understand.

One way data flows are deterministic, whereas two-way binding can cause side-effects which are harder to follow and understand.

**Good to hear:**

- React is the new canonical example of one-way data flow, so mentions of React are a good signal. Cycle.js is another popular implementation of uni-directional data flow.
- Angular is a popular framework which uses two-way binding.

**Red flags:**

- No understanding of what either one means. Unable to articulate the difference.

#### 9\. What are the pros and cons of monolithic vs microservice architectures?

A monolithic architecture means that your app is written as one cohesive unit of code whose components are designed to work together, sharing the same memory space and resources.

A microservice architecture means that your app is made up of lots of smaller, independent applications capable of running in their own memory space and scaling independently from each other across potentially many separate machines.

**Monolithic Pros:** The major advantage of the monolithic architecture is that most apps typically have a large number of cross-cutting concerns, such as logging, rate limiting, and security features such audit trails and DOS protection.

When everything is running through the same app, it’s easy to hook up components to those cross-cutting concerns.

There can also be performance advantages, since shared-memory access is faster than inter-process communication (IPC).

**Monolithic cons:** Monolithic app services tend to get tightly coupled and entangled as the application evolves, making it difficult to isolate services for purposes such as independent scaling or code maintainability.

Monolithic architectures are also much harder to understand, because there may be dependencies, side-effects, and magic which are not obvious when you’re looking at a particular service or controller.

**Microservice pros:** Microservice architectures are typically better organized, since each microservice has a very specific job, and is not concerned with the jobs of other components. Decoupled services are also easier to recompose and reconfigure to serve the purposes of different apps (for example, serving both the web clients and public API).

They can also have performance advantages depending on how they’re organized because it’s possible to isolate hot services and scale them independent of the rest of the app.

**Microservice cons:** As you’re building a new microservice architecture, you’re likely to discover lots of cross-cutting concerns that you did not anticipate at design time. A monolithic app could establish shared magic helpers or middleware to handle such cross-cutting concerns without much effort.

In a microservice architecture, you’ll either need to incur the overhead of separate modules for each cross-cutting concern, or encapsulate cross-cutting concerns in another service layer that all traffic gets routed through.

Eventually, even monolthic architectures tend to route traffic through an outer service layer for cross-cutting concerns, but with a monolithic architecture, it’s possible to delay the cost of that work until the project is much more mature.

Microservices are frequently deployed on their own virtual machines or containers, causing a proliferation of VM wrangling work. These tasks are frequently automated with container fleet management tools.

**Good to hear:**

- Positive attitudes toward microservices, despite the higher initial cost vs monolthic apps. Aware that microservices tend to perform and scale better in the long run.
- Practical about microservices vs monolithic apps. Structure the app so that services are independent from each other at the code level, but easy to bundle together as a monolithic app in the beginning. Microservice overhead costs can be delayed until it becomes more practical to pay the price.

**Red flags:**

- Unaware of the differences between monolithic and microservice architectures.
- Unaware or impractical about the additional overhead of microservices.
- Unaware of the additional performance overhead caused by IPC and network communication for microservices.
- Too negative about the drawbacks of microservices. Unable to articulate ways in which to decouple monolithic apps such that they’re easy to split into microservices when the time comes.
- Underestimates the advantage of independently scalable microservices.

#### 10\. What is asynchronous programming, and why is it important in JavaScript?

Synchronous programming means that, barring conditionals and function calls, code is executed sequentially from top-to-bottom, blocking on long-running tasks such as network requests and disk I/O.

Asynchronous programming means that the engine runs in an event loop. When a blocking operation is needed, the request is started, and the code keeps running without blocking for the result. When the response is ready, an interrupt is fired, which causes an event handler to be run, where the control flow continues. In this way, a single program thread can handle many concurrent operations.

User interfaces are asynchronous by nature, and spend most of their time waiting for user input to interrupt the event loop and trigger event handlers.

Node is asynchronous by default, meaning that the server works in much the same way, waiting in a loop for a network request, and accepting more incoming requests while the first one is being handled.

This is important in JavaScript, because it is a very natural fit for user interface code, and very beneficial to performance on the server.

**Good to hear:**

- An understanding of what blocking means, and the performance implications.
- An understanding of event handling, and why its important for UI code.

**Red flags:**

- Unfamiliar with the terms asynchronous or synchronous.
- Unable to articulate performance implications or the relationship between asynchronous code and UI code.

---

### Conclusion

Stick to high-level topics. If they can answer these questions, that typically means that they have enough programming experience to pick up language quirks & syntax in a few weeks, even if they don’t have a lot of JavaScript experience.

Don’t disqualify candidates based on stuff that’s easy to learn (including classic CS-101 algorithms, or any type of puzzle problem).

What you really need to know is, “does this candidate understand how to put an application together?”

That’s it for the spoken interview.

In real interviews, I place a much stronger emphasis on coding challenges and **_watching candidates code._** Those topics are covered in depth in my [“Master the JavaScript Interview”](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36) series.
]]></description>
            <link>https://hungvn.com/blog/10-cau-hoi-phong-van-ma-javascript-developer-nen-biet</link>
            <guid isPermaLink="true">https://hungvn.com/blog/10-cau-hoi-phong-van-ma-javascript-developer-nen-biet</guid>
            <pubDate>Sat, 23 Jun 2018 22:11:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Local Storage, Session Storage và Cookie]]></title>
            <description><![CDATA[
# Sự khác nhau và cách sử dụng Local Storage, Session Storage và Cookie

Bạn bị lẫn lộn giữa **session storage**, **local storage** và **cookies**? Bài viết dưới đây sẽ giúp bạn hiểu rõ được sự khác nhau giữa 3 cách lưu trữ này. Các kiểu không gian lưu trữ khác nhau có sẵn cho các dữ liệu có thể trên máy chủ hoặc máy khách, cho phép chúng ta chọn lựa theo nhu cầu.

## 1\. Local storage

### Giới thiệu:

- Khả năng lưu trữ vô thời hạn: Có nghĩa là chỉ bị xóa bằng JavaScript, hoặc xóa bộ nhớ trình duyệt, hoặc xóa bằng localStorage API.
- Lưu trữ được 5MB: Local Storage cho phép bạn lưu trữ thông tin tương đối lớn lên đến 5MB, lưu được lượng thông tin lớn nhất trong 3 loại.
- Không gửi thông tin lên server như Cookie nên bảo mật tốt hơn.

### Trình duyệt hỗ trợ:

| Trình duyệt              | Phiên bản |
| ------------------------ | --------- |
| Chrome                   | >= 4.0    |
| Internet Explorer / Edge | >= 8.0    |
| Firefox                  | >= 3.5    |
| Safari                   | >= 4.0    |
| Chrome                   | >= 11.5   |

Để kiểm tra xem trình duyệt có hỗ trợ localStorage hay không thì chúng ta dùng typeof như sau:

```javascript
if (typeof Storage !== "undefined") {
  //Nếu có hỗ trợ
  //Thực hiện thao tác với Storage
  alert("Trình duyệt của bạn hỗ trợ Storage");
} else {
  //Nếu không hỗ trợ
  alert("Trình duyệt của bạn không hỗ trợ Storage");
}
```

### Xem localStorage bằng trình duyệt

Để xem localstorage bằng trình duyệt các bạn vào trang web cần xem (ở đây mình ví dụ với trang web [http://book.framgia.vn/](http://book.framgia.vn/)) và sau đó các bạn ấn F12 (hoặc Ctrl + shift + i) sau đó làm theo như hình sau:

![](https://images.viblo.asia/9bcca9a7-81d0-46af-86de-6a461f67db95.png)

Chọn tab Application, di chuyển đến Storage để thấy các Storage của trình duyệt. Để xem các local Storage đang được lưu trữ, mở rộng phần Local Storage như hình. Ở đây ta có thể thấy có 2 biến Local Storage đang được lưu là _pusherTransportEncrypted_ và _lang_ với giá trị của 2 biến được hiển thị bên cạnh (cột Value). Như vậy, cột Key chính là danh sách các biến local Storage đang được lưu và cột Value là các giá trị tương ứng. Để xóa hết các giá trị local Storage này đi, bạn có thể chọn biểu tượng cấm (Clear All) hoặc chọn bên cạnh là biểu tượng dấu X (Delete Selected).

### Sử dụng

- Khởi tạo localStorage

```javascript
localStorage.setItem("key", "value");
// hoặc
localStorage.key = "value";
// hoặc
localStorage["key"] = "value";
```

> Trong đó: key là tên biến, value là giá trị của biến muốn gán vào.

- Để lấy giá trị localStorage và sử dụng, ta dùng getItem

```javascript
localStorage.getItem("key");
// hoặc
localStorage.key;
```

**Ví dụ** cụ thể như sau:

![](https://images.viblo.asia/42ea1e74-930e-4457-b8a2-125036df89dc.png)

- Để lấy số lượng localStorage đã có trong trình duyệt, sử dụng length như sau:

```javascript
localStorage.length;
```

Ví dụ

```javascript
if (typeof Storage !== "undefined") {
  //Nếu hỗ trợ
  var data = localStorage.length;
  console.log(data);
} else {
  // Nếu không hỗ trợ
  alert("Trình duyệt của bạn không hỗ trợ");
}
```

- Để xóa 1 biến trong localStorage, sử dụng removeItem(tên_key)

```javascript
localStorage.removeItem(key);
```

Hoặc xóa tất cả các biến trong localStorage, sử dụng clear

```javascript
localStorage.clear();
```

## 2\. Session Storage

### Giới thiệu:

- Lưu trên Client: Cũng giống như localStorage thì sessionStorage cũng dùng để lưu trữ dữ liệu trên trình duyệt của khách truy cập (client).
- Mất dữ liệu khi đóng tab: Dữ liệu của sessionStorage sẽ mất khi bạn đóng trình duyệt.
- Dữ liệu không được gửi lên Server
- Thông tin lưu trữ nhiều hơn cookie (ít nhất 5MB)

### Trình duyệt hỗ trợ

| Trình duyệt              | Phiên bản |
| ------------------------ | --------- |
| Chrome                   | >= 5.0    |
| Internet Explorer / Edge | >= 8.0    |
| Firefox                  | >= 2      |
| Safari                   | >= 4.0    |
| Opera                    | >= 10.5   |

Vì sessionStorage cũng nằm trong gói Storage nên các bạn cũng có thể sử dụng lại đoạn code kiểm tra trình duyệt có hỗ trợ Storage hay không ở phía trên.

### Xem Session Storage bằng trình duyệt

Tương tự như localStorage, có thể chọn mở rộng mục Session Storage để xem các giá trị được lưu trữ.

### Sử dụng

sessionStorage cũng có cú pháp và cách sử dụn các thuộc tính, phương thức như localStorage:

```javascript
if (typeof Storage !== "undefined") {
  // Khởi tạo sesionStorage
  sessionStorage.setItem("name", "Ted Mosby");
  // get sessionStorage
  sessionStorage.getItem("name");
  // lấy ra số lượng session đã lưu trữ
  sessionStorage.length;
  // xóa 1 item localStorage
  sessionStorage.removeItem("name");
  // xóa tất cả item trong sessionStorage
  sessionStorage.clear();
} else {
  alert("Trình duyệt của bạn không hỗ trợ!");
}
```

## 3\. Cookie

### Giới thiệu:

- Thông tin được gửi lên server: Cookie sẽ được truyền từ server tới browser và được lưu trữ trên máy tính của bạn khi bạn truy cập vào ứng dụng, mỗi khi người dùng tải ứng dụng, trình duyệt sẽ gửi cookie để thông báo cho ứng dụng về hoạt động trước đó của bạn. Vì vậy đừng bao giờ lưu trữ những thông tin quan trọng, yêu cầu tính bảo mật cao vào cookie vì nó hoàn toàn có thể bị sửa đổi và đánh cắp, thấp chí có thể lợi dụng điều này để tấn công website của bạn.
- Cookie chủ yếu là để đọc phía máy chủ (cũng có thể được đọc ở phía máy khách), localStorage và sessionStorage chỉ có thể được đọc ở phía máy khách.
- Có thời gian sống: Mỗi cookie thường có khoảng thời gian timeout nhất định do lập trình viên xác định trước.
- Lưu trữ: cho phép lưu trữ tối đa 4KB và vài chục cookie cho một domain.

### Xem cookie bằng trình duyệt

Tương tự như localStorage, có thể chọn mở rộng mục Cookies để xem các giá trị cookie được lưu trữ

![](https://images.viblo.asia/94606099-1b52-4377-b354-69dd4cc0fa5e.png)

### Sử dụng

Cookie có thể được tạo bằng nhiều cách, bài viết này sẽ trình bày về sử dụng cookie trong javascript. JavaScript có thể tạo, đọc, và xóa cookies với document.cookie.

- Tạo cookie: Javascript có thể tạo cookie như sau:

```javascript
document.cookie = "username=Ted Mosby";
```

Chúng ta cũng có thể thêm vào ngày hết hạn cho cookie

```javascript
document.cookie = "username=Ted Mosby; expires=Thu, 18 Dec 2018 8:00:00 UTC";
```

Hoặc đặt hẹn giờ sau bao lâu cookie sẽ hết hạn với max-age (tính bằng giây)

```javascript
document.cookie = "username=Ted Mosby; max-age=9000";
```

- Đọc cookie:

```javascript
var x = document.cookie;
```

document.cookie sẽ trả lại tất cả cookie trong một chuỗi tring kiểu như: cookie1 = giá trị; cookie2 = giá trị; cookie3 = giá trị;

Hoặc để lấy giá trị của 1 cookie, có thể viết một hàm như sau:

```javascript
function getCookie(cname) {
  var name = cname + "=";
  var decodedCookie = decodeURIComponent(document.cookie);
  var ca = decodedCookie.split(";");
  for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == " ") {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      return c.substring(name.length, c.length);
    }
  }
  return "";
}
```

> Tham số truyền vào là cname - tên cookie muốn lấy giá trị.

> Tạo một biến name và thêm vào "=" để tìm kiếm trong chuỗi document.cookie

> Chia document.cookie dựa trên dấu ; thành một mảng nhiều phần tử và gán mảng đấy cho biến ca

> Vòng lặp `(i=0; i<ca.length; i++)` để đọc mỗi giá trị `c = ca[i]`

> Nếu cookie được tìm thấy `(c.indexOf(name)==0)`, trả về giá trị của cookie `(c.substring(name.length,c.length)`. Nếu cookie không được tìm thấy, trả về ''

Ví dụ muốn lấy giá trị của cookie tên là language thì ta có thể gọi getcookie('language') và kêt quả trả về là giá trị của cookie có tên đó.

```javascript
var lang = getCookie("language");
console.log(lang);
```

Kết quả:

![](https://images.viblo.asia/de11cb91-6bf0-47a2-840f-2ba067b391cb.png)

- Thay đổi giá trị cookie: Trong javascript, bạn có thể thay đổi một cookie giống như cách mà bạn tạo ra cookie, tức là ghi đè giá trị mới lên cookie đã có:

```javascript
document.cookie = "username=Barney Stinson; expires=Wed, 26 Dec 2018 8:00:00 UTC";
```

- Kiểm tra cookie: Để kiểm tra coookie, có thể xây dựng hàm như sau:

```javascript
function checkCookie() {
  var username = getCookie("username");
  if (username != "") {
    alert("Welcome again " + username);
  } else {
    username = prompt("Please enter your name: ", "");
    if (username != "" && username != null) {
      setCookie("username", username, 365);
    }
  }
}
```

> Nếu cookie được thiết lập, nó sẽ hiển thị một lời chào

> Nếu cookie không được thiết lập, nó sẽ hiển thị một prompt box, hỏi tên của người dùng, lưu trữ tên của người dùng ở cookie trong 365 ngày, bằng việc gọi function setCookie đã được viết ở trên

- Xóa cookie: Để xóa một cookie chỉ cần xét lại giá trị ngày hết hạn expires về một thời điểm đã qua

```javascript
document.cookie = "username=; expires=Thu, 01 Jan 1970 00:00:00 UTC";
```

Tham khảo tại [https://www.w3schools.com/js/js_cookies.asp](https://www.w3schools.com/js/js_cookies.asp)

### 4\. Thông tin thêm

- Vì localStorage và sessionStorage được lưu trữ trên trình duyệt của người dùng, nên các bạn cần phải xem xét nội dung lưu trữ có liên quan đến vấn đề bảo mật hay không.
- Và cũng chính vì localStorage và sessionStorage được lưu trữ trên trình duyệt nên việc sử dụng nó sẽ không ảnh hưởng đến hiệu xuất của trang web nhưng nó sẽ làm nặng trình duyệt của người dùng (không đáng kể).
- Về phạm vi: **sessionStorage**: giới hạn trong một cửa sổ hoăc thẻ của trình duyệt. Một trang web được mở trong hai thẻ của cùng một trình duyệt cũng không thể truy xuất dữ liệu lẫn nhau. Như vậy, khi bạn đóng trang web thì dữ liệu lưu trong sessionStorage hiện tại cũng bị xóa. Còn **localStorage**: có thể truy xuất lẫn nhau giữa các cửa sổ trình duyệt. Dữ liệu sẽ được lưu trữ không giới hạn thời gian.
]]></description>
            <link>https://hungvn.com/blog/local-storage-session-storage-va-cookie</link>
            <guid isPermaLink="true">https://hungvn.com/blog/local-storage-session-storage-va-cookie</guid>
            <pubDate>Sat, 23 Jun 2018 18:40:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Load Javascript với async và defer]]></title>
            <description><![CDATA[
# Vấn đề

**Javascript** là 1 trong những tài nguyên chặn trang, có nghĩa là việc hiển thị HTML có thể bị chặn hay làm chậm bởi Javascript. Khi parser đọc đến `<script>` tag, bất kể là inline hay là external file, quá trình parse sẽ tạm dừng để fetch script đó về và execute. Việc này có thể là vấn đề nếu chúng ta load nhiều file Javascript trên trang, làm tăng thời gian load trang mặc dù có thể việc hiển thị html ở trang không thực sự phụ thuộc vào những file javascript đó. Và may mắn thay, thẻ `<script>` có 2 thuộc tính, đó là **async và defer**, cho phép chúng ta kiểm soát và load những file này theo ý muốn, tránh chặn quá trình load trang.

# Mô tả cách thực thi

![](legend.png)

## `<script>`

```html
<html>
  <head>
    ...
  </head>
  <body>
    ...
    <script src="script.js" />
    ....
  </body>
</html>
```

Với thẻ script không có thuộc tính gì khác thì HTML file sẽ được parse cho đến khi gặp phải thẻ script, đến lúc này thì quá trình parse sẽ tạm dùng và để fetch script file về (nếu là external file), sau đó execute những code script này, sau đó mới tiếp tục lại quá trình parse html

![](script.png)

## `<script async>`

```javascript
<script async src="script.js" />
```

Với thẻ script có thuộc tính async, khi quá trình parse html gặp phải script này, nó sẽ vẫn tiếp tục parse html cho đến khi script này được download xong, thì quá trình parse html mới tạm dừng để execute những code script này, sau đó lại tiếp tiếp quá trình parse html

![](script-async.png)

## `<script defer>`

```javascript
<script defer src="script.js" />
```

Với thẻ script có thuộc tính defer, quá trình parse html sẽ không bị dừng lại mà parse cho đến khi hoàn thành, quá trình download các script file được tiến hành song song, và cuối cùng thì sẽ execute những script code này khi html đã parse xong.

![](script-defer.png)

# Vậy nên dùng khi nào?

Nó phụ thuộc vào từng tình huống cụ thể.

## Quy tắc như sau:

- Nếu script là 1 module tách biệt, không phụ thuộc vào script nào khác thì nên sử dụng async cho load và execute với trang luôn
- Nếu script phụ thuộc vào script khác, hoặc bị script khác phụ thuộc, thì nên dùng defer, để load và execute theo thứ tự
- Nếu script nhỏ và các script khác phụ thuộc vào nó, thì cho load inline và không cần async hay defer

## Ngoài ra nên cân nhắc 1 số câu hỏi trước khi thêm các thuộc tính này

### 1\. Thẻ script đang nằm ở đâu trong trang

Async và defer có thể rất cần thiết nếu thẻ script không nằm ở cuối trang. HMTL document được parse theo thứ tự, từ thẻ mở `<html>` cho đến thẻ đóng `</html>`. Nếu script năm ngay gần cuối thẻ đóng `</body>` thì việc sử dụng async hay defer thì cũng không có ý nghĩa lắm bởi vì việc parse html đã gần xong xuôi, và javascript không còn block gì html nữa.

### 2\. Script đó có độc lập không?

Với những file script không phụ thuộc vào những file khác, thì thuộc tính async dùng cho script đó là việc nên làm, vì nó load và execute script song song, giảm thời gian tải trang, kết quả cuối cùng nhanh hơn.

### 3\. Script có yêu cầu việc load DOM xong mới thực hiện?

Trong nhiều trường hợp, các script chứa đựng code tương tác với DOM, hoặc phụ thuộc vào các thành phần trên trang, yêu cầu trang phải parse xong thì mới execute script. Thông thường thì những file như thế sẽ được đặt ở cuối trang để chắc chắn mọi thử đã được parse. Tuy nhiên chúng ta có thể dùng thuộc tính defer thay thế, đảm bảo script sẽ được execute khi trang đã tải xong.

### 4.Script nhỏ và các file khác phụ thuộc vào nó?

Nếu script dung lượng nhỏ, và các file khác phụ thuộc vào nó, thì nên để script đó inline. Mặc dù nó block quá trình parse HTML, nhưng nó không đáng kể vì dung lượng nhỏ.

# Lợi ích

Với việc biết cách sử dụng các thuộc tính async, defer hợp lí thì tốc độ load trang sẽ được cải thiện hơn, mang lại cảm giác thích thú cho người dùng. Vì vậy nó giúp tối ưu SEO, giúp tăng điểm Google Page Speed ([https://developers.google.com/speed/pagespeed/insights](https://developers.google.com/speed/pagespeed/insights))
]]></description>
            <link>https://hungvn.com/blog/load-javascript-voi-async-va-defer</link>
            <guid isPermaLink="true">https://hungvn.com/blog/load-javascript-voi-async-va-defer</guid>
            <pubDate>Sat, 23 Jun 2018 18:29:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Functional Programming - Phần 3 - Buông bỏ]]></title>
            <description><![CDATA[
Functional Programming là một con đường khác, một phương pháp tư duy khác trong coding. Ở tầm nhìn trừu tượng hơn, người ta xếp Functional Programming vào nhóm "Declarative", còn OOP thuộc nhóm "Imperative".

Từ các bài học ngữ pháp chúng ta đã biết 2 kiểu câu: câu trần thuật (Declarative Sentence), và câu mệnh lệnh (Imperative Sentence).

Lập trình theo lối "Imperative Programming" là sắp xếp một loạt các mệnh lệnh liên tiếp, để máy tính thực thi tuần tự từng bước. Ở đây người ta tập trung vào "how". Nào, hãy làm thế này, rồi làm thế kia... Một hình thức "cầm tay chỉ việc".

Ví dụ trên trang web có 4 boxes màu đỏ thế này:

```javascript
<style>
.box {
  width: 100px;
  height: 100px;
  float: left;
  margin: 10px;
  background-color: red;
}
.hide {
  display: none;
}
</style>
<div class="box hide"></div>
<div class="box hide"></div>
<div class="box hide"></div>
<div class="box hide"></div>
```

Mấy boxes này đang ẩn, ta cần làm chúng hiện ra bằng cách loại bỏ class "hide" đi.

Các giáo viên tin học đáng kính ở trường xưa thường dạy viết kiểu như thế này:

```javascript
// tìm hết các tags có class "box':
const els = document.querySelectorAll(".box");
// quét tất cả các tags tìm thấy
for (let i = 0; i < els.length; i++) {
  // với tag thứ i
  let el = els[i];
  // xóa bỏ class "hide" để cho tag hiện lên
  el.classList.remove("hide");
  // nếu còn phần tử phía sau thì tăng i lên 1 đơn vị
  // quay lại với xử lý tag thứ i + 1
}
```

Họ dùng code hướng dẫn cho máy tính làm từng nhiệm vụ.

Người tu luyện Functional Programming không tư duy theo cách đó.

### No for/while

"Declarative Programming" là tập trung vào "what". Chúng ta chỉ cần định nghĩa những quy tắc đầu vào, đầu ra. Chẳng hạn "nếu input là 1 thì output là 2". Phần còn lại để máy tính xử lý.

Người tu luyện Functional Programming không cần for loop.

Code như thế này nhìn mới mẻ hơn nhiều:

```javascript
const getElements = selector => {
  return Array.from(document.querySelectorAll(selector));
};

const getRemover = el => {
  return className => {
    el.classList.remove(className);
    return el;
  };
};

const els = getElements(".box")
  .map(getRemover)
  .map(removeClass => removeClass("hide"));

console.log(els);
```

Trước tiên chúng ta tạo ra 1 pure function getElements dùng để lấy các elements trên trang thông qua CSS Selector. Tập hợp này vốn là ArrayLike, ta dùng Array.from chuyển thành Array thực sự để có thể tận dụng các phương thức trong Array prototype.

Ở đây ta định nghĩa input là CSS Selector, output là 1 mảng DOM Elements.

Còn getRemover lại là 1 higher-order function. Có thể gọi nó bằng cách chaining getRemover(DOMElement)(classToRemove). Chúng ta lợi dụng đặc tính của higher-order function, sau 2 lần map thì chạm tới function do getRemover ném lại.

Ở đây ta định nghĩa input là DOM Element, output là `function() {nhận input là className và output là DOM Element đã mất đi class đó}`.

Code như vậy ta có thể đem logic dùng lại ở nhiều chỗ khác nhau, chỉ cần thay đổi input. Ví dụ loại bỏ class float-left khỏi tất cả các thẻ div.

```javascript
const els = getElements("div")
  .map(getRemover)
  .map(removeClass => removeClass("float-left"));
```

### No if/else

Người tu luyện Functional Programming cũng không cần if/else.

Thậm chí họ còn tạo ra cả một chiến dịch [Anti-IF](https://francescocirillo.com/pages/anti-if-campaign)!

Có nhiều cách để loại bỏ hoàn toàn if/else ra khỏi chương trình của bạn. Đơn giản nhất là dùng ternary.

#### Ternary

Trong JavaScript, ternary - tam phân - có tên gọi chính thức là Toán tử Điều kiện - Conditional Operator. Nó là cách viết ngắn gọn của if/else.

Hãy xem đoạn code dài dòng, rẽ nhánh phức tạp như sau:

```javascript
let title = "Mr.";
if (person.gender === "female") {
  if (!person.gotMarried) {
    title = "Ms.";
  } else {
    title = "Mrs.";
  }
}
```

Có thể được viết gọn lại thành:

```javascript
const title = person.gender === "female" ? (!person.gotMarried ? "Ms." : "Mrs.") : "Mr.";
```

Không còn if/else nữa.

Ta cũng vô hình trung loại bỏ được var, let vì không cần gán lại giá trị cho title.

#### Logical operators

Cách thứ 2 là khai thác sức mạnh ngầm của các logical operators &&, ||. Đây là những toán tử logic. Hôm trước có bạn viết [1 cái TIL ngắn](https://kipalog.com/posts/--va--) khá hay. Sau đây ta quan sát chúng kỹ hơn qua lăng kính Functional Programming.

Giả sử có đoạn code như sau:

```javascript
const sayHello = () => {
  console.log("Hello, bonjour, nihao");
  return true;
};

const doNothing = () => {
  console.log("Do nothing");
  return false;
};

const greet = hasClient => {
  if (hasClient) {
    sayHello();
  } else {
    doNothing();
  }
};

greet(true); // => 'Hello, bonjour, nihao'
greet(false); //=> 'Do nothing'
```

Về mặt logic, hàm greet() kiểm tra điều kiện nếu có khách thì chào, nếu không thì không làm gì cả.

Theo định nghĩa của && và ||, chúng ta biết:

- expr1 && expr2 trả về expr1 nếu expr1 là falsy, ngoài ra nó trả về expr2.

Một điều thú vị ở đây là JavaScript engine luôn ước lượng giá trị biểu thức logic dạng này từ trái sang phải và theo nguyên tắc "đoản mạch" - [short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation)". Tiên hữu nào giỏi Vật lý chắc còn nhớ hiện tượng "đoản mạch", đó là khi dòng điện không chạy qua tải hoặc chỉ chạy qua một phần.

Vì AND chỉ trả về true nếu cả 2 mệnh đề cùng đúng, nên ngay khi bắt gặp expr1 sai, nó lập tức kết luận mệnh đề ghép là Sai và chấm dứt tại đó luôn, không chạy qua nửa bên phải expr2 nữa.

- expr1 || expr2 trả về expr1 nếu expr1 là truthy, ngoài ra nó trả về expr2.

Vì OR trả về true nếu ít nhất 1 mệnh đề đúng, nên ngay khi bắt gặp expr1 đúng, nó lập tức kết luận mệnh đề ghép là Đúng và bỏ qua expr2.

Short-circuit thần thánh!

Các lập trình viên kinh nghiệm thường lợi dụng đặc điểm này để tối ưu hiệu suất chương trình. Họ để các biểu thức tính toán phức tạp ở nửa sau của biểu thức logic. Như vậy, khi chưa rơi vào hoàn cảnh thích hợp, chúng sẽ bị bỏ qua, không cần tốn resource xử lý.

Tới đây, ta đã có thể viết lại hàm greet() một cách bí hiểm như sau:

```javascript
const greet = hasClient => {
  return (hasClient || doNothing()) && sayHello();
};
```

Bắt đầu phần nằm trong ngoặc đơn bên trái &&. Nếu hasClient là true thì giá trị phần này cũng là true, doNothing() bị bỏ qua.

Vì phần bên trái của && là true nên cuối cùng, giá trị biểu thức quy về phần bên phải &&, tức là sayHello().

Lập luận tương tự cho trường hợp hasClient là false, dòng chảy chương trình lập tức rẽ sang doNothing(). Lúc này giá trị nửa bên trái && là false, do đó không cần quan tâm đến sayHello() nữa.

Viết như trên vừa độc vừa lạ, vừa khử được if/else, mà vẫn hoàn toàn ăn khớp với điều kiện quy ước.

Tuy nhiên, logical operators nếu nhìn không quen thì có vẻ hơi khó hình dung mạch suy diễn của chương trình. Tôi chỉ đưa ra đây để các tin hữu tham khảo. Trong dự án thực tế, vẫn nên dùng ternary cho đỡ hại não đồng đội:

```javascript
const greet = hasClient => {
  return hasClient ? sayHello() : doNothing();
};
```

#### Logical functions

Một cách tiếp cận khác thể hiện tinh thần Functional Programming quyết liệt hơn, đó là tạo ra các hàm đặc trách nhiệm vụ xử lý logic. Ví dụ trong [Ramda.js](https://ramdajs.com) và [Sanctuary](https://sanctuary.js.org) đều có ifElse , unless , when, và hàng chục hàm logic khác.

Hàm greet nếu viết lại với Ramda sẽ trở nên xinh xắn như thế này:

```javascript
const R = require("ramda");

const greet = R.ifElse(R.identity, sayHello, doNothing);
```

Đó là vẻ đẹp đầy tính nghệ thuật của Function Composition. Bạn cứ ngắm nhìn nó và đừng nói gì cả! Composition cũng có nghĩa là tác phẩm, như thơ của Paul Verlaine hay nhạc của Beethoven.

### No new/this

Có 2 thứ luôn khiến Brendan Eich cảm thấy hài lòng khi [kể về lịch sử JavaScript](https://brendaneich.com/2008/04/popularity/), đó là first-class function và prototype mechanism.

Ngày nay, hầu hết developer đều biết rằng thừa kế trong JavaScript là prototype-based inheritance. Nhưng ở thời kỳ web còn hoang sơ, người ta hay dùng new và các hàm constructors để lập trình OOP trong JavaScript theo kiểu class-based, giống như bên Java vẫn làm.

#### Classical inheritance

Cổ thư ghi lại rất nhiều ví dụ kiểu này:

```javascript
function Dog(name) {
  this.name = name;
  this.say = function () {
    console.log("woof-woof, my name is " + this.name);
  };
}

var rocky = new Dog("Rocky");
rocky.say();

var molly = new Dog("Molly");
molly.say();
```

Hàm Dog gọi là Function Constructor, các tiền bối chân giới Đại Việt thủa trước chuyển ngữ thành "hàm dựng". Còn chúng ta thời nay có lẽ cứ nên giữ nguyên văn.

#### Prototypal inheritance

Sang đầu kỷ thứ 3, ở tông môn Yahoo! có một vị trưởng lão tu vi rất cao thâm tên là [Douglas Crockford](https://en.wikipedia.org/wiki/Douglas_Crockford) tung ra bộ kỳ thư "JavaScript: The Good Parts", trong đó có đoạn nhấn mạnh bản chất prototype trong JavaScript, sự khác biệt giữa classical inheritance và prototypal inheritance. Ông cho rằng từ khóa new mang theo nhiều điểm bất cập, nên khuyến khích dùng Object.create để sao chép nguyên mẫu sang đối tượng kế thừa.

Tư tưởng của Douglas Crockford quả thực mới mẻ. Vào lúc đó, nhiều JavaScript engine còn chưa kịp hỗ trợ Object.create. Cuốn này vừa ra mắt đã gây náo loạn cả tin giới, trở thành sách gối đầu giường của rất nhiều tu sĩ.

Object.create cho phép sao chép các properties hoặc protoype của đối tượng. Hàm Dog có thể được viết lại theo hướng prototypal inheritance như thế này:

```javascript
function Dog() {}

Dog.prototype.say = function () {
  console.log("woof-woof, my name is " + this.name);
};

var rocky = Object.create(Dog.prototype);
rocky.name = "Rocky";

var molly = Object.create(Dog.prototype);
molly.name = "Molly";

rocky.say();
molly.say();
```

Không cần new nữa!

Các cường giả sau đó nhanh chóng phát triển thêm nhiều cách tiếp cận prototypal inheritance khác, nổi bật nhất phải kể đến Concatenative inheritance, Prototype delegation và Functional inheritance.

ES6 Class ngày nay chỉ vay mượn syntax của classical OOP để làm interface, còn bên trong nó chính là cơ chế prototypal inheritance.

#### Object Composition

Nhưng dù sao prototypal inheritance vẫn thuộc về OOP.

Người tu luyện Functional Programming không cần new.

Gần 10 năm sau bom tấn "The Good Parts", Douglas Crockford lại một lần nữa khiến tin giới chấn động bằng "JavaScript: The Better Parts". Thời điểm này, ông đã không còn dùng Object.create() nữa, cũng từ bỏ luôn this, for loops, for in, while... Tu vi của ông đã tiến thêm một bước lớn. Trong clip, ông nói về những tính năng mới của ES6 lúc ấy vẫn còn chưa chính thức xuất xưởng. Mấy lão quái kiệt này luôn đi trước thiên hạ vài năm.

<YouTube id="bo36MrBfTk4" />

Đó cũng là khi trào lưu Functional Programming đang dần nóng trở lại, người ta bắt đầu nhắc đến khái niệm [Object Composition](https://medium.com/javascript-scene/the-hidden-treasures-of-object-composition-60cd89480381).

Đi cặp với new là this. Từ khóa this chẳng qua chỉ là kỹ xảo nhằm tạo ra một ngữ cảnh khu biệt (context) để thực thi các hàm. Trong JavaScript, mỗi hàm như 1 kết giới độc lập. Function khi được gắn lên object thì gọi là method. Ngữ cảnh method đó chạy thường chính là đối tượng sở hữu nó. Sau này mới sinh ra các thủ thuật bind, apply, call để đánh tráo context.

Với những người mới học JavaScript, this đôi khi trở thành nỗi khiếp sợ. Rất khó debug các vấn đề phát sinh trong hàm nếu không biết chính xác ngữ cảnh chạy nó. Mà ngữ cảnh lại thường không ổn định. Đúng hơn, phải nói rằng chúng luôn luôn mutable.

Người tu luyện Functional Programming không cần this.

Đoạn code với classical OOP trên kia có thể viết lại thành:

```javascript
const sayName = state => {
  return Object.assign(state, {
    say: () => {
      console.log(`woof-woof, my name is ${state.name}`);
    },
  });
};

const createDog = name => {
  let state = {
    name,
  };
  return Object.assign(state, sayName(state));
};

const rocky = createDog("Rocky");
rocky.say();
const molly = createDog("Molly");
molly.say();
```

Nhìn đâu cũng thấy functions.

Không còn for/while, if/else, new/this.

Liệu bạn đã sẵn sàng rời khỏi những phàm vật ấy?

Hay nói như các nhà sư, liệu bạn có thể buông bỏ?

![](https://i.imgur.com/LK0k8LW.jpg)

Khi lối tư duy truyền thống đã ăn sâu vào tâm trí, hễ gặp vấn đề phân cấp đối tượng thì chúng ta sẽ nghĩ ngay đến OOP, class, prototype, inheritance... thậm chí coi chúng như giải pháp tất yếu, duy nhất. Hễ xử lý tập hợp là phải looping, hễ thấy có điều kiện thì chỉ biết dựa vào if... Đây là trở ngại rất lớn cho kẻ mới nhập đạo.

Phải tìm cách rũ bỏ những thứ không cần thiết, thì mới đi xa được.

Rời khỏi chúng, chỉ giữ lại một ý niệm duy nhất: FUNCTION!

Nhất niệm "phân sần"!

![](https://i.imgur.com/0clmtSN.jpg)

Ban đầu tất nhiên là sẽ khó khăn, lúng túng. Giống như hàng ngày bạn vẫn đi trên con đường quen thuộc từ nhà đến công sở rồi lại trở về nhà. Cho đến một hôm con đường đó bị cảnh sát chặn lại, bạn đành phải rẽ sang lối khác.

Trên con đường xa lạ ấy, bạn không còn trông thấy những điểm mốc hàng ngày vẫn thấy: 1 shop lưu niệm, 1 cây xăng, 1 tiệm cầm đồ, sau ngã tư là đến ven sông, cây cầu sơn màu đỏ, một tiệm tạp hóa thường có cô em rất xinh ngồi trước cửa... Bạn không còn bắt gặp những dấu hiệu đã quen mắt. Bạn chẳng biết mình đã đi đến đâu, còn cách nhà bao nhiêu km nữa.

Nhưng con đường nào đi lại vài lần thì cũng thành quen. Chẳng có gì đáng ngại. Vấn đề là, ngay khi bạn nhận thấy Functional Programming là thứ gì đó rất thú vị, đáng để học hỏi, vận dụng nó, bạn nên thực hiện ngay lập tức, đừng chờ đợi dịp nào thuận tiện, đừng chờ tìm được minh sư dẫn dắt. Nếu vậy, bạn sẽ khó mà rời khỏi lối mòn xưa cũ.

Krishnamurti từng diễn giải một điều gần tương tự, đại ý thế này:

> Nếu bạn đi về hướng Bắc suốt những ngày tháng của cuộc đời bạn, giống như con người đã đi theo một hướng đặc biệt, rồi có người nào đó xuất hiện và nói, “Hướng đó không đúng”. Sau đó ông ta bảo bạn, “Đi về hướng Nam, hướng Đông, bất kỳ hướng nào, ngoại trừ hướng đó.” Và khi bạn thực sự chuyển động khỏi hướng đó, có một sự thay đổi ngay tại chính những tế bào não bởi vì bạn đã phá vỡ cái khuôn mẫu. Và cái khuôn mẫu đó phải được phá vỡ ngay lúc này, không phải bốn mươi năm hay một trăm năm sau.
]]></description>
            <link>https://hungvn.com/blog/functional-programming-phan-3-buong-bo</link>
            <guid isPermaLink="true">https://hungvn.com/blog/functional-programming-phan-3-buong-bo</guid>
            <pubDate>Wed, 20 Jun 2018 15:46:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Functional Programming - Phần 2 - Nhập đạo]]></title>
            <description><![CDATA[
Như vậy, Functional Programming là nghệ thuật lập trình trong đó ta:

- sử dụng functions để điều khiển workflow
- tuân thủ 2 nguyên tắc immutability và purity

Nói cách khác, chư vị tin hữu muốn tu luyện Functional Programming thì phải giữ đạo tâm trong sáng, ý chí kiên định, hàng ngày chiêm nghiệm, suy diễn, cảm ngộ function, tu vi theo đó sẽ không ngừng thăng tiến.

Nhưng làm thế nào để cảm ngộ "phân sần ý cảnh"? Ta phải nắm bắt, quan sát, tư duy, suy tưởng về function ra sao? Sau đây là những pháp quyết nhập môn.

### Higher-order function

Higher-order function là một khái niệm đến từ Toán học. Bất cứ hàm nào tiếp nhận 1 function như tham số, hoặc trả về 1 function như kết quả, thì đều được coi là higher-order function.

Dưới đây là 1 ví dụ, hàm getItem nhận vào hàm by mô tả điều kiện, lại trả về 1 hàm khác. Nó thừa tiêu chuẩn để gọi là higher-order function.

```javascript
const getItem = (by) => (arr) => by;

// hoặc phiên bản chi tiết
const getItem = (by) => {
  return (arr) => {
    return by(arr);
  };
};
```

Lập trình phong cách Functional Programming là khiêu vũ với các functions.

Trong Functional Programming, hầu như mọi functions đều là higher-order function, vì chúng đều có thể nhận vào và ném ra các functions.

Nhưng như vậy thì có lợi ích gì? Nó đơn giản cung cấp cho ta một cách khác để lập luận và suy diễn. Chẳng hạn như với hàm getItem trên kia cho phép bạn biến hóa rất nhiều dạng, tùy vào cách bạn thao túng by.

Khi bạn viết getItem, bạn không cần biết sau này sẽ phải kiểm tra điều kiện ra sao, cũng không quan tâm sẽ nhận được đầu vào như thế nào.

Bạn có thể tạo ra hàm tìm số lớn nhất trong 1 mảng toàn số như sau:

```javascript
// tạo hàm engine lấy max number từ mảng
const maxNumber = arr => {
  return Math.max(...arr);
};

// rồi truyền vào getItem để được hàm cần thiết
const getMaxNumber = getItem(maxNumber);

// thử xem sao
getMaxNumber([4, 6, 2, 3, 1, 8, 7, 5]);
// => 8
```

Thế sao không truyền thẳng cái mảng số kia vào maxNumber cho khỏe? Vì trong thiết kế này ta đang cư xử với maxNumber như plugin. Còn nhiều plugins khác nữa. Ta không gọi trực tiếp plugin mà gọi qua 1 giao diện tổng quát hơn.

Giờ ta lại có dữ liệu 1 nhóm người như sau:

```javascript
const members = [
  {
    name: "Alice",
    height: 165,
  },
  {
    name: "Bob",
    height: 152,
  },
  {
    name: "Celina",
    height: 178,
  },
  {
    name: "Dan",
    height: 194,
  },
  {
    name: "Eric",
    height: 187,
  },
];
```

Ta muốn tìm người cao nhất trong nhóm thì sao? Hãy thêm 1 plugin khác.

```javascript
// bạn tạo 1 hàm engine lấy max height từ mảng
const maxHeight = people => {
  return people.reduce((prev, current) => {
    return prev.height > current.height ? prev : current;
  });
};

// rồi truyền vào getItem để được hàm cần thiết
const getTallestPerson = getItem(maxHeight);

// thử xem sao
getTallestPerson(members);
// => { name: 'Dan', height: 194 }
```

Ví dụ trên tuy tầm thường, nhưng có thể là gợi ý tốt để bạn dùng higher-order function thiết kế những chương trình linh hoạt, dễ mở rộng.

### Function Composition

Đây là [khái niệm Toán học](https://www.mathsisfun.com/sets/functions-composition.html) mà tiếng Việt ta gọi là "hàm hợp", hay "hàm phức hợp". Mọi thứ trong Functional Programming đều có nguồn gốc Toán học.

Function Composition là sự phối hợp, liên kết nhiều hàm lại với nhau, thành một hàm lớn, nhiều chức năng hơn.

Có 2 kỹ thuật căn bản trong Function Composition là compose và pipe.

#### Compose

Hãy nhớ lại, trong không gian Functional Programming tồn tại vô số pure functions nhỏ gọn, đơn giản. Đúng triết lý "do one thing and do it well" của UNIX.

Vì mỗi hàm chỉ làm 1 việc, khi muốn thực hiện nhiều hành động lên cùng một input, ta chỉ việc kết hợp các hàm cần thiết lại với nhau.

Bây giờ chúng ta hãy tạm ngừng tu luyện, tạm quên tu vi để nhập phàm, quan sát và cảm ngộ nhân sinh.

Lần này, bạn hóa thành con trai thứ 4 trong gia đình một thôn dân sinh sống dưới chân núi Tản Viên bằng nghề bán thịt...

Một hôm bạn xin được khúc cây lớn ở chỗ ông chú làm kiểm lâm kiêm lâm tặc.

![](https://i.imgur.com/OQofkz2.jpg)

Từ khúc gỗ này, bạn muốn làm ra cái thớt cho nhà dùng.

Là tu sĩ mới nhập môn tu luyện Functional Programming, tuy không có tu vi, nhưng bạn vẫn hình dung được sẽ cần đến các pure functions sau:

- cưa(): nhận vào khúc gỗ, trả về từng khoanh tròn
- sấy(): nhận khoanh gỗ tươi, trả về khoanh gỗ khô
- bào(): nhận vào khoanh gỗ, trả về khoanh gỗ bằng phẳng
- khoan(): nhận vào khoanh gỗ, trả về khoanh gỗ có 2 lỗ (để gắn quai treo/móc lên cho gọn)
- chà(): nhận vào khoanh gỗ, trả về khoanh gỗ trơn láng (dùng giấy nhám, miền ngoài gọi giấy giáp, để đánh cho nhẵn bề mặt)
- móc(): nhận thớt không quai, trả về thớt có quai

Mỗi hàm chỉ làm đúng 1 việc. Không hơn. Không kém. Khi đi qua chừng đó công đoạn, ta sẽ được sản phẩm mong muốn.

![](https://i.imgur.com/qKYfPYA.jpg)

Dĩ nhiên chúng ta đang muốn khúc gỗ được sửa đổi nên tạm bỏ qua vấn đề immutability.

Đây là phiên bản mô phỏng:

```javascript
const cưa = x => {
  return `${x} đã cưa`;
};

const sấy = x => {
  return `${x} đã sấy`;
};

const bào = x => {
  return `${x} đã bào`;
};

const khoan = x => {
  return `${x} đã khoan`;
};

const chà = x => {
  return `${x} đã chà`;
};

const móc = x => {
  return `${x} đã gắn móc`;
};
```

Để tạo ra 1 cái thớt, ở thời viễn cổ xa xưa, các man sĩ thường code thế này:

```javascript
var thớt = cưa("khúc gỗ");
thớt = sấy(thớt);
thớt = bào(thớt);
thớt = khoan(thớt);
thớt = chà(thớt);
thớt = móc(thớt);

console.log(thớt);
// => khúc gỗ đã cưa đã sấy đã bào đã khoan đã chà đã gắn móc
```

![](https://i.imgur.com/nBLW7ye.jpg)

5 vạn năm sau, khi đã xuất hiện Toán học, các tộc nhân bộ lạc Giao Chỉ thời đại Hồng Bàng lại thích code như thế này:

```javascript
var thớt = móc(chà(khoan(bào(sấy(cưa("khúc gỗ"))))));
console.log(thớt);
// => khúc gỗ đã cưa đã sấy đã bào đã khoan đã chà đã gắn móc
```

Đây chính là Toán học cơ bản. Với y = f(g(x)), ta tính g(x) trước, được bao nhiêu truyền vào f() là ra kết quả. Việc tính toán đi từ ngoặc trong cùng ra ngoài, mắt thường nhìn thấy là từ phải sang trái, từ g đến f.

Lại thêm 5 ngàn năm nữa trôi qua. Lúc này đã có ES6\. Một số cường giả Functional Programming sáng tạo ra phương thức compose, như thế này:

```javascript
const compose = (...fns) => {
  return fns.reduce((f, g) => x => f(g(x)));
};
```

Bạn có thể dùng [Babel](https://babeljs.io/repl) dịch sang ES2015 cho dễ hiểu.

Ý tưởng của compose là xếp cuốn chiếu các hàm lại với nhau, theo thứ tự từ trái sang phải để tạo ra một hàm mới, mà khi được thực thi, nó sẽ lần lượt gọi các hàm đã truyền vào trước đó theo thứ tự ngược lại, từ phải sang trái.

Tức là nếu y = compose(f, g), thì y(x) = f(g(x));
Nó sẽ tính g(x) trước rồi truyền kết quả cho f;
Giả sử g(x) = z thì y(x) = f(z);

Nếu bạn vẫn thấy mơ hồ thì cứ xem cái này là Đạo. Chỉ có thể cảm ngộ, không thể giảng được bằng lời!

Trở lại với cái thớt. Hàm compose tất nhiên là higher-order function. Ta sẽ thử xem nó làm việc ra sao:

```javascript
const quăng_cho_tao_cái_thớt = compose(móc, chà, khoan, bào, sấy, cưa);
console.log(quăng_cho_tao_cái_thớt.toString());
// => bạn đoán xem log ra thứ gì?
```

Bây giờ ta có 1 hàm, gọi là quăng_cho_tao_cái_thớt(), kết quả của sự lắp ghép bằng compose tất cả các pure functions ở trên.

Ta biết compose sẽ gọi từ phải sang trái, nên công đoạn nào làm trước thì để bên phải.

Chạy thử 1 phát:

```javascript
const thớt = quăng_cho_tao_cái_thớt("khúc gỗ");
console.log(thớt);
// => khúc gỗ đã cưa đã sấy đã bào đã khoan đã chà đã gắn móc
```

Vậy là đủ công đoạn, khúc gỗ đã trở thành một cái thớt tốt.

Nhưng chưa hết. Khi bạn treo cái thớt đó ở nhà, nhiều người quen đến chơi thấy đẹp hỏi mua. Nhiều đến mức bạn quyết định kinh doanh thớt.

Làm thớt kinh doanh thì phải gán nhãn, vậy là bạn tạo ra một pure function mới và dùng compose để làm khuôn sản suất loại thớt commercial này.

Dễ ợt, không ảnh hưởng gì đến loại thớt cho nhà dùng.

```javascript
const nhãn = x => {
  return `${x} đã dán nhãn`;
};

const làm_thớt_để_bán = compose(nhãn, móc, chà, khoan, bào, sấy, cưa);
```

Hoặc tận dụng lại khuôn mẫu cũ:

```javascript
const làm_thớt_để_bán = compose(nhãn, quăng_cho_tao_cái_thớt);
```

Thử xem sao:

```javascript
const thớt_bán = làm_thớt_để_bán("khúc gỗ");
console.log(thớt_bán);
// => khúc gỗ đã cưa đã sấy đã bào đã khoan đã chà đã móc đã dán nhãn
```

Để mở rộng thị phần, hướng đến phân khúc giá rẻ, bạn tạo ra dòng sản phẩm thớt tầm trung, dùng chip MediaTek, bỏ qua bước sấy khô và đánh bóng để giảm giá thành. Rất đơn giản:

```javascript
const làm_thớt_loại_hai = compose(nhãn, móc, khoan, bào, cưa);
```

Thử xem sao:

```javascript
const thớt_loại_hai = làm_thớt_loại_hai("khúc gỗ");
console.log(thớt_loại_hai);
// => khúc gỗ đã cưa đã bào đã khoan đã móc đã dán nhãn
```

Lập trình như vậy phải nói là vô cùng tao nhã, lịch thiệp! Đôi khi tôi cảm thấy phong cách lập trình Functional Programming có sự thanh tịnh đầy chất quý tộc, vừa bình dân lại vừa hàn lâm, đẹp đến mức khó hiểu!

Nếu dùng OOP, có thể chúng ta còn đang loay hoay giữa một đống class Máy Cưa, Máy Bào, Máy Khoan... Hoặc 1 class Máy Làm Thớt khổng lồ có đủ methods cưa, bào, khoan... Rồi còn một mớ properties mà ta phải cân nhắc xem cái nào public, cái nào private. Rồi phải tạo instance, thừa kế qua lại mấy vòng may ra mới làm được cái thớt. Muốn thêm dòng sản phẩm lại càng khó khăn. Phải tạo class Thớt*nhà_dùng, extend ra Thớt*để*bán, Thớt*để_bán_loại_2, phiền phức không sao kể xiết!

Functional Programming thì chỉ cần mấy hàm đơn giản, rời rạc, dùng compose lắp ráp lại như lắp ráp dây chuyền công nghệ là chế được các kiểu thớt.

Function Composition tựa như một nhà máy hiện đại, mỗi chi tiết linh kiện được xử lý bằng một robot chuyên trách, kết hợp lại với nhau một cách khoa học để tạo ra sản phẩm hoàn thiện.

#### Pipe

Một biến thể của compose là pipe, vận hành theo chiều ngược lại. Ta có thể implement bằng cách đảo vị trí f và g thế này:

```javascript
const pipe = (...fns) => {
  return fns.reduce((f, g) => x => g(f(x)));
};
```

Hoặc giữ nguyên code của compose nhưng thay reduce bằng reduceRight:

```javascript
const pipe = (...fns) => {
  return fns.reduceRight((f, g) => x => f(g(x)));
};
```

Vì pipe tổ hợp các hàm theo chiều ngược lại so với compose nên ta viết:

```javascript
const làm_thớt_dỏm = pipe(cưa, bào, nhãn);
```

Thử xem sao:

```javascript
const thớt_dỏm = làm_thớt_dỏm("khúc gỗ");
console.log(thớt_dỏm);
// => khúc gỗ đã cưa đã bào đã dán nhãn
```

Dùng pipe có vẻ thuận mắt hơn. Thứ tự các bước cưa, bào... trông khá tự nhiên. Nếu bạn quen với cách suy luận Toán học thì bạn sẽ thích compose. Còn nếu bạn muốn trực quan dễ hiểu thì cứ dùng pipe.

compose và pipe là những thuật pháp nhập môn dễ học, dễ dùng, nhưng không kém uy lực, thư viện Functional Programming nào cũng có. Trong Ramda.js, ngoài [compose](http://ramdajs.com/docs/#compose) và [pipe](http://ramdajs.com/docs/#pipe), các tác giả còn bổ sung thêm pipeK, pipeP, composeK, composeP.

Khi đã thông thạo, bạn hoàn toàn có thể tạo ra compose theo cách của bạn. Ví dụ composeBinary liên kết các hàm từ giữa sang 2 bên thay vì từ đầu này đến đầu kia, composeRandom liên kết các hàm không theo trật tự cố định... Đó là không gian sáng tạo thuộc về riêng bạn.

### Currying function

Thuật ngữ currying và các dạng curry, curried của nó trong khoa học máy tính được [Christopher Strachey](https://en.wikipedia.org/wiki/Christopher_Strachey) đặt ra từ năm 1967 để ghi nhớ công lao của [Haskell Brooks Curry](https://en.wikipedia.org/wiki/Haskell_Curry), một nhà Toán học và Luận lý học người Mỹ.

Currying function là làm cho 1 function trở thành "curried function".

Cái function ban đầu đó hơi ngốc nghếch, nó cần bạn truyền vào N tham số để tính toán, mà nếu thiếu 1 tham số, nó sẽ không chạy.

Ví dụ hàm sum thế này:

```javascript
const sum = (a, b, c) => {
  return a + b + c;
};
```

sum cần 3 tham số để cộng dồn lại, nếu thiếu, sẽ không tính toán ra được.

```javascript
// có thể ra sân
sum(5, 3, 2); // => 10
sum(4, 4, 2); // => 10
sum(4, 3, 3); // => 10
sum(3, 5, 2); // => 10

// nhưng
sum(4, 5); // => NaN
```

Đây là thiếu tiền đạo cả đội không chịu ra sân tập! Nhưng cuộc sống đâu phải lúc nào cũng thuận lợi, đầy đủ cho chúng ta? Dù cả mấy tiền đạo đều bị chấn thương, treo giò, trốn tập thì các anh còn lại vẫn phải có trách nhiệm ra sân chứ!

Currying chính là kỹ thuật biến hàm sum ngốc đó trở thành một function vi diệu hơn, nếu bạn gọi nó với 1 tham số, nó sẽ trả về 1 hàm tạm thời, giữ lại tham số đó, chờ khi nào đủ 3 tham số thì mới thực hiện tính toán.

Hình dung bạn tổ chức một buổi party, mời 3 người bạn tham gia. Lúc này đã có mặt 2 người, còn 1 người đến muộn. Bạn quyết định không cần chờ nữa. Bữa tiệc cứ bắt đầu đã, chừng nào người kia đến thì tính tiếp.

Đây là 1 cách implement cho hàm curry:

```javascript
const curry = fn => {
  let totalArguments = fn.length;
  let next = (argumentLength, rest) => {
    if (argumentLength > 0) {
      return (...args) => {
        return next(argumentLength - args.length, [...rest, ...args]);
      };
    }
    return fn(...rest);
  };
  return next(totalArguments, []);
};
```

Và curry tất nhiên cũng là higher-order function.

Thử dùng với sum xem sao:

```javascript
const curriedSum = curry(sum);
```

curriedSum bây giờ là phiên bản curried của hàm sum trước đó.

```javascript
curriedSum(4, 4, 2); // => 10
curriedSum(4, 3, 3); // => 10
curriedSum(3, 5, 2); // => 10

// và
curriedSum(5, 3); // => [Function]
```

curriedSum(5, 3) là 1 function. Nó đang chờ đợi tham số cuối cùng xuất hiện. Nếu bây giờ ta gọi nó với 1 tham số thì kết quả sẽ được tính toán ra:

```javascript
curriedSum(5, 3)(2); // => 10
```

Nếu ta truyền nhiều hơn số lượng tham số còn thiếu thì sao? Ở đây là 1 tham số cuối cùng. Theo cách implement trên thì nó sẽ bỏ qua các tham số dư thừa. Các phiên bản curry của [Ramda.js](http://ramdajs.com/docs/#curry) và [Lodash FP](https://lodash.com/docs/4.17.10#curry) cũng hành xử như vậy.

```javascript
curriedSum(5, 3)(2, 4, 8); // => 10
```

Một điểm quan trọng nữa là ta có thể phân tách hàm gốc ra từ 1 đến N phần, với N là số lượng tham số của hàm gốc đó. Chẳng hạn, nếu hàm gốc có 3 tham số, ta có thể chia nó ra 1, 2 hoặc 3 phần. Những cách viết sau là tương đương:

```javascript
curriedSum(3, 5, 2);
curriedSum(3, 5)(2);
curriedSum(3)(5, 2);
curriedSum(3)(5)(2);
```

curry, cũng như compose và pipe là những kỹ thuật căn bản, ai cũng phải học, phải biết. Mọi ngôn ngữ được thiết kế với tư tưởng Functional Programming như Haskell, Scalla, Elm... đều có sẵn các hàm này. Chúng rất tinh tế và được dùng ở khắp nơi.

Chỉ cần thành thạo 3 pháp quyết này thì bạn đã được xem như đệ tử Functional Programming chân chính.
]]></description>
            <link>https://hungvn.com/blog/functional-programming-phan-2-nhap-dao</link>
            <guid isPermaLink="true">https://hungvn.com/blog/functional-programming-phan-2-nhap-dao</guid>
            <pubDate>Sat, 16 Jun 2018 15:43:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Functional Programming - Phần 1 - Con đường sáng]]></title>
            <description><![CDATA[
Lúc bấy giờ, Tin giới Tây phương xuất hiện 2 lão quái Nguyên Anh hậu kỳ đỉnh phong, chỉ thiếu nửa bước cảm ngộ ý cảnh là đột phá tới cảnh giới Hóa Thần. Một người là Đồ Linh tôn giả - tức Alan Turing, nổi danh với pháp môn Turing Machine. Người kia là Khâu Kỳ thượng tiên, Alonzo Church, tung hoành tam giới bằng đạo thuật Lambda Calculus (1).

Turing Machine của Alan Turing và Lambda Calculus của Alonzo Church thực ra là hai cách tiếp cận nguyên lý xử lý tính toán trong computer, thường được giới chuyên môn gọi chung là Luận đề Church - Turing ([The Church-Turing Thesis](https://plato.stanford.edu/entries/church-turing/)).

Turing Machine đặt cơ sở trên việc nắm giữ state machine và trạng thái tiến trình, còn ý tưởng Lambda Calculus được xây dựng trên các tính chất của hàm toán học. Lấy tu vi của bổn tiên hiện giờ thì chưa lĩnh hội được mấy thứ cao siêu như vậy, nên không dám lạm bàn ở đây. Chỉ biết rằng, 2 thuật pháp kể trên là khởi nguồn của 2 trường phái tu luyện mạnh nhất trong tin giới hiện nay: Object Oriented Programming và Functional Programming.

Có khá nhiều cơ chế lập trình - Programming Paradigm. OOP và Functional Programming chỉ là 2 trong số đó. Trong cuốn "[Programming Paradigms for Dummies: What Every Programmer Should Know](https://drive.google.com/file/d/1sNAojaDlY4Q9LAMad_2aJLIUBt06ru7U/view)", tác giả Peter Van Roy đưa ra mô hình tổng hợp quan hệ giữa các cơ chế lập trình như thế này:

![](https://i.imgur.com/1yDCYYq.png)

Trong lịch sử công nghệ, có vẻ OOP chiếm ưu thế hơn so với Functional Programming. Bạn cứ thử nhìn xung quanh mình là biết, từ thời tập tành code đã thấy thiên địa tràn ngập quy tắc OOP rồi. Các job description, các buổi interview đều nhắc đến OOP như pháp thuật căn bản. Thảo luận kỹ thuật hầu hết xoay quanh mấy khái niệm Class, Object, Inheritance, rồi cao hơn thì SOLID, Polymorphism, Encapsulation...

Nhưng, trên thế giới, từ thời [Lisp](http://lisp-lang.org/) đến [FP](https://en.wikipedia.org/wiki/FP_%28programming_language%29), rồi [Haskell](https://www.haskell.org/), [Elixir](https://elixir-lang.org/), chưa bao giờ thiếu vắng những tu tin giả đi theo con đường Functional Programming. Nhất là khoảng sau 2010, không rõ vì sao người ta bắt đầu phàn nàn nhiều hơn về OOP, trích dẫn nhiều hơn luận điểm banana/gorilla của Joe Armstrong (2), theo đó, chủ đề "Functional Programming" bắt đầu nóng dần trở lại.

Tôi biết đến Functional Programming vào khoảng 2015 qua một talk show trên YouTube của "[chú Bob](https://en.wikipedia.org/wiki/Robert_C._Martin)", nhưng không hiểu lắm nên cũng không chú ý.

Phải sang 2016, tôi mới chính thức tìm hiểu sâu về Functional Programming sau khi đọc 2 loạt bài viết "[Composing Software](https://medium.com/javascript-scene/composing-software-an-introduction-27b72500d6ea)" của [Eric Elliott](https://medium.com/@_ericelliott) và "[So You Want to be a Functional Programmer](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-1-1f15e387e536)" của [Charles Scalfani](https://medium.com/@cscalfani) trên Medium.

Eric Elliott lần lượt giải thích từng concepts của Functional Programming một cách tường tận, dễ hiểu. Còn Charles Scalfani đúng là fan cuồng Functional Programming. Anh trình bày nó dưới dạng một hệ thống triết lý, thế giới quan đặc sắc. Thậm chí, Scalfani còn đề cao Functional Programming như nấc thang tiến hóa trong lịch sử lập trình. Lối viết của anh gây ấn tượng cực mạnh.

![](https://i.imgur.com/e3zKVPq.png)

Trước đó, Scalfani còn có bài "[Goodbye, Object Oriented Programming](https://medium.com/@cscalfani/goodbye-object-oriented-programming-a59cda4c0e53)" gây tranh luận sôi nổi.

Nhưng bạn đọc nên lưu ý, Functional Programming không bài xích OOP. Chúng chỉ là những con đường tu luyện khác nhau, cùng hướng về Đại Đạo. Trong khi viết code, ta hoàn toàn có thể phối hợp nhiều cơ chế lập trình khác nhau, miễn sao đạt đến kết quả Đúng - Nhanh - Ổn - Đẹp.

ReactJS là một ví dụ tiêu biểu, có thể coi nó như 7 phần Functional Programming + 3 phần OOP. Về điểm này, [Anjana Vakil](https://twitter.com/anjanavakil) có một bài thuyết trình rất hay ở GOTO 2017.

<YouTube id="Pg3UeB-5FdA" />

Dù sao, từ đó đến nay, khuynh hướng tư duy Functional Programming vẫn từng bước lan rộng, ảnh hưởng đến thiết kế của rất nhiều chương trình hiện đại. Chỉ cần để ý một chút, chúng ta có thể nhận ra các đặc tính nổi bật của Functional Programming xuất hiện trong hầu hết frameworks và các bản cập nhật ngôn ngữ mới. Thậm chí, nếu xét kỹ, những khái niệm thoạt nhìn có vẻ không liên quan như WebComponent, Serverless, Microservice... cũng ẩn hiện tư tưởng Functional Programming. Và tôi gần như không còn đụng tới class, new, this nữa.

![](https://i.imgur.com/LuyuYCU.jpg)

### What's Functional Programming?

Vậy rốt cuộc Functional Programming là cái gì? Nếu google bạn sẽ tìm thấy hàng tá cách giải thích khác nhau. Còn tôi chủ chương nên định nghĩa ngắn gọn thế này:

_Functional Programming là phương pháp lập trình lấy function làm đơn vị thao tác cơ bản._

Đúng vậy. Functional Programming xét về lý tưởng thì chỉ có function, function và function. Không lệnh gán (assignment statements), không cần tới các biến (variables), không lưu giữ trạng thái toàn cục (global state). Trong Functional Programming, chúng ta điều khiển dòng chảy chương trình bằng cách phối hợp các functions lại với nhau. Chúng ta tung hứng các functions qua lại, nhận vào function, nhả ra function, lồng ghép, xâu chuỗi, biến hóa chúng theo mọi cách có thể nghĩ ra.

Đó gọi là không gian "[first-class functions](https://en.wikipedia.org/wiki/First-class_function)", nơi lập trình viên đối xử với functions như "first-class citizens". Ở đâu functions được coi trọng như vậy, ở đó ta có thể lập trình theo cơ chế Functional Programming. JavaScript, Python, Golang, ngay cả PHP chính là như vậy. Java tính từ v8.0 ra mắt năm 2017 cũng là như vậy. Dù không hoàn hảo như Haskell, F#, etc - những tu chân giới vốn được sinh ra cho Functional Programming - nhưng ta vẫn có thể tu luyện Functional Programming được...

Chỉ có điều phải vận dụng khác một chút, linh hoạt hơn một chút. Đó là lý do tại sao trong các chương trình JavaScript, Python, dù viết theo phong cách Functional Programming nhưng vẫn phải dùng đến các biến, lệnh gán để thao tác.

Các tu tin giả tầng thấp muốn bắt đầu con đường Functional Programming cần phải nắm bắt những khái niệm cơ bản như Immutability, Purity, Higher-order functions, Currying function, Function Composition... Sau khi thăng cấp cảnh giới cao hơn thì có thể tìm hiểu Monad, Functor, Setoid, Idempotent, Lens... và nhiều nữa.

Nào, bây giờ hãy bắt đầu hành trình...

### Immutability

Immutability nghĩa là tính bất biến.

Nguyên tắc thứ nhất trong Functional Programming là: cái nào đã khai báo một lần thì mãi mãi như vậy, không bao giờ thay đổi nữa. Các biến hoặc đối tượng trong kịch bản Functional Programming nếu có thì phải immutable.

Code thế này không phải là Functional Programming vì x và y bị thay đổi.

```javascript
var x = 5;
var y = 2;
while (x < 10) {
  y += x;
  x++;
}
```

Mutable là điều tối kỵ trong Functional Programming. Cần phải hạn chế đến mức thấp nhất. Các mẫu coding convention và best practices thông dụng hiện nay đều khuyến khích sử dụng const để khai báo, bỏ hẳn var , và dùng let đúng liều lượng.

Đối với Object, ta nên dùng Object.freeze để lock toàn bộ thuộc tính. Cũng có thể dùng Object.defineProperty, Object.defineProperties để lock một số thuộc tính quan trọng. Các giải pháp này đều chỉ hỗ trợ 1 cấp thuộc tính. Phải chủ động code thêm nếu muốn áp dụng lên các thuộc tính con.

Nếu dự án đủ phức tạp, hãy cân nhắc sử dụng các thư viện chuyên dụng như [Immutable.js](https://facebook.github.io/immutable-js/), [Baobap](https://github.com/Yomguithereal/baobab)...

### Purity

Purity là tính thuần khiết, thuần túy, sự trong sạch, không bị pha tạp.

Đây là nguyên tắc thứ hai trong Functional Programming: tất cả các hàm đều phải là pure function, không có hiệu ứng phụ (side effect), không được tác động lên bất cứ giá trị nào bên ngoài nó, cũng nói không với chỉnh sửa tham số input.

Hàm dưới đây không phải pure function vì nó chỉnh sửa DOM element bên ngoài và thay đổi giá trị chứa trong localStorage.

```javascript
const updateView = html => {
  let $view = document.getElementById("panel");
  $view.innerHTML = html;
  localStorage.setItem("panelCache", html);
  return $view;
};
```

Đặc điểm quan trọng nữa của pure function là với mỗi tập giá trị đầu vào nhất định, luôn có 1 và chỉ 1 kết quả trả về tương ứng. Đây là tính chất của hàm số toán học.

Hàm dưới đây không phải pure function vì trả về kết quả khác nhau cho cùng đầu vào:

```javascript
const getDuration = timestamp => {
  return Date.now() - timestamp;
};
```

Pure function trong Functional Programming thường ngắn gọn, đơn giản và chỉ xử lý duy nhất 1 vấn đề logic.

Đây là 1 pure function kinh điển:

```javascript
const add = (a, b) => {
  return a + b;
};
```

Dù bạn có gọi hàng triệu lần thì add(3, 2) vẫn luôn trả về 5.

Viết unit test cho pure function là nhiệm vụ dễ chịu như dạo chơi cùng một thiếu nữ ngây thơ trong trắng vậy!

Immutability và Purity là 2 đặc trưng cơ bản nhất của Functional Programming, cho phép phân biệt với các cơ chế lập trình khác. Tu tin giả tu luyện theo con đường này nhất định phải giữ tâm niệm "immutable" và "pure" trong từng sát na.

### Chú thích

1, Chữ Tàu ghi Alan Turing là 艾伦图灵 - Ngải Luân Đồ Linh, Alonzo Church là 阿隆佐邱奇 - A Long Tá Khâu Kỳ.

2, "You wanted a banana but you got a gorilla holding the banana".
]]></description>
            <link>https://hungvn.com/blog/functional-programming-phan-1-con-duong-sang</link>
            <guid isPermaLink="true">https://hungvn.com/blog/functional-programming-phan-1-con-duong-sang</guid>
            <pubDate>Tue, 12 Jun 2018 15:35:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cấu trúc projects và đặt tên components trong React]]></title>
            <description><![CDATA[
Như bạn đã biết, React chỉ là một thư viện nên nó không chỉ rõ cho người dùng cách tổ chức, phân chia cấu trúc thư mục cho dự án của mình. Xét trên một khía cạnh, có thể điều này là tốt vì dev có thể thoải mái thử rất nhiều cách khác nhau để chọn ra phương pháp phù hợp với dự án của mình. Tuy nhiên, nó lại khiến cho những dev mới bắt đầu sử dụng React cảm thấy khó hiểu. Bài viết này sẽ đưa ra một vài phương pháp phân chia folders, files giúp cho ứng dụng React của bạn có thể mở rộng một cách thuận tiện, nhất là đối với những người mới bước chân vào React và không biết phải làm như thế nào cho hợp lý.

# Cấu trúc files và folders

Một trong những câu hỏi dev thường gặp phải khi bắt đầu code là "Làm thế nào dể phân chia files và folders". Để thuận tiện thì chúng ta sẽ bắt đầu từ cấu trúc đơn giản nhất mà package **create-react-app** đã tạo ra. Cụ thể là folder **src**. Đây là folder chính chứa source code, vì vậy chúng ta sẽ tập trung vào phần này. Toàn bộ những files, folder khác nằm ngoài vẫn sẽ được giữ nguyên:

![](https://cdn-images-1.medium.com/max/800/1*eXN1LlNnuZmosJ7n7EsJ-Q.png)

## Tách riêng thành folder Containers và Components

Có thể bạn đã thấy trong một vài dự án, dev thường sử dụng hai folders có tên _Components_ và _Containers_

```javascript
src
├─ components
└─ containers
```

Thoạt nhìn thì có vẻ ổn, nhưng cách phân chia như trên còn tồn tại những nhược điểm như sau:

- **Định nghĩa chức năng một cách không rõ ràng** - Sử dụng cấu trúc như trên có thể gây nhầm lẫn, hiểu lần về chức năng của mỗi folder _Container_ và _Component_ , có nhiều người sẽ hiểu chức năng của mỗi folder theo ý khác nhau. Có người thì hiểu _Containers_ là các components thực hiện việc xử lý logic (như handle click, button) và lấy dữ liệu từ server, còn components có nghĩa _Presentational Component_, thực hiện nhiệm vụ hiển thị view cho người dùng. Có người lại sử dụng _Containers_ để chứa những route components (mỗi component là một link route, nếu như bạn sử dụng react-router), còn _Components_ thì chứa những base component để tạo nên các route components kia. Vì thế khi làm việc trong team sẽ gây ra không đồng nhất và các member khó thống nhất trong việc sử dụng hai folder này.
- **Components không còn linh động, reusable** - Ngay cả khi bạn đã code ra một components với chức năng đặc thù, sau này bạn vẫn phải sửa lại components đó do những lí do như đổi requirements, thêm chức năng,... khiến cho file chuyển qua chuyển lại giữa 2 folders **components** và **containers**.
- **Components trùng tên** - Khi sử dụng react, tên của một component nên có ý nghĩa như chức năng của nó, và quan trọng là không nên có nhiều components trùng tên nhau trong project để tránh gây nhầm lẫn. Cách tổ chức folders như trên sẽ tạo ra 2 components có tên giống nhau, một sử dụng cho **container**, một sử dụng cho **components** (_presentational_ - hiển thị)
- **Giảm hiệu suất code** - Bạn sẽ phải thường xuyên navigate giữa 2 folder trên khi viết cho một tính năng, do một tính năng thường sẽ gồm cả 2 loại components Một cách phân chia khác cũng có cấu trúc 2 folder như trên, nhưng phân biệt dựa trên module . Giả sử ứng dụng của bạn có một module User. Trong đó sẽ tách ra thành 2 folder components và containers:

```javascript
src
└─ User
    ├─ components
    └─ containers
```

Theo hướng tiếp cận trên, dev sẽ không phải gặp khó khăn trong việc navigate giữa các folder khi code. Bạn sẽ không phải kéo lên, kéo xuống để tìm xem components của User ở đâu, khi đang hoàn thiện file trong containers để đối chiếu. Tuy nhiên, cách này sẽ sinh ra một đống folder containers và components nếu như hệ thống của bạn lớn và cót rất nhiều modules.

Như vậy, việc tách biệt 2 folder **components** và **containers** không hẳn là hợp lý. Thay vì tách riêng ra như vậy, các components sẽ được đặt hết trong folder **components** ngoại trừ những components sử dụng làm _screens_

## Tái cấu trúc folders dựa trên module

Trong folder **components**, chúng ta sẽ nhóm các files lại theo module hoặc feature/tính năng.

Với tính năng CRUD user, chúng ta chỉ cần module User, nên folder tree sẽ có dạng như sau:

```javascript
src
└─ components
  └─ User
    ├─ Form.jsx
    └─ List.jsx
```

Khi component được cấu thành bời nhiều hơn một file (chẳng hạn như phải import nhiều components khác, hay file chỉnh sửa css cho component đó), chúng ta sẽ đưa component này cùng các files liên quan vào một folder có cùng tên. Ví dụ như **Form.jsx** cần thêm **Form.css** để chỉnh style, bạn sẽ có một folder như sau:

```javascript
src
└─ components
  └─ User
    ├─ Form
    │ ├─ Form.jsx
    │ └─ Form.css
    └─ List.jsx
```

### UI components

Ngoài các folder dành cho module hay tính năng trong ứng dụng của bạn, có thể thêm một folder _UI_ (hoặc _base_/_atomic_) dùng cho các component dạng UI - là những phần tử nhỏ sử dụng cho UI trong ứng dụng của bạn. Đây là những component giống các thư viện open source, thường được dùng đi dùng lại nhiều lần trong ứng dụng của bạn, không nhất thiết phải là một module lớn và không thực hiện các business logic. Những ví dụ về components dạng này như Button, Checkbox, SelectBox, Modal, DatePicker, BreadCrumb,...

# Đặt tên cho components

Ở phần trên chúng ta đã thấy được cách hệ thống files và folder trong ứng dụng, còn bây giờ sẽ tìm hiểu xem đặt tên components ra sao cho phù hợp.

Như đã đề cập ở trên, tên của components nên rõ ràng và không bị trùng lặp để có thể dễ tìm lại và tránh nhầm lẫn cho những thành viên khác trong team. Ngoài ra, tên components rõ ràng cũng giúp cho việc debug bằng những extension tools trở nên dễ dàng hơn trên trình duyệt (chẳng hạn như React Dev Tools) - vì khi app của bạn gặp lỗi khi đang chạy thì lỗi sẽ hiển thị ở đúng components xảy ra lỗi.

Để đặt tên components, chúng ta sẽ đặt theo hướng _path-based-component-naming_, nghĩa là cấu thành bởi đường dẫn từ folder src/components đến file chúng ta tạo component đó. Chẳng hạn, bạn có một file với đường dẫn **src/components/User/List.jsx** thì tên component được sử dụng trong **List.jsx** sẽ được đặt là **UserList**:

```javascript
class UserList extends React.Component
```

Nếu một file trong folder trùng tên với tên folder, chúng ta sẽ không cần phải lặp lại cả tên folder lẫn tên file. Chẳng hạn, có một file **src/components/User/Form/Form.jsx** thì thay vì sử dụng **UserFormForm**, chúng ta sẽ đặt là UserForm.

Việc đặt tên components theo đường dẫn như trên có những ích lợi như sau:

- **Việc search file trong text editor/IDE trở nên thuận tiện hơn** - Chỉ cần gõ vào ô search của IDE hay text editor mà bạn sử dụng là có thể tìm đến file một cách nhanh chóng. Hoặc navigate đến file cũng rất thuận tiện:

![](https://cdn-images-1.medium.com/max/800/1*DLndSrnMgIklk7tAhzgMWg.png)

- **Tránh lặp đi lặp lại tên khi import** Theo cách đặt tên như vậy, bạn sẽ luôn đặt tên file giống với chức năng, nhiệm vụ của nó. Đối với component **form** ở trên, chính xác thì phải là **user form**, nhưng do file đã nằm trong folder **User** nên chúng ta không cần lặp lại từ đó trong tên file của component, mà chỉ cần sử dung **Form.jsx**

  Có nhiều trường hợp, dev viết app React và đặt tên file/folder cũng như tên component một cách đầy đủ, bao gồm cả tên module lớn và nhỏ, và dần dần sau này khi app scale lên thì việc đặt tên này sẽ trở nên phức tạp hơn rất nhiều. Thử so sánh hai trường hợp sau đây:

```javascript
import ScreensUserForm from './screens/User/UserForm';
// vs
import ScreensUserForm from './screens/User/Form';
```

Đối với module nhỏ với ít thành phần như trên thì cách đặt tên thứ hai có vẻ như không tạo nhiều khác biệt lắm, ta có thể thấy cách viết thứ nhất vẫn ổn. Tuy nhiên, nếu như app của bạn scale lên với nhiều thành phần, module, chức năng phức tạp thì việc đặt tên như vậy sẽ trở nenen vô cùng kinh khủng:

```javascript
import MediaPlanViewChannel from '/MediaPlan/MediaPlanView/MediaPlanViewChannel.jsx';
// vs
import MediaPlanViewChannel from './MediaPlan/View/Channel';
```

Chưa kể những dòng như thế này còn lặp lại nhiều lần vì phải import nhiều thành phần cùng lúc.... Ví lí do đó, chúng ta nên đặt tên file và folder đúng với chức năng/nhiệm vụ trực tiếp của nó, thay vì thêm vào tên của những module cha. Còn tên component thì nên đặt theo đường dẫn tương đối so với folder src/components.

# Screens components - Dùng cho một view page

Ở trên, bài viết có nhắc đến những compoents không được đặt trong folder components, được gọi là _screens_. Giống như tên gọi của nó, đây là những components tượng trưng cho một _màn hình_ hiển thị trong ứng dụng của bạn Lấy ví dụ đối với tính năng CRUD users, chúng ta sẽ có những màn hình cơ bản nhất bao gồm:

- List users (/users
- Create user (/user)
- Edit user (/users/:id)

Như vậy, chúng ta có 3 screens khác nhau. Mỗi screen là một component cấu thành lên một page trong ứng dụng react của bạn. Screen component nên là một presentational component và không nên thực hiện xử lý business logic.

Các screens sẽ nằm trong một folder screens song song với components trong đường dẫn src, vì mỗi component ở trong sẽ đại diện cho route của ứng dụng, thay vì một module nào đó:

```javascript
src
    ├─ components
    └─ screens
      └─ User
        ├─ Form.jsx
        └─ List.jsx
```

Nếu ứng dụng của bạn sử dụng react-router, chúng ta sẽ giữ một file Root.jsx trong folder screens và đưa toàn bộ các view route vào trong file này:

```javascript
import React, { Component } from "react";

import { Router } from "react-router";
import { Redirect, Route, Switch } from "react-router-dom";

import ScreensUserForm from "./User/Form";
import ScreensUserList from "./User/List";

const ScreensRoot = () => (
  <Router>
    <Switch>
      <Route path="/user/list" component={ScreensUserList} />
      <Route path="/user/create" component={ScreensUserForm} />
      <Route path="/user/:id" component={ScreensUserForm} />
    </Switch>
  </Router>
);

export default ScreensRoot;
```

Với cách này chúng ta đã đưa toàn bộ screens vào trong một folder có cùng tên với định nghĩa route: user/ -> User/. Folder User chứa màn hình List và màn hinh Form bên trong. Từ đó bạn có thể dễ dàng tìm thấy màn hình nào render route nào bằng cách nhìn vào url.

Một màn hình có thể sử dụng để render nhiều route, như chúng ta thấy màn hình Form sẽ render 2 route dành cho việc Create và Edit. Chú ý rằng, chúng ta nên thêm prefix Screen khi đặt tên cho các screen, để tránh nhầm lẫn với các component trong folder components.

Như vậy tên của screen component đặt trong folder src/screens/User/List.jsx nên được đặt là ScreenUserList:

```javascript
import React from "react";

import UserForm from "../../components/User/Form/Form";

const ScreensUserForm = ({ match: { params } }) => (
  <div>
    <h1>{`${!params.id ? "Create" : "Update"}`} User</h1>
    <UserForm id={params.id} />
  </div>
);

export default ScreensUserForm;
```

Như trong đoạn code trên thì screen component sẽ không xử lý gì liên quan đến state (data) mà chỉ thực hiện render ra component _UserForm_.

Cuối cùng thì chúng ta sẽ có được một cấu trúc folder như sau:

```javascript
src
├─ components
│  ├─ User
│  │ ├─ Form
│  │ │ ├─ Form.jsx
│  │ │ └─ Form.css
│  │ └─ List.jsx
│  └─ UI
│
└─ screens
  ├─ User
  │ ├─ Form.jsx
  │ └─ List.jsx
  └─ Root.jsx
```

## Tổng kết

Tóm tắt lại, chúng ta cần nhớ những điểm sau đây:

- **Presentational** và **Container** components được đặt trong folder src/components
- Nhóm các components lại dựa trên module/feature
- Đưa những component chung được sử dụng nhiều lần (UI components) vào trong src/components/UI
- Viết component **screens** (màn hình) thật đơn giản, ít code
- Nhóm các màn hình lại theo route của ứng dụng. Với route /user/list thì screen sẽ nằm trong src/screens/User/List.jsx.
- Components được dặt tên theo đường dẫn tương đối của so với src/components hoặc src - Tên component trong file src/components/User/List.jx sẽ có tên là UserList, tên component trong file src/screens/User/List.jsx sẽ có tên là ScreensUserList.
- Component trong file có cùng tên với folder chứa nó sẽ không lặp lại tên của folder. Ví dụ file src/components/User/List/List.jsx sẽ có component được đặt tên là UserList, chứ **KHÔNG PHẢI** là UserListList

# Kết luận

Bài viết đã đưa ra một trong những cách để tổ chức, phân chia cũng như đặt tên cho file, folder và component khi thiết kế ứng dụng bằng React. Đương nhiên, đây chỉ là ý kiến chủ quan, bạn hoàn toàn có thể tự mình thiết lập và đưa ra những pattern mà bạn cảm thấy hợp lý, thuận tiện khi làm việc với React, miễn sao cho trải nghiệm của bản thân là tốt nhất. Xin cảm ơn!
]]></description>
            <link>https://hungvn.com/blog/cau-truc-projects-va-dat-ten-components-trong-react</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cau-truc-projects-va-dat-ten-components-trong-react</guid>
            <pubDate>Sat, 26 May 2018 23:02:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Gooact: React trong 160 dòng code JavaScript]]></title>
            <description><![CDATA[
## Làm thế nào để xây dựng React cho riêng mình chỉ trong vài phút.

### **Giới thiệu**

[**React**](https://reactjs.org) là một thư viện tuyệt vời - nhiều nhà phát triển ngay lập tức đã yêu thích nó vì tính đơn giản, hiệu suất và cách khai báo làm việc. Nhưng cá nhân tôi có một lý do cụ thể khiến nó trở nên đặc biệt đối với tôi - và đó là cách nó hoạt động bên dưới. Tôi tìm thấy những ý tưởng đứng đằng sau React đơn giản nhưng kỳ lạ thú vị - và tôi tin rằng sự hiểu biết nguyên tắc cốt lõi của nó sẽ giúp bạn viết mã nhanh hơn và an toàn hơn.

Trong bài viết này, tôi sẽ chỉ cho cho bạn cách viết một bản sao của React đầy đủ chức năng, bao gồm Component API và tự triển khai Virtual DOM. Nó được chia thành bốn phần - mỗi phần là một chủ đề chính:

- **Elements**: Trong phần này chúng ta sẽ tìm hiểu cách các khối JSX được xử lý thành phiên bản nhẹ của DOM được gọi là VDOM như thế nào.
- **Rendering**: Trong phần này tôi sẽ hướng dẫn bạn cách chuyển đổi VDOM thành DOM thông thường.
- **Patching**: Trong phần này tôi sẽ trình bày lý do tại sao thuộc tính "key" quan trọng như thế và cách sử dụng VDOM để nối lại với DOM hiện tại một cách hiệu quả.
- **Components:** Phần cuối cùng sẽ cho bạn biết về các thành phần React và quy trình tạo, vòng đời và dựng hình của chúng.

Mỗi phần sẽ kết thúc bằng một ví dụ có link **CodePen** trực tiếp, vì vậy bạn có thể ngay lập tức kiểm tra tất cả các tiến trình chúng ta đã thực hiện. Bắt đầu nào.

### **Elements**

![](https://cdn-images-1.medium.com/max/1600/1*KQcMpRQeOW0sdc0wYrwSrw.png)

[**Element**](https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html#elements-describe-the-tree) là một đối tượng trọng lượng nhẹ của một DOM thực tế. Nó chứa tất cả thông tin quan trọng - như node type, attributes và danh sách children —  vì vậy nó có thể dễ dàng rendered trong tương lai. Thành phần giống như cây của các elements được gọi là VDOM - một ví dụ được hiển thị bên dưới:

```javascript
{
    "type": "ul",
    "props": {
        "className": "some-list"
    },
    "children": [
        {
            "type": "li",
            "props": {
                "className": "some-list__item"
            },
            "children": [
                "One"
            ]
        },
        {
            "type": "li",
            "props": {
                "className": "some-list__item"
            },
            "children": [
                "Two"
            ]
        }
    ]
}
```

Thay vì viết object quái dị đó mọi lúc, hầu hết các nhà phát triển React đều sử dụng cú pháp JSX, trông giống như một sự kết hợp gọn gàng giữa mã JavaScript và các thẻ HTML:

```html
/** @jsx createElement */ const list =
<ul className="some-list">
  <li className="some-list__item">One</li>
  <li className="some-list__item">Two</li>
</ul>
;
```

In order to get executed it needs to be transpiled into regular function calls — notice that pragma comment which defines what function must be used:
Để được thực hiện, nó cần phải được chuyển thành các gọi hàm thông thường - chú ý comment pragma là phải luôn sử dụng:

```javascript
const list = createElement(
  "ul",
  { className: "some-list" },
  createElement("li", { className: "some-list__item" }, "One"),
  createElement("li", { className: "some-list__item" }, "Two")
);
```

Cuối cùng, function mong muốn được gọi - và nó được cho là trả về cấu trúc VDOM được mô tả ở trên. Việc triển khai của chúng tôi sẽ ngắn gọn - nhưng mặc dù có vẻ nguyên thủy, nó phục vụ mục đích cần một cách hoàn hảo:

```javascript
const createElement = (type, props, ...children) => {
  props = props != null ? props : {};
  return { type, props, children };
};
```

CodePen đầu tiên có sẵn [**ở đây**](https://codepen.io/SweetPalma/pen/gzpZNv?editors=0010)— nó chứa phương pháp được mô tả ở trên với một vài cây VDOM do nó tạo ra.

### Rendering

![](https://cdn-images-1.medium.com/max/1600/1*Wc-kOHkiu41Rc69-cG9KhA.png)

[**Rendering**](https://reactjs.org/docs/rendering-elements.html) là một quá trình biến VDOM thành DOM hiển thị. Nói chung, nó là một thuật toán khá đơn giản mà đi qua cây VDOM và tạo ra phần tử DOM tương ứng cho mỗi node:

```javascript
const render = (vdom, parent = null) => {
  if (parent) parent.textContent = "";
  const mount = parent ? el => parent.appendChild(el) : el => el;
  if (typeof vdom == "string" || typeof vdom == "number") {
    return mount(document.createTextNode(vdom));
  } else if (typeof vdom == "boolean" || vdom === null) {
    return mount(document.createTextNode(""));
  } else if (typeof vdom == "object" && typeof vdom.type == "function") {
    return mount(Component.render(vdom));
  } else if (typeof vdom == "object" && typeof vdom.type == "string") {
    const dom = document.createElement(vdom.type);
    for (const child of [].concat(...vdom.children)) // flatten
      dom.appendChild(render(child));
    for (const prop in vdom.props) setAttribute(dom, prop, vdom.props[prop]);
    return mount(dom);
  } else {
    throw new Error(`Invalid VDOM: ${vdom}.`);
  }
};

const setAttribute = (dom, key, value) => {
  if (typeof value == "function" && key.startsWith("on")) {
    const eventType = key.slice(2).toLowerCase();
    dom.__gooactHandlers = dom.__gooactHandlers || {};
    dom.removeEventListener(eventType, dom.__gooactHandlers[eventType]);
    dom.__gooactHandlers[eventType] = value;
    dom.addEventListener(eventType, dom.__gooactHandlers[eventType]);
  } else if (key == "checked" || key == "value" || key == "id") {
    dom[key] = value;
  } else if (key == "key") {
    dom.__gooactKey = value;
  } else if (typeof value != "object" && typeof value != "function") {
    dom.setAttribute(key, value);
  }
};
```

Code ở trên có vẻ trông đáng sợ, nhưng hãy làm cho mọi thứ trở nên ít phức tạp hơn bằng cách tách nó thành các phần nhỏ hơn:

- **Custom Attribute Setter**: Các thuộc tính được chuyển đến VDOM không phải lúc nào cũng hợp lệ về DOM - những thứ như trình xử lý sự kiện, key định danh và các giá trị phải được xử lý riêng lẻ.
- **Primitive VDOM rendering:** Primitives — như strings, numbers, booleans và nulls — được chuyển thành các node văn bản thuần túy.
- **Complex VDOM rendering:** Nodes với tag string được biến thành các phần tử DOM với hiển thị children theo đệ quy.
- **Component VDOM rendering**: Nodes với tag function tag được xử lý riêng — không chú ý nhiều đến phần đó, chúng ta sẽ thực hiện nó sau.

CodePen thứ hai có sẵn [**ở đây**](https://codepen.io/SweetPalma/pen/ZoGwWY?editors=0010)— nó thể hiện thuật toán render trong hành động.

### Patching

![](https://cdn-images-1.medium.com/max/1600/1*2IcfCputh--ch7rTVLCmcw.png)

[**Patching**](https://reactjs.org/docs/reconciliation.html) là một quá trình hòa hợp DOM hiện có với cây VDOM mới được xây dựng.

Hãy tưởng tượng bạn có một số VDOM lồng nhau sâu và cập nhật thường xuyên. Khi một cái gì đó thay đổi, ngay cả phần nhỏ nhất - mà phải được hiển thị. Triển khai native sẽ yêu cầu render toàn bộ mỗi lần cập nhật như vậy.

- Xóa các nút DOM hiện có.
- Re-render mọi thứ.

Đó là lý do thực tế — xây dựng DOM và vẽ lại nó là một hoạt động khá tốn kém. Nhưng chúng ta có thể tối ưu hóa điều này bằng cách viết thuật toán và sẽ yêu cầu ít sửa đổi DOM:

- Xây dựng một VDOM mới.
- Đệ quy so sánh nó với DOM hiện có.
- Tìm các nút đã được thêm, xóa hoặc thay đổi theo bất kỳ cách nào.
- Patch(Vá) chúng lại.

Nhưng sau đó một vấn đề khác nổi lên — độ phức tạp tính toán. So sánh hai cây có độ phức tạp O(n³) — ví dụ: nếu bạn định patch một ngìn elements — nó sẽ yêu cầu _một tỷ_ so sánh. Điều đó là quá nhìu. Thay vào đó, chúng ta sẽ triển khai một thuật toán độ phức tạp O(n) với hai giả định sau:

- Hai elements của các loại khác nhau sẽ tạo ra những cây khác nhau.
- Nhà phát triển có thể gợi ý các phần tử con nào có thể không đổi qua các lần render khác nhau với prop "key".

Trong thực tế, các giả định này có giá trị đối với hầu hết các trường hợp sử dụng thực tế. Bây giờ chúng tôi đã sẵn sàng cho một phần code khác:

```javascript
const patch = (dom, vdom, parent = dom.parentNode) => {
  const replace = parent ? el => parent.replaceChild(el, dom) && el : el => el;
  if (typeof vdom == "object" && typeof vdom.type == "function") {
    return Component.patch(dom, vdom, parent);
  } else if (typeof vdom != "object" && dom instanceof Text) {
    return dom.textContent != vdom ? replace(render(vdom)) : dom;
  } else if (typeof vdom == "object" && dom instanceof Text) {
    return replace(render(vdom));
  } else if (typeof vdom == "object" && dom.nodeName != vdom.type.toUpperCase()) {
    return replace(render(vdom));
  } else if (typeof vdom == "object" && dom.nodeName == vdom.type.toUpperCase()) {
    const pool = {};
    const active = document.activeElement;
    for (const index in Array.from(dom.childNodes)) {
      const child = dom.childNodes[index];
      const key = child.__gooactKey || index;
      pool[key] = child;
    }
    const vchildren = [].concat(...vdom.children); // flatten
    for (const index in vchildren) {
      const child = vchildren[index];
      const key = (child.props && child.props.key) || index;
      dom.appendChild(pool[key] ? patch(pool[key], child) : render(child));
      delete pool[key];
    }
    for (const key in pool) {
      if (pool[key].__gooactInstance) pool[key].__gooactInstance.componentWillUnmount();
      pool[key].remove();
    }
    for (const attr of dom.attributes) dom.removeAttribute(attr.name);
    for (const prop in vdom.props) setAttribute(dom, prop, vdom.props[prop]);
    active.focus();
    return dom;
  }
};
```

Hãy điều tra tất cả các kết hợp có thể:

- **Primitive VDOM + Text DOM:** So sánh giá trị VDOM với nội dung DOM và thực hiện full render nếu chúng khác nhau.
- **Primitive VDOM + Element DOM :** Full render.
- **Complex VDOM + Text DOM :** Full render.
- **Complex VDOM + Element DOM of different type :** Full render.
- **Complex VDOM + Element DOM of same type :** Sự kết hợp thú vị nhất, nơi diễn ra sự hòa hợp của children, xem chi tiết bên dưới.
- **Component VDOM + any kind of DOM:** Cũng giống như trong phần trước, được xử lý riêng và sẽ được triển khai sau.

Như bạn có thể thấy, các nút text và phức tạp nói chung không tương thích và yêu cầu full render — may mắn thay đó là một sự thay đổi hiếm hoi. Nhưng những gì về sự hòa hợp của children đệ quy - nó thực hiện như sau:

- Current active element is memoized — reconciliation may break focus sometimes.
- DOM children are moved into temporary pool under their respective keys — index is used as a key by default.
- VDOM children are paired to the pool DOM nodes by key and recursively patched — or rendered from scratch if pair is not found.
- DOM nodes that left unpaired are removed from document.
- New attributes are applied to final parent DOM.
- Focus is returned back to previously active element.

CodePen thứ ba có sẵn [**ở đây**](https://codepen.io/SweetPalma/pen/rvOWxa?editors=0010) — bao gồm ví dụ nhỏ về list patching.

### Components

![](https://cdn-images-1.medium.com/max/1600/1*wOrDURrPrNvH3eKeaQuyQQ.png)

[**Component**](https://reactjs.org/docs/react-component.html) về mặt khái niệm tương tự như hàm JavaScript — nó có đầu vào tùy ý được gọi là "props" và trả về tập các elements mô tả những gì sẽ xuất hiện trên màn hình. Nó có thể được định nghĩa là một stateless function hoặc derived class với trạng thái bên trong của riêng và tập các phương thức và các lifecycle hooks. Tôi sẽ ngắn gọn về lý thuyết - tốt hơn hãy xem code:

```javascript
class Component {
  constructor(props) {
    this.props = props || {};
    this.state = null;
  }

  static render(vdom, parent = null) {
    const props = Object.assign({}, vdom.props, { children: vdom.children });
    if (Component.isPrototypeOf(vdom.type)) {
      const instance = new vdom.type(props);
      instance.componentWillMount();
      instance.base = render(instance.render(), parent);
      instance.base.__gooactInstance = instance;
      instance.base.__gooactKey = vdom.props.key;
      instance.componentDidMount();
      return instance.base;
    } else {
      return render(vdom.type(props), parent);
    }
  }

  static patch(dom, vdom, parent = dom.parentNode) {
    const props = Object.assign({}, vdom.props, { children: vdom.children });
    if (dom.__gooactInstance && dom.__gooactInstance.constructor == vdom.type) {
      dom.__gooactInstance.componentWillReceiveProps(props);
      dom.__gooactInstance.props = props;
      return patch(dom, dom.__gooactInstance.render());
    } else if (Component.isPrototypeOf(vdom.type)) {
      const ndom = Component.render(vdom);
      return parent ? parent.replaceChild(ndom, dom) && ndom : ndom;
    } else if (!Component.isPrototypeOf(vdom.type)) {
      return patch(dom, vdom.type(props));
    }
  }

  setState(nextState) {
    if (this.base && this.shouldComponentUpdate(this.props, nextState)) {
      const prevState = this.state;
      this.componentWillUpdate(this.props, nextState);
      this.state = nextState;
      patch(this.base, this.render());
      this.componentDidUpdate(this.props, prevState);
    } else {
      this.state = nextState;
    }
  }

  shouldComponentUpdate(nextProps, nextState) {
    return nextProps != this.props || nextState != this.state;
  }

  componentWillReceiveProps(nextProps) {
    return undefined;
  }

  componentWillUpdate(nextProps, nextState) {
    return undefined;
  }

  componentDidUpdate(prevProps, prevState) {
    return undefined;
  }

  componentWillMount() {
    return undefined;
  }

  componentDidMount() {
    return undefined;
  }

  componentWillUnmount() {
    return undefined;
  }
}
```

Các static methods được gọi internally:

- **Render**: Performs initial rendering. Stateless components are called as a regular function — result is displayed immediately. Class components are instantiated and attached to the DOM — and only then are rendered.
- **Patching:** Performs further update. Sometimes DOM node already has a component instance attached to it — pass new properties to it and patch differences. Perform full render otherwise.

Các Instance methods có nghĩa là có thể bị ghi đè hoặc được gọi trong các derived classes do người dùng định nghĩa:

- **Constructor:** Handles properties and defines initial state, storing them within itself.
- **State modifier:** Handles new state, fires all required lifecycle hooks and initiates patch cycle.
- **Lifecycle hooks:** Set of methods that are fired throughout component life — on mount, during updates and just before it gets removed.

Lưu ý rằng phương thức render bị thiếu — nó được định nghĩa trong các child classes. CodePen cuối cùng có [**ở đây**](https://codepen.io/SweetPalma/pen/gzavjB?editors=0010) — với tất cả các code chúng tôi đã thực hiện cho đến đây cùng với một ví dụ to-do đơn giản.

### Kết luận

Đó là tất cả của tôi — chúng ta có một bản sao React đầy đủ chức năng ngay bây giờ. Tôi sẽ gọi nó là Gooact — đó sẽ là một món quà nhỏ cho người bạn tốt của tôi. Chúng ta hãy xem xét kỹ hơn các kết quả:

- Gooact có thể xây dựng và patch hiệu quả các cây DOM phức tạp bằng cách sử dụng VDOM làm tham chiếu.
- Gooact hỗ trợ cả hai functional và class components — cùng với việc xử lý chính xác internal state và hooks lifecycle hoàn chỉnh.
- Gooact dùng transpiled code cung cấp bởi Babel.
- Gooact vừa đủ trong 160 dòng code JavaScript chưa nén.

Mục đích chính của bài viết này là để chứng minh các nguyên tắc cốt lõi của cấu trúc bên trong React mà không cần phải đi sâu vào các API phụ trợ - đó là lý do tại sao chúng bị thiếu một số thứ sau trong Gooact:

- Gooact không hỗ trợ những thứ như fragments, portals, contexts, references và một số thứ khác đã được giới thiệu trong các phiên bản mới hơn.
- Gooact không triển khai React Fiber do sự phức tạp của nó — nhưng tôi có thể viết một bài về nó trong tương lai.
- Gooact không theo dõi các key trùng lặp và đôi khi có thể gây ra lỗi.
- Gooact thiếu hỗ trợ callbacks thêm cho một số methods.

Như bạn có thể thấy, đó là một lĩnh vực tuyệt vời cho các tính năng và cải tiến mới - repository có sẵn [**ở đây**](https://github.com/sweetpalma/gooact), do đó, vì vậy đừng ngần ngại fork và thử nghiệm. Bạn thậm chí có thể cài đặt nó bằng cách sử dụng NPM!

Tôi muốn cảm ơn toàn bộ [**React Team**](https://github.com/facebook/react/blob/master/AUTHORS) đã tạo một thư viện tuyệt vời, làm cho cuộc sống của hàng nghìn nhà phát triển trở nên dễ dàng hơn. Đặc biệt cảm ơn đến [**Preact**](https://github.com/developit/preact) tác giả chính là [**Jason Miller**](https://twitter.com/_developit) — bài viết này đã được lấy cảm hứng từ cách tối giản nó được thực hiện.

![](https://cdn-images-1.medium.com/max/1600/1*Ok_UbUJOtYxN08pFNHMwMQ.png)
]]></description>
            <link>https://hungvn.com/blog/gooact-react-trong-160-dong-code-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/gooact-react-trong-160-dong-code-javascript</guid>
            <pubDate>Sat, 26 May 2018 15:13:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cơ chế sử dụng Virtual DOM trong React]]></title>
            <description><![CDATA[
Khi tìm hiểu về ReactJS, chắc hẳn bạn đã nghe tới khái niệm DOM ảo (Virtual DOM). Nó giúp cho hiệu suất làm việc của React cao hơn hẳn so với các thư viện và framework Javascript khác. Nhưng bạn đã bao giờ tìm hiểu DOM ảo là gì và nó hoạt động như thế nào trong React? Hôm nay, chúng ta cùng tìm hiểu về chủ đề này nhé.

## **Virtual DOM là gì?**

Điều đầu tiên tôi muốn nói ở đây là: Virtual DOM không được phát minh ra bởi React, mà React sử dụng nó. DOM ảo là một bản sao chép trừu tượng của DOM thật (HTML DOM). Bạn có thể tưởng tượng nó giống như một bản thiết kế, chứa các chi tiết cần thiết để cấu hình lên một DOM. Ví dụ, thay vì tạo một thẻ `<div>` thật chứa các thẻ `<ul>` bên trong, nó sẽ tạo một div object chứa `ul` object bên trong. Cụ thể ở trong React sẽ là các `React.div` và `React.ul`. Khi tương tác, ta có thể tương tác với các object đó rất nhanh mà không phải động tới DOM thật hoặc thông qua DOM API. Tiếp theo chúng ta sẽ tìm hiểu cụ thể React tương tác với DOM ảo như thế nào nhé

## **Virtual DOM trong React**

Trước tiên, đã bao giờ bạn tự hỏi tại sao lại phải tương tác thông qua DOM ảo, sao không render trực tiếp ở DOM thật? Vậy bạn đã thực sự hiểu rõ DOM được tạo và re-render như thế nào mỗi khi các thành phần trong DOM thay đổi?

![](https://cdn-images-1.medium.com/max/800/1*ZrzXoRljG5Co5KvEsWJNjA.png)

Mỗi khi có sự thay đổi, vì cấu trúc của DOM là **tree structure** , khi muốn thay đổi các element và các thẻ con của nó, nó phải thông qua các **Reflow/Layout**, sau đó các thay đổi đó sẽ được Re-painted, rất mất thời gian. Vì thế, càng nhiều các item phải **reflow/repaint**, web của bạn sẽ càng load chậm. Vậy React đã sử dụng DOM ảo như thế nào? Để một trang lớn như Facebook mà chúng ta dùng hàng ngày có hiệu suất làm việc cao như vậy? Để dễ hình dung, chúng ta sẽ tìm hiểu thông qua một ví dụ nho nhỏ dưới đây nhé.

![](https://cdn-images-1.medium.com/max/800/1*QX2kUf7GoCkTNkTWBUfX-g.png)

Đó là giao diện của một app cộng hoặc trừ 2 số. Người dùng sẽ nhập vào 2 số vào 2 ô input, sau đó chọn phép toán và in ra kết quả ở phần Output.

```javascript
import React, { Component } from 'react';

export default class Calculator extends Component {
  constructor(props) {
    super(props);
    this.state = { output: '' };
  }

  render() {
    let IntegerA, IntegerB, IntegerC;

    return (
      <div className="container">
        <h2>using React</h2>
        <div>
          Input 1:
          <input type="text" placeholder="Input 1" ref="input1" />
        </div>
        <div>
          Input 2 :
          <input type="text" placeholder="Input 2" ref="input2" />
        </div>
        <div>
          <button
            id="add"
            onClick={() => {
              IntegerA = parseInt(this.refs.input1.value);
              IntegerB = parseInt(this.refs.input2.value);
              IntegerC = IntegerA + IntegerB;
              this.setState({ output: IntegerC });
            }}
          >
            Add
          </button>

          <button
            id="subtract"
            onClick={() => {
              IntegerA = parseInt(this.refs.input1.value);
              IntegerB = parseInt(this.refs.input2.value);
              IntegerC = IntegerA - IntegerB;
              this.setState({ output: IntegerC });
            }}
          >
            Subtract
          </button>
        </div>
        <div>
          <hr />
          <h2>Output: {this.state.output}</h2>
        </div>
      </div>
    );
  }
}


import React, { Component } from 'react';
import Calculator from './Calculator';

export default class Layout extends Component {
  render() {
    return (
      <div>
        <h1>Basic Calculator</h1>
        <Calculator />
      </div>
    );
  }
}

```

Và đây là DOM thật sau lần load đầu tiên

![How DOM looks after initial rendering](https://cdn-images-1.medium.com/max/800/1*UeJO46kqBIm0Z8j9B8G6kw.png)

Còn đây là DOM ảo mà React tạo ra tương ứng với DOM thật bên trên. Trong React, nó cũng được gọi là một Component với **tree structure** gồm các Component con bên trong

![Component Tree structure build by React](https://cdn-images-1.medium.com/max/800/1*WMkI8W__gUagZEVCUN37Pg.png)

Sau đây, chúng ta sẽ cùng thử nhập vào 2 số và click vào button Add và xem React xử lí như thế nào nhé.

```
Input 1: 100
Input 2: 50

Output mong đợi sẽ là 150.
```

Điều gì xảy ra khi ta click vào button Add? Ở ví dụ này, chúng ta set **output** là một **state**, vì thế khi một **output** mới được hiện ra nghĩa là ta đã set cho **State** đó một giá trị mới đó là 150.

### Đánh dấu Component dirty

![Calculator component marked Dirty](https://cdn-images-1.medium.com/max/600/1*SBXiC6G3cjT5deW1tR0C4w.png)

Trong React, khi một Component có một **state** mới được set, React đánh dấu nó như là một **dirty Component**, nghĩa là mỗi khi chúng ta gọi tới function _setState()_ thì Component đó sẽ được đánh dấu là **dirty**. Cụ thể ở đây, khi ta click Add, React sẽ đánh dấu Component **Calculator** như thế nào:

1.  Tất cả các event khi ta thao tác với DOM, nó được gói trọn trong **React event listener**. Vì thế khi nút Add được click, event đó được gửi tới **React event listener** và sau đó nó sẽ chạy một _anonymous function_()
2.  Trong _anonymous function()_, chúng ta gọi tới function _this.setState_ với một **state** value mới.
3.  Function _this.setState_() được chạy, Component **Calculator** được đánh dấu là **dirty**.

```javascript
//ReactUpdates.js  - enqueueUpdate(component) function
dirtyComponents.push(component);
```

4.  Và hiện tại, Calculator của chúng ta đã được đánh dấu là **dirty**. Cùng xem những gì sẽ diễn ra tiếp theo

### Chạy qua Component lifecycle

[Component lifecycle](https://reactjs.org/docs/react-component.html) trong React là một loạt các hàm mặc định sẽ được chạy ngay trước, trong và ngay sau quá trình update một Component. Ở ví dụ này, chúng ta không overwrite các hàm đó thì nó sẽ chạy ở các giá trị mặc định.

![](https://cdn-images-1.medium.com/max/800/1*HmOs3RG_uYsneZFHnrmYEA.png)

Quá trình update Component được diễn ra như sau:

1.  React sẽ kiểm tra Component đó có được mark **dirty** hay không, sau đó bắt đầu quá trình update.

```javascript
//ReactUpdates.js
var flushBatchedUpdates = function () {
  while (dirtyComponents.length || asapEnqueued) {
    if (dirtyComponents.length) {
      var transaction = ReactUpdatesFlushTransaction.getPooled();
      transaction.perform(runBatchedUpdates, null, transaction);
```

2.  Sau đó, React sẽ kiểm tra xem có **pending state** nào phải được update hay không hoặc có **forceUpdate** nào không

```javascript
if (this._pendingStateQueue !== null || this._pendingForceUpdate) {
      this.updateComponent(transaction, this._currentElement,
      this._currentElement, this._context, this._context);
```

![](https://cdn-images-1.medium.com/max/600/1*UVixYuczWFlNJ7tbM4TAsg.png)

Trong ví dụ này của chúng ta, trong Calculator wrapper, **this.pendingStateQueue,** chứa State object với giá trị Output mới 3\. React chạy các lifecycle methods. Đầu tiên là _componentWillReceiveProps_(), tiếp đó là _shouldComponentUpdate()_ (các phương thức này có giá trị mặc định thế nào nếu chúng ta không overwrite nó thì các bạn tự tìm hiểu nhé). Trong trường hợp này, method _shouldComponentUpdate()_ sẽ trả về _true_, sau đó sẽ chạy _componentWillUpdate(), render()_ và _componentDidUpdate()_. Thứ quan trọng nhất trong quá trình update ở đấy chính là _render()_, đó chính là chỗ mà DOM ảo được tạo lại và update DOM ảo để tìm ra sự khác biệt để sau đó cập nhật ở DOM thật, hay nói các khác là tìm ra cụ thể những element thay đổi để update chỉ những element đó trong DOM thật.

### Xây dựng lại Component, Update DOM ảo, tìm sự thay đổi, update DOM thật

![](https://cdn-images-1.medium.com/max/800/1*9paXIsNMjkuN4iBdpJ-MXg.png)

React sẽ kiểm tra các element trước và sau khi được render lại ở lần vừa rồi có giống nhau hay không, sau đó bắt đầu quá trình đồng bộ.

```javascript
var prevRenderedElement = this._renderedComponent._currentElement;
var nextRenderedElement = this._instance.render(); //Calculator.render() method is called and the element is build.
```

Quá trình đồng bộ và update DOM thật như sau:

![](https://cdn-images-1.medium.com/max/800/1*chzMjpfd821rcHntjWb8rQ.png)

Những điểm màu đỏ nghĩa là quá trình đồng bộ sẽ được lặp lại đối với những thành phần con của nó. Và đây là DOM mà chúng ta nhận được sau quá trình đó :

![](https://cdn-images-1.medium.com/max/600/1*l2w9vcsBN7wd2UqZ7qZTHA.png)

Trong ví dụ này, chỉ có phần Output bị thay đổi, bạn có thể nhìn thấy phần được đánh dấu flash ở hình dưới, chỉ có phần đó được DOM thật re-painted

![](https://cdn-images-1.medium.com/max/800/1*-N2b8UJgqIUtgUfPLWtQQw.png)

Và cây component được cập nhật tại DOM thực tế.

![](https://cdn-images-1.medium.com/max/800/1*xvjOyXVne-7Y0ch0dRTIdw.png)

## **Kết luận**

Qua ví dụ trên mong là bạn có thể hình dung phần nào đó cách thực hoạt động của DOM ảo trong React và tính hữu dụng của nó. Nhờ có DOM ảo, React có thể tìm ra các node bị thay đổi và update ở DOM thật chỉ ở những cái node đó, thật thuận tiện và nhanh gọn phải không nào.
]]></description>
            <link>https://hungvn.com/blog/co-che-su-dung-virtual-dom-trong-react</link>
            <guid isPermaLink="true">https://hungvn.com/blog/co-che-su-dung-virtual-dom-trong-react</guid>
            <pubDate>Fri, 25 May 2018 22:22:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm Hiểu Regular Expression Javascript]]></title>
            <description><![CDATA[
Regular expression hay còn được gọi tắt là Regex hay RegExp, là một cách để biểu diễn khuôn mẫu của string. Đây là một phần của ngôn ngữ lập trình JavaScript, cũng như nhiều ngôn ngữ lập trình khác. Nếu bạn là một lập trình viên và đã từng sử dụng Regular Expression thì bạn chắc hẳn sẽ thấy rằng nó có cú pháp rất kinh khủng và có phần "bí ẩn". Tuy nhiên, công cụ này lại cực kì mạnh mẽ và hiệu quả khi dùng để xử lý string. Sau đây, chúng ta sẽ cùng tìm hiểu về Regular Expression trong JavaScript.

## Khởi tạo Regular Expression

Có hai cách để tạo ra một Regular Expression là:

- Sử dụng hàm khởi tạo của đối tượng RegExp
- Viết trực tiếp sử dụng cặp dấu "/ /"

```javascript
var re1 = new RegExp("abc");
var re2 = /abc/;
```

Cả hai cách trên ta đều thu được một Regular Expression biểu diễn một string có dạng: _abc_.

## Một số phương thức của Regular Expression

### Phương thức Test

Đây là phương thức đơn giản nhất dùng để kiểm tra xem một string có chứa khuôn mẫu đã định nghĩa hay không. Nếu có thì kết quả trả về là TRUE và ngược lại thì là FALSE.

```javascript
console.log(/abc/.test("abcde"));
// => true
console.log(/abc/.test("12abcde"));
// => true
console.log(/abc/.test("abxcde"));
// => false
```

Trong ví dụ trên, 2 string "abcde" và "12abcde" đều chứa "abc" nên kết quả trả về là true. String còn lại "abxcde" không chứa "abc" nên kết quả là false.

#### Kiểm tra trùng khớp với tập hợp các kí tự

Nếu chỉ kiểm tra như ví dụ trên thì bạn hoàn toàn có thể sử dụng phương thức *indexOf* của string thay vì sử dụng Regular Expression. Tuy nhiên, với Regular Expression thì bạn có thể kiểm tra những mẫu string phức tạp hơn. **Ví dụ:**

```javascript
console.log(/[0123456789]/.test("in 1992"));
// => true
console.log(/[0-9]/.test("in 1992"));
// => true
console.log(/[0-9]/.test("Hello "));
// => false
console.log(/[0-5]/.test("Gold 9999"));
// => false
```

Ví dụ 1, 2, 3 kiểm tra xem string có chứa bất kì chữ số nào từ 0 đến 9\. Ví dụ cuối cùng kiểm tra xem string có chứa bất kì chữ số nào từ 0 đến 5\. JavaScript sử dụng cặp dấu ngoặc vuông [] để biểu thị việc kiểm tra string có chứa bất kì kí tự nào có trong cặp dấu [] hay không. Trong đó, dấu "-" giữa hai kí tự dùng để chỉ 1 khoảng giữa hai kí tự đó.

- [0-9] là các chữ số từ 0 đến 9
- [a-z] là các chữ cái từ a đến z

Ngoài ra, JavaScript cung cấp sẵn một số cách biểu diễn một tập hợp các kí tự:

- \d : bất kì chữ số nào từ 0 đến 9
- \w : một chữ cái
- \s : kí tự trắng (dấu cách, tab, dòng mới,...)
- \D : kí tự không phải số
- \W : kí tự không phải chữ cái
- \S : kí tự không phải kí tự trắng
- . : bất kì kí tự nào trừ dòng mới.

Ví dụ kiểm tra ngày giờ có định dạng: **dd-mm-yyyy hh:mm**

```javascript
var dateTime = /\d\d-\d\d-\d\d\d\d \d\d:\d\d/;
console.log(dateTime.test("30-01-2003 15:20"));
// => true
console.log(dateTime.test("30-jan-2003 15:20"));
// => false
```

#### Đảo ngược tập hợp các kí tự

Trường hợp bạn muốn kiểm tra một string chứa bất kì kí tự nào không có trong tập hợp đã cho thì bạn có thể sử dụng kí tự "^". Ví dụ:

```javascript
var notBinary = /[^01]/;
console.log(notBinary.test("1100100010100110"));
// => false
console.log(notBinary.test("1100100010200110"));
// => true
```

#### Lặp lại khuôn mẫu

Trong ví dụ về kiểm tra ngày giờ bên trên, "\d" xuất hiện lặp lại rất nhiều lần. Điều này gây nên sự khó theo dõi. Do đó, JavaScript cung cấp cách thức để biểu diễn sự lặp lại khuôn mẫu:

- "+": biểu thị phần tử xuất hiện `>= 1` lần

```javascript
console.log(/'\d+'/.test("'123'"));
// => true
console.log(/'\d+'/.test("''"));
// => false
```

- "\*": biểu thị phần tử xuất hiện `>= 0` lần (có thể không xuất hiện)

```javascript
console.log(/'\d*'/.test("'123'"));
// => true
console.log(/'\d*'/.test("''"));
// => true
```

- "?": biểu thị phần tử xuất hiện 0 hoặc 1 lần

```javascript
var neighbor = /neighbou?r/;
console.log(neighbor.test("neighbour"));
// => true
console.log(neighbor.test("neighbor"));
// => true
console.log(neighbor.test("neighbouur"));
// => false
```

- `{n}`: biểu thị phần tử xuất hiện đúng n lần

```javascript
console.log(/\d{4}/.test("1234"));
// => true
console.log(/\d{4}/.test("12345"));
// => true
console.log(/\d{4}/.test("123"));
// => false
```

- `{x,y}`: biểu thị phần tử xuất hiện từ x đến y lần

```javascript
console.log(/\d{2,4}/.test("12345"));
// => true
console.log(/\d{2,4}/.test("1234"));
// => true
console.log(/\d{2,4}/.test("123"));
// => true
console.log(/\d{2,4}/.test("12"));
// => true
console.log(/\d{2,4}/.test("1"));
// => false
```

- `{x, }`: biểu thị phần tử xuất hiện `>= x` lần

```javascript
console.log(/\d{2,}/.test("12"));
// => true
console.log(/\d{2,}/.test("1234"));
// => true
console.log(/\d{2,}/.test("1"));
// => false
```

#### Nhóm các phần tử

Trong nhiều trường hợp bạn muốn lặp lại cả một nhóm các phần tử. Khi đó, bạn phải nhóm các phần tử đó lại sử dụng cặp dấu ngoặc đơn "( )".

```javascript
var cartoonCrying = /boo+(hoo+)+/i;
console.log(cartoonCrying.test("Boohoooohoohooo"));
// => true
```

#### Lựa chọn khuôn mẫu

Trường hợp bạn có nhiều khuôn mẫu và bạn cần kiểm tra xem string đưa ra chứa một trong các khuôn mẫu đó thì bạn có thể viết các Regular Expression tương ứng để kiểm tra. Hoặc sử dụng kí tự (|) để biểu diễn "hoặc":

```javascript
var animalCount = /\d+ (pig|cow|chicken)s?/;
console.log(animalCount.test("15 pigs"));
// => true
console.log(animalCount.test("15 pigchickens"));
// => false
```

### Phương thức Exec

Nếu như phương thức **test** chỉ kiểm tra xem có tồn tại khuôn mẫu hay không thì phương thức **exec** sẽ trả về một đối tượng chứa thông tin thành phần trùng khớp với khuôn mẫu, ngược lại thì trả về null.

```javascript
var match = /\d+/.exec("one two 100 200");
console.log(match);
// => ["100", index: 8, input: "one two 100 200"]
console.log(match.index);
// => 8
```

Ví dụ trên trả về thành phần thoả mãn khuôn mẫu đầu tiên là: "100". _Index_ là vị trí đầu tiên của string thoả mãn khuôn mẫu. Khi Regular Expression chứa group với cặp dấu ngoặc đơn thì phần tử đầu tiên trong kết quả sẽ là toàn bộ thành phần trùng khớp, thành phần tiếp theo là phần trùng khớp với group đầu tiên, thành phần tiếp theo là phần trùng khớp với group thứ 2,...

```javascript
var quotedText = /'([^']*)'/;
console.log(quotedText.exec("she said 'hello'"));
// => ["'hello'", "hello", index: 9, input: "she said 'hello'"]

console.log(/bad(ly)?/.exec("bad"));
// => ["bad", undefined, index: 0, input: "bad"]

console.log(/(\d)+/.exec("123"));
// => ["123", "3", index: 0, input: "123"]
```

#### Trích xuất dữ liệu từ string

Phương thức này đặc biệt hữu ích khi bạn muốn lấy thông tin ra từ string. Ví dụ sau đưa ra một string biểu diễn ngày, tháng, năm. Sau đó chúng ta sẽ trích xuất ra thông tin về ngày, tháng và năm ở trong đó:

```javascript
function findDate(string) {
  var dateTime = /(\d{1,2})-(\d{1,2})-(\d{4})/;
  var match = dateTime.exec(string);
  return {
    day: match[1],
    month: match[2],
    year: match[3],
  };
}
var obj = findDate("30-1-2003");
console.log(obj);
// => Object {day: "30", month: "1", year: "2003"}
```

#### Ranh giới của string

Trong ví dụ trên, hàm findDate vẫn tìm ra kết quả nếu như string là "30-1-200300" hay "1130-1-2003",... Đây là trường hợp không mong muốn. Regular Expression JavaScript cung cấp 2 cách để giải quyết vấn đề này:

- Sử dụng kí tự biểu diễn bắt đầu `(^)` và kết thúc `($$` string

```javascript
function findDate(string) {
  var dateTime = /^(\d{1,2})-(\d{1,2})-(\d{4})$/;
  var match = dateTime.exec(string);
  if (!match) return null;
  return {
    day: match[1],
    month: match[2],
    year: match[3],
  };
}
var obj1 = findDate("30-1-2003");
console.log(obj1);
// => Object {day: "30", month: "1", year: "2003"}

var obj2 = findDate("0030-1-200300");
console.log(obj2);
// => null

var obj3 = findDate("Hello 30-1-2003 Haha");
console.log(obj3);
// => null
```

- Sử dụng kí tự biên (\b)

```javascript
function findDate(string) {
  var dateTime = /\b(\d{1,2})-(\d{1,2})-(\d{4})\b/;
  var match = dateTime.exec(string);
  if (!match) return null;
  return {
    day: match[1],
    month: match[2],
    year: match[3],
  };
}
var obj1 = findDate("30-1-2003");
console.log(obj1);
// => Object {day: "30", month: "1", year: "2003"}

var obj2 = findDate("0030-1-200300");
console.log(obj2);
// => null

var obj3 = findDate("Hello 30-1-2003 Haha");
console.log(obj3);
// => Object {day: "30", month: "1", year: "2003"}
```

## Tạo đối tượng RegExp một cách linh động

Trong nhiều trường hợp, bạn muốn tạo ra một Regular Expression với nội dung chưa được biết trước. Bạn có thể sử dụng hàm khởi tạo của RegExp theo cách sau:

```javascript
var name = "lampv";
var text = "LamPV is a suspicious character.";
var regexp = new RegExp("\\b(" + name + ")\\b", "gi");
console.log(text.replace(regexp, "_$1_"));
// => _LamPV_ is a suspicious character.
```

Trong đó:

- tham số g: chỉ ra rằng khuôn mẫu áp dụng Global, nghĩa là nó áp dụng cho tất cả thành phần trùng khớp.
- tham số i: chỉ ra rằng khuôn mẫu không phân biệt chữ hoa và chữ thường.

Ngoài ra, ở đây tôi có sử dụng phương thức _replace_ của [string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) - dùng để thay thế tất cả những thành phần trùng khớp với khuôn mẫu với "_$1_". Ở đây $$ chính là nội dung của group thứ nhất.

## Kết luận

Trên đây là một số kiến thức cơ bản về Regular Expression. Hy vọng qua bài viết này bạn phần nào hiểu và biết cách sử dụng công cụ hiệu quả này trong công việc lập trình của mình, đặc biệt là lập trình JavaScript. Tóm tắt một số khuôn mẫu cơ bản của Regular Expression:

- `/abc/` : chuỗi các kí tự _abc_
- `/[abc]`: bất kỳ kí tự nào thuộc tập hợp a, b, c
- `/[^abc]`: bất kỳ kí tự nào không thuộc tập a, b, c
- `/[0-9]/`: bất kỳ kí tự nào thuộc đoạn từ 0 đến 9
- `/x+/`: thành phần x xuất hiện >= 1 lần
- `/x\*/`: thành phần x xuất hiện >= 0 lần (có thể không xuất hiện)
- `/x?/`: thành phần x xuất hiện 0 hoặc 1 lần
- `/x{2, 4}/`: thành phần x xuất hiện từ 2 đến 4 lần
- `/(abc)/`: cụm _abc_
- `/a|b|c/`: bất kì pattern nào trong 3 loại a, b, c
- `/\d/`: chữ số từ 0 đến 9
- `/\w/`: chữ cái
- `/\s/`: kí tự trắng (dấu cách, tab, dòng mới,...)
- `/./` : bất kỳ kí tự nào trừ dòng mới
- `/\b/`: ranh giới từ
- `/^/`: bắt đầu string
- `/$$`: kết thúc string

## Tham khảo

- [http://eloquentjavascript.net/09_regexp.html](http://eloquentjavascript.net/09_regexp.html)
- Bài thực hành của tôi: [Regexp Golf](https://github.com/completejavascript/practical-javascript/blob/master/regular_expression/regexp_golf_completejavascript.com.js), [Quoting style](https://github.com/completejavascript/practical-javascript/blob/master/regular_expression/quoting_style_completejavascript.com.js), [Numbers again](https://github.com/completejavascript/practical-javascript/blob/master/regular_expression/numbers_again_completejavascript.com.js).
- [Xác thực mã màu RGB và mã màu HEX sử dụng Regex trong Javascript](http://phamvanlam.com/xac-thuc-ma-mau-rgb-va-ma-mau-hex-su-dung-regex-trong-javascript/)
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-regular-expression-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-regular-expression-javascript</guid>
            <pubDate>Fri, 25 May 2018 21:38:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giới thiệu về Composing Software]]></title>
            <description><![CDATA[
> Ghi chú: Đây là phần giới thiệu về loạt bài "Composing Software" về việc học các kỹ năng functional programming và compositional software trong JavaScript ES6+ từ đầu. Hãy theo dõi còn rất nhiều thứ khác nữa!
> [_Bài viết Kế tiếp >_](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c)

> Composition: “Hành động kết hợp các parts hoặc elements để tạo thành một tổng thể.”

Trong lớp học lập trình đầu tiên của tôi, tôi đã nói rằng phát triển phần mềm là “hành động phá vỡ một vấn đề phức tạp thành các vấn đề nhỏ hơn, và soạn các giải pháp đơn giản để tạo thành một giải pháp hoàn chỉnh cho vấn đề phức tạp.”

Một trong những hối tiếc lớn nhất của tôi trong cuộc sống là tôi đã không hiểu ý nghĩa của bài học đó từ sớm. Tôi đã học được bản chất của thiết kế phần mềm quá muộn trong cuộc sống.

Tôi đã phỏng vấn hàng trăm developers. Những gì tôi đã học được từ những buổi đó là Tôi không đơn độc. Rất ít developers phần mềm làm việc mà có nắm bắt tốt về bản chất của phát triển phần mềm. Họ không nhận thức được các công cụ quan trọng nhất chúng ta có thể có để xử lý hoặc làm thế nào để đưa chúng vào sử dụng cho tốt. 100% đã đấu tranh để trả lời một hoặc cả hai câu hỏi quan trọng nhất trong lĩnh vực phát triển phần mềm:

- What is function composition?
- What is object composition?

Vấn đề là bạn không thể tránh được 'composition' chỉ vì bạn không biết về nó. Bạn vẫn làm điều đó - nhưng bạn làm điều đó rất tệ. Bạn viết mã với nhiều lỗi hơn và làm cho các developers khác khó hiểu hơn. Đây là một vấn đề lớn. Các ảnh hưởng ấy tốn nhất nhiều chi phí. Chúng tôi dành nhiều thời gian hơn để duy trì phần mềm hơn là chúng tôi tạo ra nó từ đầu và các lỗi của chúng tôi tác động đến hàng tỷ người trên khắp thế giới.

Cả thế giới chạy trên phần mềm ngày nay. Mỗi chiếc xe mới là một siêu máy tính mini trên bánh xe, và các vấn đề với thiết kế phần mềm gây ra tai nạn thực sự và chi phí cuộc sống thực của con người. Vào năm 2013, Ban giám khảo đã tìm thấy nhóm phát triển phần mềm của Toyota có tội ["Liều lĩnh không để ý"](http://www.safetyresearch.net/blog/articles/toyota-unintended-acceleration-and-big-bowl-%E2%80%9Cspaghetti%E2%80%9D-code) sau khi một cuộc điều tra tai nạn cho thấy spaghetti code với 10000 biến global.

[Hackers và governments stockpile bugs](https://www.technologyreview.com/s/607875/should-the-government-keep-stockpiling-software-bugs/) để theo dõi mọi người, ăn cắp thẻ tín dụng, khai thác tài nguyên máy tính để khởi chạy các cuộc tấn công từ chối dịch vụ phân tán (DDoS), crack mật khẩu và thậm chí [điều khiển cuộc bầu cử](https://www.technologyreview.com/s/604138/the-fbi-shut-down-a-huge-botnet-but-there-are-plenty-more-left/).

Chúng ta phải làm tốt hơn.

### You Compose Software Every Day

Nếu bạn là nhà phát triển phần mềm, bạn lập trình các chức năng và cấu trúc dữ liệu mỗi ngày, cho dù bạn có biết hay không. Bạn có thể làm điều đó một cách có ý thức (và tốt hơn), hoặc bạn có thể làm điều đó một cách vô tình, with duct-tape and crazy glue.

Quá trình phát triển phần mềm là chia nhỏ các vấn đề lớn thành các vấn đề nhỏ hơn, xây dựng các thành phần giải quyết những vấn đề nhỏ hơn, sau đó kết hợp các thành phần lại với nhau để tạo thành một ứng dụng hoàn chỉnh.

### Composing Functions

Function composition là quá trình áp dụng một function là output của function khác. Trong đại số, có hai hàm số, `f` và `g`, `(f ∘ g)(x) = f(g(x))`. Vòng tròn là toán tử kết hợp. Nó thường được phát âm "kết hợp với" hoặc là "theo sau". Bạn có thể nói như "f _kết hợp với_ g bằng f of g of x", or "f _theo sau_ g bằng f of g of x". Chúng ta nói f _theo sau_ g bởi vì g is giá trị đầu, sau đó output của nó được chuyển thành đối số f.

Mỗi lần bạn viết code như thế này, nó là composing functions:

```javascript
const g = n => n + 1;
const f = n => n * 2;
const doStuff = x => {
  const afterG = g(x);
  const afterF = f(afterG);
  return afterF;
};
doStuff(20); // 42
```

Mỗi khi bạn viết một chuỗi promise, nó là composing functions:

```javascript
const g = n => n + 1;
const f = n => n * 2;
const wait = time => new Promise((resolve, reject) => setTimeout(resolve, time));
wait(300)
  .then(() => 20)
  .then(g)
  .then(f)
  .then(value => console.log(value)); // 42
```

Tương tự như vậy, mỗi khi bạn thực hiện các gọi các chuỗi phương thức mảng, các hàm lodash, observables (RxJS, etc…) nó là composing functions. Nếu là một chuỗi, thì nó là composing. Nếu bạn chuyển một giá trị trả về vào những functions khác, nó cũng là composing. Nếu bạn gọi hai hàm theo trình tự, nó là composing nếu sử dụng dữ liệu hàm này làm dữ liệu đầu vào cho hàm kia.

> Nếu là một chuỗi, thì nó là composing.

Khi bạn viết một functions có chủ ý, bạn sẽ làm tốt hơn.

Composing functions có chủ ý, chúng ta có thể cải thiện hàm doStuff() thành 1 dòng đơn giản:

```javascript
const g = n => n + 1;
const f = n => n * 2;
const doStuffBetter = x => f(g(x));
doStuffBetter(20); // 42
```

Một trong những phản đối chung về kiểu này là khó để debug. Ví dụ, chúng ta sẽ viết function composition bằng cách nào?

```javascript
const doStuff = x => {
  const afterG = g(x);
  console.log(`after g: ${afterG}`);
  const afterF = f(afterG);
  console.log(`after f: ${afterF}`);
  return afterF;
};

doStuff(20); // =>
/*
"after g: 21"
"after f: 42"
*/
```

Đầu tiên, hãy trừu tượng rằng “after f”, “after g” và viết vào một tiện ích nhỏ gọi là trace():

```javascript
const trace = label => value => {
  console.log(`${label}: ${value}`);
  return value;
};
```

Now we can use it like this:

```javascript
const doStuff = x => {
  const afterG = g(x);
  trace("after g")(afterG);
  const afterF = f(afterG);
  trace("after f")(afterF);
  return afterF;
};

doStuff(20); // =>
/*
"after g: 21"
"after f: 42"
*/
```

Thư viện functional programming phổ biến như Lodash và Ramda bao gồm các tiện ích để thực hiện function composition dễ hơn. Bạn có thể viết lại hàm trên như thế này:

```javascript
import pipe from "lodash/fp/flow";

const doStuffBetter = pipe(g, trace("after g"), f, trace("after f"));

doStuffBetter(20); // =>
/*
"after g: 21"
"after f: 42"
*/
```

If you want to try this code without importing something, you can define pipe like this:
Nếu bạn muốn thử code này mà không cần nhập gì, bạn có thể xác định pipe như thế này:

```javascript
// pipe(...fns: [...Function]) => x => y
const pipe =
  (...fns) =>
  x =>
    fns.reduce((y, f) => f(y), x);
```

Đừng lo lắng nếu bạn chưa thể theo dõi cách hoạt động. Sau đó, chúng tôi sẽ khám phá function composition chi tiết hơn. In fact, it’s so essential, you’ll see it defined and demonstrated many times throughout this text. The point is to help you become so familiar with it that its definition and usage becomes automatic. Be one with the composition.

pipe() creates a pipeline of functions, passing the output of one function to the input of another. When you use pipe() (and its twin, compose()) You don't need intermediary variables. Writing functions without mention of the arguments is called **point-free style.** To do it, you'll call a function that returns the new function, rather than declaring the function explicitly. That means you won't need the function keyword or the arrow syntax (=>).

Point-free style can be taken too far, but a little bit here and there is great because those intermediary variables add unnecessary complexity to your functions.

There are several benefits to reduced complexity:

#### Working Memory

Bộ não con người trung bình chỉ có một vài tài nguyên được chia sẻ cho lượng tử rời rạc trong bộ nhớ làm việc [working memory](http://www.nature.com/neuro/journal/v17/n3/fig_tab/nn.3655_F2.html), và mỗi biến có khả năng tiêu thụ một trong những lượng tử đó. As you add more variables, our ability to accurately recall the meaning of each variable is diminished. Working memory models typically involve 4–7 discrete quanta. Above those numbers, error rates dramatically increase.

Using the pipe form, we eliminated 3 variables — freeing up almost half of our available working memory for other things. That reduces our cognitive load significantly. Software developers tend to be better at chunking data into working memory than the average person, but not so much more as to weaken the importance of conservation.

#### Signal to Noise Ratio

Concise code also improves the signal-to-noise ratio of your code. It’s like listening to a radio — when the radio is not tuned properly to the station, you get a lot of interfering noise, and it’s harder to hear the music. When you tune it to the correct station, the noise goes away, and you get a stronger musical signal.

Code is the same way. More concise code expression leads to enhanced comprehension. Some code gives us useful information, and some code just takes up space. If you can reduce the amount of code you use without reducing the meaning that gets transmitted, you’ll make the code easier to parse and understand for other people who need to read it.

#### Surface Area for Bugs

Take a look at the before and after functions. It looks like the function went on a diet and lost a ton of weight. That’s important because extra code means extra surface area for bugs to hide in, which means more bugs will hide in it.

> _Less code = less surface area for bugs = fewer bugs._

### Composing Objects

> “Favor object composition over class inheritance” the Gang of Four, [“Design Patterns: Elements of Reusable Object Oriented Software”](https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=as_li_ss_tl?ie=UTF8&qid=1494993475&sr=8-1&keywords=design+patterns&linkCode=ll1&tag=eejs-20&linkId=6c553f16325f3939e5abadd4ee04e8b4)

> “In computer science, a composite data type or compound data type is any data type which can be constructed in a program using the programming language’s primitive data types and other composite types. […] The act of constructing a composite type is known as composition.” ~ Wikipedia

These are primitives:

```javascript
const firstName = "Claude";
const lastName = "Debussy";
```

And this is a composite:

```javascript
const fullName = {
  firstName,
  lastName,
};
```

Likewise, all Arrays, Sets, Maps, WeakMaps, TypedArrays, etc… are composite datatypes. Any time you build any non-primitive data structure, you’re performing some kind of object composition.

Note that the Gang of Four defines a pattern called the **composite pattern** which is a specific type of recursive object composition which allows you to treat individual components and aggregated composites identically. Some developers get confused, thinking that the composite pattern is _the only form of object composition._ Don’t get confused. There are many different kinds of object composition.

The Gang of Four continues, “you’ll see object composition applied again and again in design patterns”, and then they catalog three kinds of object compositional relationships, including **delegation** (as used in the state, strategy, and visitor patterns), **acquaintance** (when an object knows about another object by reference, usually passed as a parameter: a uses-a relationship, e.g., a network request handler might be passed a reference to a logger to log the request — the request handler _uses_ a logger), and **aggregation** (when child objects form part of a parent object: a has-a relationship, e.g., DOM children are component elements in a DOM node — A DOM node _has_ children).

Class inheritance can be used to construct composite objects, but it’s a restrictive and brittle way to do it. When the Gang of Four says “favor object composition over class inheritance”, they’re advising you to use flexible approaches to composite object building, rather than the rigid, tightly-coupled approach of class inheritance.

We’ll use a more general definition of object composition from [“Categorical Methods in Computer Science: With Aspects from Topology”](https://www.amazon.com/Categorical-Methods-Computer-Science-Topology/dp/0387517227/ref=as_li_ss_tl?ie=UTF8&qid=1495077930&sr=8-3&keywords=Categorical+Methods+in+Computer+Science:+With+Aspects+from+Topology&linkCode=ll1&tag=eejs-20&linkId=095afed5272832b74357f63b41410cb7) (1989):

> “Composite objects are formed by putting objects together such that each of the latter is ‘part of’ the former.”

Another good reference is “Reliable Software Through Composite Design”, Glenford J Myers, 1975\. Both books are long out of print, but you can still find sellers on Amazon or eBay if you’d like to explore the subject of object composition in more technical depth.

_Class inheritance is just one kind of composite object construction._ All classes produce composite objects, but not all composite objects are produced by classes or class inheritance. “Favor object composition over class inheritance” means that you should form composite objects from small component parts, rather than inheriting all properties from an ancestor in a class hierarchy. The latter causes a large variety of well-known problems in object oriented design:

- **The tight coupling problem:** Because child classes are dependent on the implementation of the parent class, class inheritance is the tightest coupling available in object oriented design.
- **The fragile base class problem:** Due to tight coupling, changes to the base class can potentially break a large number of descendant classes — potentially in code managed by third parties. The author could break code they’re not aware of.
- **The inflexible hierarchy problem:** With single ancestor taxonomies, given enough time and evolution, all class taxonomies are eventually wrong for new use-cases.
- **The duplication by necessity problem:** Due to inflexible hierarchies, new use cases are often implemented by duplication, rather than extension, leading to similar classes which are unexpectedly divergent. Once duplication sets in, it’s not obvious which class new classes should descend from, or why.
- **The gorilla/banana problem:** “…the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.” ~ Joe Armstrong, [“Coders at Work”](http://www.amazon.com/gp/product/1430219483?ie=UTF8&camp=213733&creative=393185&creativeASIN=1430219483&linkCode=shr&tag=eejs-20&linkId=3MNWRRZU3C4Q4BDN)

The most common form of object composition in JavaScript is known as **object concatenation** (aka mixin composition). It works like ice-cream. You start with an object (like vanilla ice-cream), and then mix in the features you want. Add some nuts, caramel, chocolate swirl, and you wind up with nutty caramel chocolate swirl ice cream.

Building composites with class inheritance:

```javascript
class Foo {
  constructor() {
    this.a = "a";
  }
}
class Bar extends Foo {
  constructor(options) {
    super(options);
    this.b = "b";
  }
}
const myBar = new Bar(); // {a: 'a', b: 'b'}
```

Building composites with mixin composition:

```javascript
const a = {
  a: "a",
};
const b = {
  b: "b",
};
const c = { ...a, ...b }; // {a: 'a', b: 'b'}
```

We’ll explore other styles of object composition in more depth later. For now, your understanding should be:

1.  There’s more than one way to do it.
2.  Some ways are better than others.
3.  You want to select the simplest, most flexible solution for the task at hand.

### Conclusion

This isn’t about functional programming (FP) vs object-oriented programming (OOP), or one language vs another. Components can take the form of functions, data structures, classes, etc… Different programming languages tend to afford different atomic elements for components. Java affords classes, Haskell affords functions, etc… But no matter what language and what paradigm you favor, you can’t get away from composing functions and data structures. In the end, that’s what it all boils down to.

We’ll talk a lot about functional programming, because functions are the simplest things to compose in JavaScript, and the functional programming community has invested a lot of time and effort formalizing function composition techniques.

What we won’t do is say that functional programming is better than object-oriented programming, or that you must choose one over the other. OOP vs FP is a false dichotomy. Every real Javascript application I’ve seen in recent years mixes FP and OOP extensively.

We’ll use object composition to produce datatypes for functional programming, and functional programming to produce objects for OOP.

_No matter how you write software, you should compose it well._

> The essence of software development is composition.

A software developer who doesn’t understand composition is like a home builder who doesn’t know about bolts or nails. Building software without awareness of composition is like a home builder putting walls together with duct tape and crazy glue.

It’s time to simplify, and the best way to simplify is to get to the essence. The trouble is, almost nobody in the industry has a good handle on the essentials. We as an industry have failed you, the software developer. It’s our responsibility as an industry to train developers better. We must improve. We need to take responsibility. Everything runs on software today, from the economy to medical equipment. There is literally no corner of human life on this planet that is not impacted by the quality of our software. We need to know what we’re doing.

It’s time to learn how to compose software.

[Continued in “The Rise and Fall and Rise of Functional Programming”](https://medium.com/javascript-scene/the-rise-and-fall-and-rise-of-functional-programming-composable-software-c2d91b424c8c)
]]></description>
            <link>https://hungvn.com/blog/gioi-thieu-ve-composing-software</link>
            <guid isPermaLink="true">https://hungvn.com/blog/gioi-thieu-ve-composing-software</guid>
            <pubDate>Tue, 22 May 2018 08:09:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Sử dụng ký pháp BEM trong CSS]]></title>
            <description><![CDATA[
## Ký pháp BEM là gì

BEM viết tắt của Blocks, Elements, Modifiers, là một phương pháp đặt tên class cho HTML và CSS. Được phát triển [tại Yandex](https://en.bem.info) giúp lập trình viên hiểu rõ hơn mối quan hệ giữa HTML và CSS trong dự án front end.

Ví dụ sau đây sẽ minh hoạ cách sử dụng ký pháp BEM:

```css
/* Một Block (khối) độc lập */
.btn {
}

/* Element (phần tử) con, phụ thuộc vào Block ở trên */
.btn__price {
}

/* Modifier (bộ điều chỉnh) thay đổi trạng thái của Block */
.btn--orange {
}
.btn--big {
}
```

Với cách đặt tên class này, ta có **Block** sẽ đại diện cho một component, và trong ví dụ ở đây, là một button `.btn`. Block cũng sẽ đóng vai trò là một _parent_ mà trong nó sẽ có một hoặc nhiều hơn **Element** con liên quan. Tên class cho Element và mối quan hệ của nó với Block sẽ được diễn tả bằng tên của Block, tiếp theo là _hai gạch dưới_, và cuối cùng là tên của Element `.btn__price`. Thành phần thứ ba của BEM là các **Modifier** mà chúng sẽ giúp điều chỉnh các trạng thái hoặc phái sinh khác của Block / Element. Tên của Modifier sẽ được nối với tên Block / Element phía trước bởi _02 gạch ngang_ `.btn--orange`.

Trong HTML, ký pháp BEM sẽ được dùng như sau:

```html
<a class="btn btn--big btn--orange" href="http://int3ractive.com">
  <span class="btn__price">$9.99</span>
  <span class="btn__text">Subscribe</span>
</a>
```

<Codepen url="https://codepen.io/css-tricks/embed/226a65c8f7d64615aabd45048d1d3b6d" />

Ấn tượng đầu tiên với bạn có thể là tên class quá xấu và mất thời gian hơn so với việc tạo riêng một class mới cho một kiểu button mới. Tuy nhiên, ký pháp BEM sẽ mang lại nhiều lợi ích mà tôi sẽ phân tích tiếp theo sau đây:

## Tại sao sử dụng ký pháp BEM

Trước tiên, ký pháp BEM giúp người mới tham gia dự án dễ dàng phát hiện ra các trạng thái và các đối tượng con của một component đã được viết sẵn. Điều này giúp tránh cho họ phải viết lại những kiểu CSS đã có sẵn và hạn chế việc viết thừa code hoặc trùng kiểu CSS, điều mà rất hay xảy ra trong dự án lớn có nhiều người tham gia.

Thứ hai, chỉ cần đọc HTML, bạn vẫn có thể nhanh chóng nắm được các thành phần phụ thuộc lẫn nhau. Trong ví dụ trên, bạn dễ dàng nhìn thấy `.btn__price` phụ thuộc vào `.btn` mặc dù bạn chưa biết vai trò cụ thể của nó ngay lập tức.

Thứ ba, với ký pháp BEM, mọi định nghĩa chỉ có một cấp class và không lồng cấp. Điều này giúp cho độ ưu tiên (specificity) chung của hệ thống CSS thấp. Đây là một lợi thế vì sau này bạn không phải "chiến đấu" với specificity của những thuộc tính đã có sẵn (VD: siêu lồng cấp `.a .b .c .d .e {...}`) cũng như vận dụng những kỹ thuật không hay để thay thế được style (chẳng hạn `!important` hay inline CSS).

Quy luật thác nước cascading của CSS là con dao hai lưỡi: nó giúp dễ dàng định nghĩa những thuộc tính và kiểu chung trên những selector tổng quát mà không cần phải khai báo lặp lại trên từng phần tử, nhưng nếu không nắm được tầm ảnh hưởng, lập trình viên CSS rất dễ gây ra những tác động phụ đến các đối tượng không liên quan khi chỉnh sửa trên những class có sẵn hoặc thậm chí viết mới. Với ký pháp BEM, lập trình viên sẽ tự tin hơn khi bắt tay chỉnh sửa hoặc viết thêm style vì đã biết rõ tầm ảnh hưởng của selector mà mình đang viết ra.

Tóm lại, ký pháp BEM, nếu áp dụng triệt để, sẽ giúp cải thiện sự phối hợp giữa các thành viên trong nhóm. Ngoài ra, nó buộc người viết CSS phải đầu tư suy nghĩ về việc xây dựng những component độc lập và tái sử dụng được (phù hợp với tiêu chí của [OOCSS](https://github.com/stubbornella/oocss/wiki)).

## Sử dụng BEM với SASS

Với phiên bản SASS mới nhất hiện nay, việc viết theo ký pháp BEM trong SCSS dễ dàng và thuận tiện hơn bao giờ hết.

Bạn vẫn sẽ sử dụng cách viết lồng để cô lập khối component và kết hợp với biểu tượng _parent_ `&` của SASS để đặt tên cho Element và Modifier mà không phải đánh lại tên của Block. VD:

```scss
.block {
  &__element {
  }

  &--mod {
  }
}
```

Mặc dù viết lồng cấp, khi được biên dịch thành CSS, chúng vẫn được trải phẳng thành một cấp class theo đúng tinh thần của BEM:

```css
.block {
}

.block__element {
}

.block--mod {
}
```

Nếu bạn sử dụng LibSass (nhanh hơn rất nhiều lần bản gốc Ruby) để biên dịch SASS, thì hãy đảm bảo các công cụ wrapper được cập nhật các phiên bản tương đương hoặc mới hơn như sau: node-sass [3.4.0](https://github.com/sass/node-sass/releases/tag/v3.4.0), gulp-sass [2.1.0](https://github.com/dlmanning/gulp-sass/releases/tag/v2.1.0) (nếu sử dụng [GulpJS](https://github.com/gulpjs/gulp)) và grunt-sass [1.1.0](https://github.com/sindresorhus/grunt-sass/releases/tag/v1.1.0) (nếu sử dụng [GruntJS](https://github.com/gruntjs/grunt))

Thế còn LESS? Vì tôi không sử dụng LESS nên sẽ không đề cập ở đây. Bạn có thể giúp bổ sung hướng dẫn cho LESS nếu nó có cú pháp trợ giúp tương đương.

## Các ý kiến không đồng tình

Vẫn có một số ý kiến hoài nghi và không đồng tình với phương pháp đặt tên này.

### Tên class quá xấu

Đồng ý với bạn rằng BEM trông kỳ quặc, tuy nhiên khả năng mà nó đem lại vô cùng lớn và sẽ hoàn toàn xoá mờ hạn chế về mặt "ngoại hình" của nó.

Ngoài ra BEM đòi hỏi phải gõ nhiều chữ hơn và chiếm nhiều byte ký tự hơn, tuy nhiên với việc sử dụng SASS như trên và việc gzip file đã trở thành tiêu chuẩn như hiện nay, những điều đó không còn là vấn đề so với lợi ích mà BEM mang lại.

### Descendant selector vẫn giải quyết được vấn đề như trước giờ

Có một [chỉ trích](https://twitter.com/samuelfine/status/575645771334291456) dành cho BEM thế này: Thay vì viết

```css
.site-search {
}
.site-search__field {
}
.site-search--full {
}
```

Họ đặt vấn đề rằng tại sao không viết như thế này:

```css
.site-search {
}
.site-search input {
}
.site-search.full {
}
```

Rõ ràng cả hai cách viết đều có thể giúp hiện thực được component cụ thể này và cách thứ hai có vẻ "gọn gàng" hơn. Tuy nhiên khi CSS của toàn bộ dự án trở nên lớn và phức tạp hơn, thì rất khó tránh khỏi các kiểu được định nghĩa chồng chéo lên nhau ngoài tầm kiểm soát.

Thử tưởng tượng `.site-search` cũng nằm trong một container tên `.main` và những `input` bên trong `.main` cần được style với `.main input`. Như vậy, `input` bên trong `.site-search` sẽ bị điều chỉnh một cách không mong muốn.

Tương tự, nếu như `.full` trong ví dụ trên hoặc một tên phổ biến như `.label` được dùng như modifier, thì sẽ có rủi ro (rất cao) là một ngày nào đó một lập trình viên khác định nghĩa một class global trùng tên và sẽ làm hỏng style của element kia.

Ngoài ra, khi bạn đọc trong ngữ cảnh HTML, bạn sẽ khó thấy được quan hệ ràng buộc giữa `input` và `.full` với block `.site-search`.

### "Tôi đơn giản là không thích ký pháp này"

Một số người khi nhìn thấy cách đặt tên BEM đã ngay lập tức bác bỏ nó. Họ không thích BEM, đó là quyền của họ, tuy nhiên sẽ là vô lý nếu phản bác việc cần có một số quy tắc đặt tên để dễ dàng nắm bắt và quản lý CSS trong dự án trung và lớn.

Hơn nữa, bạn hoàn toàn có thể nghĩ ra cho mình một cách đặt tên khác cho hợp sở thích, nhưng vẫn dựa trên nguyên tắc của BEM đã đề ra. Là kết quả đúc kết từ những kiến trúc CSS lớn và phức tạp trước đây, đề xuất của BEM không phải vô tình lại có một số điểm chung với các phương pháp quản lý CSS khác như SMACSS hay OOCSS. Lấy ví dụ khái niệm module của SMACSS:

```css
/* Ví dụ một module */
.btn {
}

/* Modifier của một module */
.btn-primary {
}

/* Btn Module với State */
.btn.is-collapsed {
}
```

Trong các phương pháp quản lý CSS vừa kể trên thì chỉ có BEM là làm rõ được mối quan hệ với các thành phần con bên trong.

Tóm lại, mỗi phương pháp đều có ưu nhược điểm. Quan trọng là cả team phải có phương pháp tiếp cận khoa học và áp dụng triệt để thì kiến trúc CSS của cả dự án mới vững và dễ bảo trì.

## Câu hỏi thường gặp:

❓**Hỏi:** Element có modifier hay không?

💬️ **Đáp:** Có. Element có thể có modifier riêng của nó. Ví dụ:

```css
.accordion__copy--open {
  display: block;
}
```

❓**Hỏi:** Có cần phải đặt tên class cho tất cả element (thẻ HTML) trong block hay không?

💬️ **Đáp:** Không cần thiết, chỉ những element cần có style riêng được viết trong CSS. Tuy nhiên cũng không nên lạm dụng những thẻ wrapper (phổ biến nhất là DIV) một cách vô tội vạ và không có chức năng vai trò cụ thể nào. Như vậy việc đặt tên element con cũng khiến bạn phải suy nghĩ một tag nào đó có thật sự cần thiết thêm vào trong block hay không.

❓**Hỏi:** Bên trong element con `foo` có một tag đóng vai trò một element con `bar` khác của block, vậy việc đặt tên class cho element `bar` này như thế nào? Có nên đặt là `.block__foo__bar`?

💬️ **Đáp:** Vẫn đặt bằng tên block và hai gạch dưới rồi đến tên element `.block__bar`, không chen giữa bằng `foo__`. Nói tóm lại, tên của element chỉ cần thể hiện quan hệ phụ thuộc với block, không cần phải chỉ rõ sự lồng bên trong nhau của các element con. (Xem thêm ví dụ trong câu hỏi tiếp theo)

❓**Hỏi:** Một thẻ HTML có thể là element của 2 block khác nhau không?

💬️ **Đáp:** Hoàn toàn có thể. Hãy xem ví dụ sau:

```html
<a class="btn btn--big btn--orange" href="http://int3ractive.com">
  <span class="btn__price"><i class="icon icon--dollar-sign btn__icon"></i>9.99</span>
  <span class="btn__text">Subscribe</span>
</a>
```

Button có biểu tượng dollar-sign là một block `.icon`. Có thể trong block `.btn`, biểu tượng dollar-sign cần được style riêng, nên cần có một cái tên xác định rõ vai trò và style cho element này là `.btn__icon`. Nếu block `.icon.icon--dollar-sign` được dùng ở một ngữ cảnh khác, thì rõ ràng nó không cần class `.btn__icon` nữa vì tên class đã chỉ rõ sự ràng buộc với block `.btn` và chỉ được thêm vào khi ở bên trong nó.

❓**Hỏi:** Một element con có thể đóng vai trò là block của riêng nó không? Có thể xây dựng chuỗi component phụ thuộc nhau như `.a__b__c` không?

💬️ **Đáp:** Câu hỏi này thật sự ngoài tầm hiểu biết và kinh nghiệm của tôi. Có thể có những hoàn cảnh đặt biệt như vậy. Tuy nhiên, theo tôi, nếu có cũng không nên quá 2 cấp, tức là element con chỉ đặt đến `.a__b__c` là tối đa. Điều này là để sự phụ thuộc không quá sâu, làm giảm khả năng dùng lại của block (portability) và sự linh hoạt của các đối tượng CSS theo tinh thần OOCSS. Xem ví dụ bên dưới.

```css
/* block list */
.list {
}
/* item là con của list */
.list__item {
}
/* link là con của block list__item, để phân biệt với list__link
hoặc chỉ rõ mối quan hệ phụ thuộc giữa item và link*/
.list__item__link {
}
```

## Sai lầm hay mắc phải khi sử dụng BEM:

Tôi xin hẹn lại về vấn đề này trong một bài viết khác, khi mà bản thân đã ứng dụng nhiều và quan sát được những ví dụ thực tiễn hơn để tổng hợp những sai lầm hay mắc phải do ảnh hưởng từ phương pháp cũ cũng như cách hiểu chưa đúng về phương pháp BEM này.

Xem thêm:

- Bài viết [giới thiệu BEM của CSSWizadry](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/)
- Bài viết [giới thiệu BEM của Smashing Magazine](http://www.smashingmagazine.com/2012/04/a-new-front-end-methodology-bem/)
- [Sử dụng BEM và @extend của SASS](http://webuniverse.io/css-organization-naming-conventions-and-safe-extend-without-preprocessors/)
- Bài viết [5 sai lầm phổ biến với BEM](https://medium.com/fed-or-dead/battling-bem-5-common-problems-and-how-to-avoid-them-5bbd23dee319)
]]></description>
            <link>https://hungvn.com/blog/su-dung-ky-phap-bem-trong-css</link>
            <guid isPermaLink="true">https://hungvn.com/blog/su-dung-ky-phap-bem-trong-css</guid>
            <pubDate>Sun, 20 May 2018 16:05:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giới thiệu Progressive Web App]]></title>
            <description><![CDATA[
**P**rogressive Web App (PWA) là một dạng ứng dụng web (web app) mới đang thu hút rất nhiều sự quan tâm từ các nhà phát triển web khắp thế giới đặc biệt là các doanh nghiệp hoạt động trực tuyến, tuy nhiên nó vẫn còn khá mới mẻ tại Việt Nam.

Đã có nhiều bài viết liên quan đến PWA dành cho [lập](https://addyosmani.com/blog/getting-started-with-progressive-web-apps/) [trình](https://infrequently.org/2015/06/progressive-apps-escaping-tabs-without-losing-our-soul/) [viên](https://www.smashingmagazine.com/2016/08/a-beginners-guide-to-progressive-web-apps/), cho nên trong bài viết này tôi sẽ cố gắng giải thích PWA để người dùng Web phổ thông vẫn có thể hiểu.

## Progressive Web App là gì?

**PWA là ứng dụng web được viết để tận dụng những tính năng mới nhất của trình duyệt Web trên máy tính để bàn (desktop) lẫn điện thoại thông minh, nhưng đồng thời vẫn chạy được trên những trình duyệt và thiết bị cũ hơn. PWA lấy phương pháp [Cải Tiến Tăng Dần (Progressive Enhancement)](https://www.youtube.com/watch?v=5oUSzo1oRv0) làm cốt lõi (nên mới có chữ Progressive).**

Đối với những trình duyệt và thiết bị cũ, PWA hoạt động như một mobile website thông thường. Nhưng với những trình duyệt trên thiết bị di động mới nhất, PWA hoạt động như một _mobile app_[^1] thực thụ.

Những tác giả của khái niệm PWA (đến từ nhóm phát triển trình duyệt Chrome) đã đưa ra những đặc tính cần có của một PWA như sau:

- **Progressive** - Chạy được trên _mọi_ (nên hiểu: tuyệt đại đa số) thiết bị, do được phát triển với phương pháp Cải Tiến Tăng Dần.
- **Responsive** - Có thiết kế _giao diện tùy ứng_ (responsive design), hiển thị và sử dụng được trên mobile, tablet, laptop hay bất kỳ cỡ màn hình nào trong tương lai.
- **Connectivity independent** - PWA vẫn có thể hoạt động tốt với điều kiện kết nối mạng chập chờn hoặc mất hẳn (offline).
- **App-like** - Có giao diện và trải nghiệm như mobile app thực thụ.
- **Fresh** - Dù nó hoạt động như mobile app, nhưng tính năng và giao diện luôn được cập nhật tức thời nhờ nền tảng Web (không cần người dùng update từ Apple App Store hay Google Play - gọi chung là app store).
- **Safe** - PWA phải được tải thông qua giao thức TLS (hay nôm na là HTTPS), để đảm bảo việc trao đổi dữ liệu không bị bên thứ ba can thiệp.
- **Discoverable** - Thông qua file khai báo chuẩn (được thống nhất bởi tổ chức W3C), mà các PWA dễ dàng được các cỗ máy tìm kiếm đánh dấu và thông báo cho người dùng.
- **Re-engageable** - PWA cho phép việc tái tiếp cận người dùng dễ dàng hơn nhờ những tính năng đặc biệt như là push notification (thông báo chủ động).
- **Installable** - PWA cho phép người dùng dễ dàng lưu lại web app trên điện thoại (thường là trên màn hình home screen) mà không cần phải vào app store
- **Linkable** - Dễ dàng share app chỉ với đường link và không cần người nhận phải cài đặt phức tạp chỉ để xem được nội dung bạn muốn share.

## Những điểm khác biệt của Progressive Web App?

Trước tiên cần hiểu rằng, sự tiến hóa của mobile web app cần sự hợp tác của rất nhiều bên liên quan trong đó có các nhà phát triển trình duyệt, hệ điều hành di động, và cả những chuyên gia về ngôn ngữ lập trình cho Web. Sự tiến hóa của mobile web thường đi cùng với sự phát triển và chuẩn hóa của nền tảng Web do tổ chức **W3C**[^2] chịu trách nhiệm.

Khi tôi tư vấn và phát triển app cho khách hàng, rất nhiều lần doanh nghiệp từ chối lựa chọn giải pháp web app hoặc hybrid app với lý do chính là _"HTML5 không nhanh bằng native"_. Tuy nhiên điều này không còn đúng tại thời điểm hiện tại.

Nhờ những cải tiến của phần cứng thiết bị, hệ điều hành di động, trình duyệt, và nhất là đặc tả Web trong vài năm gần đây mà web app đã thêm những khả năng không thua kém native app như:

- Giao diện tương tác mượt mà hơn, đặt biệt là hỗ trợ đồ họa 3D, animation từ phần cứng (hardware accelerated)
- Khả năng chơi video, audio thông qua trình duyệt mobile đã hoàn thiện và định dạng gần như đã thống nhất.
- Bàn phím ảo thích ứng với trường nhập web form khác nhau: email, URL, telephone...
- Có khả năng truy xuất các sensor và bộ phận đa phương tiện của thiết bị: định vị GPS, con quay hồi chuyển, trạng thái pin, network, camera, microphone...
- Cơ sở dữ liệu (CSDL) tại trình duyệt cho phép tìm kiếm và truy cập nhanh lượng dữ liệu lớn và cho phép người dùng trở lại trang web app nhanh hơn.
- Đặc tả mới về CSS cho phép designer và front end developer tạo giao diện tùy ứng (responsive design) và giao diện giống app dễ dàng hơn.

Dù vậy, web app vẫn còn một số hạn chế so với native app. Chúng ta hãy xem PWA đã được bổ sung những khả năng gì để có thể xóa dần khoảng cách giữa web và native:

## Kết luận

Được giới thiệu chính thức [từ 2015](https://en.wikipedia.org/wiki/Progressive_Web_Apps), PWA đã trải qua thời gian thử nghiệm và trưởng thành đủ lâu để giờ đây chúng ta có thể khẳng định PWA chính là tương lai của Web và Web App.

PWA đóng góp thêm một giải pháp ứng dụng di động nhiều hứa hẹn, giải phóng doanh nghiệp khỏi sự lệ thuộc vào app store, những hạn chế của native app. Và nếu được thiết kế hợp lý, PWA sẽ là giải pháp hợp nhất cho "mọi nền tảng" từ desktop đến mobile.

---

#### Ghi chú:

[^1]: Xin tóm tắt lại một số thuật ngữ về **"app"** trên thiết bị di động:

- Mobile app hoặc native app: (ở Việt Nam thường gọi tắt là "app") là ứng dụng được cài đặt từ app store, được viết bằng ngôn ngữ lập trình dành riêng cho từng hệ điều hành di động khác nhau.
- (Mobile) web app: là website chạy trên trình duyệt của smart phone nhưng có trải nghiệm giống app và thường trao đổi nhiều dữ liệu giữa người dùng và website.
- Hybrid app: là ứng dụng được cài đặt từ app store, tuy nhiên được viết bằng cùng ngôn ngữ lập trình với web app. Dù hybrid app có thể cài được trên nhiều HĐH khác nhau nhưng nó chỉ cần được viết cùng một bộ mã nguồn với một ít điều chỉnh riêng cho mỗi loại HĐH mà nó hỗ trợ.

[^2]: Tổ chức World Wide Web Consortium có trách nhiệm chuẩn hóa các đặc tả về Web và khuyến khích các trình duyệt khác nhau phải tuân theo để các website hoạt động một cách đồng nhất bất kể trình duyệt dùng để hiển thị.

[^3]: URL là đường link đến một trang web bất kỳ

[^4]: Các trình duyệt phổ biến nhất bao gồm: Chrome, Firefox, Safari, MS Edge, Opera, Samsung Internet, UC Browser. Tại Việt Nam, trình duyệt phổ biến thứ 2 sau Chrome là CocCoc. Tuy nhiên CocCoc cũng là một trình duyệt biến thể từ mã nguồn mở của Chrome nên những tính năng của PWA cũng sẽ được hỗ trợ.

[^5]: Người dùng sẽ vẫn nhận được push notification cho dù họ không lưu app về home screen chỉ cần họ đã bấm đồng ý nhận push notification. Việc yêu cầu gửi push notification cần thận trọng và chỉ thực hiện khi người dùng đã thể hiện sự quan tâm đến dịch vụ của bạn. (Nếu không khả năng người dùng từ chối nhận push notification là rất cao)
]]></description>
            <link>https://hungvn.com/blog/gioi-thieu-progressive-web-app</link>
            <guid isPermaLink="true">https://hungvn.com/blog/gioi-thieu-progressive-web-app</guid>
            <pubDate>Fri, 18 May 2018 07:30:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giới thiệu về redux saga]]></title>
            <description><![CDATA[
# Redux-Saga là gì?

Redux-Saga là một thư viện redux middleware, giúp quản lý những side effect trong ứng dụng redux trở nên đơn giản hơn. Bằng việc sử dụng tối đa tính năng [Generators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/function*) `(function*)` của ES6, nó cho phép ta viết async code nhìn giống như là synchronos.

Saga không chỉ tồn tại trong thế giới javascript, nó còn được coi là 1 pattern. Bạn có thể xem qua về saga pattern bằng clip này: [https://youtu.be/xDuwrtwYHu8](https://youtu.be/xDuwrtwYHu8)

Một cách nhìn nhanh chóng thì Saga pattern là cách để quản lý những long transaction với những side effect hoặc các nguy cơ tiềm ẩn. Với mỗi transaction thành công, chúng ta đều cần có counter-transaction để revert transaction đó về trạng thái ban đầu nếu gặp trục trặc. Tham khảo thêm về saga pattern với bài viết của Roman Liutikov : [Confusion about Saga pattern](https://medium.com/@roman01la/confusion-about-saga-pattern-bbaac56e622)

# Side effect là gì??

Ta đã biết tất cả những xử lý ở REDUCER đều phải là synchronous và pure tức chỉ là xử lý đồng bộ. Nhưng trong ứng dụng thực tế thì cần nhiều hơn vậy ví dụ như asynchronous (thực hiện một số việc như gọi một hàm AJAX để fetch dữ liệu về nhưng cần đợi kết quả chứ kết quả không trả về ngay được) hoặc là impure (thực hiện lưu, đọc dữ liệu ra bên ngoài như lưu dữ liệu ra ổ cứng hay đọc cookie từ trình duyệt… đều cần đợi kết quả). Những việc như thế trong lập trình hàm gọi nó là side effects.

# Generator function là gì??

Khác với function bình thường là thực thi và trả về kết quả, thì Generator function có thể thực thi, tạm dừng trả về kết quả và thực thi bằng tiếp. Từ khóa để làm được việc đấy là “YIELD”. Generator được đưa ra cách đây mấy chục năm nhưng đến ES2015 mới được bổ sung, các ngôn ngữ khác đã được bổ sung tính năng này như C#, PHP, Ruby, C++, R…

# Redux-Saga hoạt động như thế nào??

Đối với logic của saga, ta cung cấp một hàm cho saga, chính hàm này là hàm đứng ra xem xét các action trước khi vào store, nếu là action quan tâm thì nó sẽ thực thi hàm sẽ được thực thi, nếu bạn biết khái niệm hook thì hàm cung cấp cho saga chính là hàm hook. Điều đặc biệt của hàm hook này nó là một generator function, trong generator function này có yield và mỗi khi yield ta sẽ trả về một plain object. Object trả về đó được gọi Effect object. effect object này đơn giản chỉ là một object bình thường nhưng chứa thông tin đặc biệt dùng để chỉ dẫn middleware của Redux thực thi các hoạt động khác ví dụ như gọi một hàm async khác hay put một action tới store. Để tạo ra effect object đề cập ở trên thì ta gọi hàm từ thư viện của saga là redux-saga/effects.

![](https://i.stack.imgur.com/iCi6Y.png)

# Tại sao tôi phải sử dụng Saga??

Khi bắt đầu tìm tòi về redux, bạn hay tìm thấy các bài hướng dẫn sử dụng [redux-thunk](https://github.com/gaearon/redux-thunk) hoặc [redux-saga](https://github.com/redux-saga/redux-saga) để quản lý các async action. Vậy tại sao bạn lại được khuyên sử dụng redux-saga ?

Trích dẫn trong document của redux-saga:

> Contrary to redux thunk, you don’t end up in callback hell, you can test your asynchronous flows easily and your actions stay pure. \_Tạm dịch: trái với redux thunk, bạn không cần phải phát dồ lên với các callback trong mỗi action, đến với saga đi, bạn có thể test các async action với một quy trình dễ dàng mà không làm hư các action đó !

#### So sánh saga và thunk:

1.  redux-thunk

    ```javascript
    import {
      API_BUTTON_CLICK,
      API_BUTTON_CLICK_SUCCESS,
      API_BUTTON_CLICK_ERROR,
    } from './actions/consts';
    import { getDataFromAPI } from './api';

    const getDataStarted = () => ({ type: API_BUTTON_CLICK });
    const getDataSuccess = data => ({ type: API_BUTTON_CLICK_SUCCESS, payload: data })
    const getDataError = message => ({ type: API_BUTTON_CLICK_ERROR. payload: message });

    const getDataFromAPI = () => {
      return dispatch => {
        dispatch(getDataStarted());

        getDataFromAPI()
          .then(data => {
            dispatch(getUserSuccess(data));
          }).fail(err => {
            dispatch(getDataError(err.message));
          })
      };
    };
    ```

    Ở đây ta có một action creator getDataFromAPI() bắt đầu async progress như sau:
    - Đầu tiên bắn ra action cho phép store biết rằng chuẩn bị 1 API request ( dispatch(getDataStarted())
    - Tiếp theo thực hiện API request trả về một Promise
    - Cuối cùng bắn ra success action nếu request thành công hoặc error action nếu có lỗi

2.  redux-saga

    ```javascript
    import { call, put, takeEvery } from "redux-saga/effects";

    import {
      API_BUTTON_CLICK,
      API_BUTTON_CLICK_SUCCESS,
      API_BUTTON_CLICK_ERROR,
    } from "./actions/consts";
    import { getDataFromAPI } from "./api";

    export function* apiSideEffect(action) {
      try {
        const data = yield call(getDataFromAPI);
        yield put({ type: API_BUTTON_CLICK_SUCCESS, payload: data });
      } catch (e) {
        yield put({ type: API_BUTTON_CLICK_ERROR, payload: e.message });
      }
    }

    // the 'watcher' - on every 'API_BUTTON_CLICK' action, run our side effect
    export function* apiSaga() {
      yield takeEvery(API_BUTTON_CLICK, apiSideEffect);
    }
    ```

    Cùng một process, nhưng cách implement khác nhau hoàn toàn.
    - put thay cho dispatch
    - function cuối (apiSaga()) giúp theo dõi tổng thể toàn bộ các action (ở đây có API_BUTTON_CLICK)
    - Với cách gọi của redux-saga, chúng ta có thể get data từ bất kì async function nào (promise, ...)

3.  ###### Nhận xét

    Cả 2 cách implement đều dễ đọc, tuy nhiên đối với redux-thunk , bạn phải đối đầu với một tá các promise, các callback nếu có, rất mất thời gian cho người maintain đọc và tìm code. Với redux-saga , đơn giản bạn chỉ cần track theo try/catch block để theo dõi dòng code, bên cạnh đó còn có hàm giúp bạn track các action một cách dễ dàng.

# Kết luận

Ở bài viết này mình đề cập đến 2 điểm nhấn chính của redux-saga là giữ cho action pure synchronos theo chuẩn redux và loại bỏ hoàn toàn callback theo javascript truyền thống. Bài viết tiếp theo mình sẽ đề cập nốt key point cuối cùng của saga là **easy to test**.
]]></description>
            <link>https://hungvn.com/blog/gioi-thieu-ve-redux-saga</link>
            <guid isPermaLink="true">https://hungvn.com/blog/gioi-thieu-ve-redux-saga</guid>
            <pubDate>Mon, 30 Apr 2018 18:37:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Thinking in React]]></title>
            <description><![CDATA[
> React is, in our opinion, the premier way to build big, fast Web apps with JavaScript. It has scaled very well for us at Facebook and Instagram.

Một trong những phần quan trọng nhất của React là cách nó tạo ra cách nghĩ của bạn về các ứng dụng mà bạn xây dựng. Trong tài liệu này, chúng tôi sẽ hướng dẫn bạn cách để xây dựng một ứng dụng tìm kiếm sản phẩm trong table với React.

# Bắt đầu

Giả dụ bạn đã có sẵn một JSON API và giao diện đã sẵn sàng gọi đến nó. Cụ thể như ảnh sau:

![](https://reactjs.org/static/thinking-in-react-mock-1071fbcc9eed01fddc115b41e193ec11-4dd91.png)

Dữ liệu trả về có dạng như sau:

```javascript
[
  {
    category: "Sporting Goods",
    price: "$49.99",
    stocked: true,
    name: "Football",
  },
  {
    category: "Sporting Goods",
    price: "$9.99",
    stocked: true,
    name: "Baseball",
  },
  {
    category: "Sporting Goods",
    price: "$29.99",
    stocked: false,
    name: "Basketball",
  },
  {
    category: "Electronics",
    price: "$99.99",
    stocked: true,
    name: "iPod Touch",
  },
  {
    category: "Electronics",
    price: "$399.99",
    stocked: false,
    name: "iPhone 5",
  },
  { category: "Electronics", price: "$199.99", stocked: true, name: "Nexus 7" },
];
```

## Bước 1: Chia UI thành component theo bậc

Việc đầu tiên bạn sẽ phải vẽ các hộp xung quanh mỗi component ( và subcomponent ) và đặt tên cho chúng. Nhưng bạn phân vân không biết khi nào nên tạo ra component? Đối với component, một kĩ thuật được sử dụng rộng rãi để design component là sử dụng [nguyên tắc đơn nhiệm](https://en.wikipedia.org/wiki/Single_responsibility_principle). Khi các component được sinh ra quá nhiều, bạn hãy tách chúng ra thành nhiều subcomponent. Đối với việc thuường xuyên hiển thị dữ liệu JSON, bạn nên đảm bảo về tính đúng đắn của model, liệu rằng nó sẽ được map chính xác với UI ( các component ) của bạn? Bởi vì UI và các model luôn phải dính liền với cấu trúc của thông tin, có nghĩa là công việc phân chia UI sang component là không đáng kể. Cứ chia ra thành các component và hiển thị chính xác từng mẩu dữ liệu của bạn là ổn.

![](https://reactjs.org/static/thinking-in-react-components-eb8bda25806a89ebdc838813bdfa3601-82965.png)

Đối với dữ liệu trong ảnh, bạn sẽ nghĩ đến 5 component tương ứng với mỗi màu phải không? Sau đây là chi tiết cho từng component đó:

1.  **FilterableProductTable (cam)**: chứa toàn bộ ví dụ
2.  **SearchBar (xanh)**: nhận dữ liệu từ người dùng
3.  **ProductTable (xanh lá cây)**: hiển thị và lọc dữ liệu dựa trên user input
4.  **ProductCategoryRow (lam)**: hiển thị tiêu đề cho mỗi category
5.  **ProductRow (đỏ)**: mỗi hàng là 1 sản phẩm

Nếu bạn nhìn vào ProductTable , bạn sẽ thấy có header (bao gồm nhãn "Name" và "Price") không phải là chính component của nó. Đây là vấn đề của việc tinh chỉnh. Ví dụ, chúng ta để phần header thuộc component ProductTable vì nó là một phần của việc render ra dữ liệu, đó là trách nhiệm của ProductTable. Tuy nhiên, nếu header này khi được sử dụng một cách phức tạp (như là tương tác với sắp xếp), nó sẽ phải tạo thêm một component riêng cho header gọi là ProductTableHeader chẳng hạn. Tóm lại, bạn nên phân chia cấu trúc của component và các subcomponent như sau:

- FilterableProductTable
  - SearchBar
  - ProductTable
    - ProductCategoryRow
    - ProductRow

## Bước 2: Xác định mức tối thiểu (nhưng hoàn chỉnh)

Để UI của bạn tương tác tốt, bạn cần xác định các thay đổi đến dữ liệu thuộc tầng dưới (underlying data model) . Hãy sử dụng **state** của React.

Đầu tiên bạn nên nghĩ đến việc tối giản các mutable state. Chìa khóa thành công ở đây là **DRY:** _**Don't Repeat Yourself**_ . Ví dụ với ứng dụng TODO, bạn chỉ cần giữ mảng các TODO item, không cần đến các state khác như để đếm số lượng. Thay vào đó, khi bạn muốn đếm số lượng của TODO item, đơn giản là lấy ra length của TODO item array.

Cụ thể với dữ liệu mẫu trong bài viết này, chúng ta có:

- Nguyên mẫu danh sách sản phẩm
- Text tìm kiếm mà user nhập vào
- Value của checkbox
- Danh sách đã lọc sản phẩm

Hãy suy nghĩ về việc bạn nên để cái nào là state, trong thời gian suy nghĩ, hãy đọc các câu hỏi dưới về luồng data:

1.  Có thể pass từ parent component thông qua props không? Nếu có, state là không cần thiết.
2.  Nó có giữ nguyên trạng thái dữ liệu suốt không? Nếu có, state không thể sử dụng được.
3.  Bạn có đoán được data dựa vào bất kì state hay props nào trong component không? Nếu có, chỗ này càng không phải chỗ cho state.

Danh sách sản phẩm nguyên bản được pass thông qua props. Text tìm kiếm và checkbox dường như sẽ thích hợp với state vì nó có thể được thay đổi bất kì lúc nào bởi người dùng. Vậy cuối cùng, danh sách lọc sản phẩm cũng không thể nào là state bởi vì chúng có thể được tính toán thông qua list sản phẩm ban đầu dựa vào search text và checkbox.

Tóm lại, bạn nên sử dụng state cho:

- Search text mà user nhập vào
- Giá trị của checkbox khi user sử dụng

## Bước 4: Xác định nơi sinh sống của state

Hãy nhớ rằng, React là luồng dữ liệu một chiều, phụ thuộc theo luồng của các cấp component. Bạn không thể đoán ngay được component này sẽ có những state gì. **Đây là việc chiếm nhiều thời gian và công sức nhất dành cho người mới tìm hiểu về react**, hãy nhớ: đừng vội khẳng định state A thuộc component A. Để hình dung ra một cách rõ ràng, hãy theo các bước sau:

- Phân loại mỗi component sẽ render ra những gì dựa vào state đó.
- Tìm thử trong component cha
- Nếu component cha không có, tìm tiếp ở component cao hơn component cha đó
- Nếu bạn không tìm ra được component đang giữ state, thử tạo một conponent mới để giữ state đó và thêm nó ở đâu đó trong cấp thư mục cao hơn thư mục chứa component cha.

Ví dụ cụ thể:

- ProductTable cần filter sản phẩm dựa vào state và SearchBar cần phải hiển thị text được nhập và state của checkbox.
- Component cha sẽ là FilterableProductTable
- Tất nhiên theo lẽ tự nhiên, search text và giá trị của checkbox sẽ được lưu ở trong FilterableProductTable.

## Bước 5: Thêm luồng dữ liệu

...

Và đây là kết quả

<Codepen url="//codepen.io/gaearon/embed/LzWZvb" width="100%" height="600px" />

## Kết

Hy vọng rằng, bài viết này cho bạn ý tưởng làm thế nào để suy nghĩ về việc xây dựng các component với React. Mặc dù có thể khiến bạn gõ nhiều code hơn, hãy nhớ rằng code được đọc nhiều hơn nó được viết. Khi bạn bắt đầu xây dựng các thư viện component lớn, bạn sẽ đánh giá cao sự rõ ràng và tính mô đun, và với việc tái sử dụng code, các dòng code của bạn sẽ bắt đầu co lại.
]]></description>
            <link>https://hungvn.com/blog/thinking-in-react</link>
            <guid isPermaLink="true">https://hungvn.com/blog/thinking-in-react</guid>
            <pubDate>Mon, 30 Apr 2018 16:47:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tổng hợp các cheat sheets tốt nhất của front-end]]></title>
            <description><![CDATA[
Chúng ta không thể nhớ thuộc lòng tất cả các API. Đây là lúc chúng ta cần các trang cheat sheets này! Dưới đây là các bản cheat sheets tốt nhất mà tôi đã thu thập được.

### [Javascript ES2015 features](https://devhints.io/es6)

![https://devhints.io/es6](https://cdn-images-1.medium.com/max/2000/1*l90SMm_aR9UD8m9QDu3kKA.png)

### [Javascript](http://overapi.com/javascript)

![http://overapi.com/javascript](https://cdn-images-1.medium.com/max/2000/1*sqkshvsmr7hN4Ab2A7GJzg.png)

### [Javascript Regular expression](https://www.debuggex.com/cheatsheet/regex/javascript)

![https://www.debuggex.com/cheatsheet/regex/javascript](https://cdn-images-1.medium.com/max/2000/1*jHRyyzwj9z11ouDkY9dK9Q.png)

### [React](https://devhints.io/react)

![https://devhints.io/react](https://cdn-images-1.medium.com/max/2000/1*VhtpckI6V0tckQa3uM9MbA.png)

### [Redux](https://github.com/linkmesrl/react-journey-2016/blob/master/resources/egghead-redux-cheat-sheet-3-2-1.pdf)

![https://github.com/linkmesrl/react-journey-2016/blob/master/resources/egghead-redux-cheat-sheet-3-2-1.pdf](https://cdn-images-1.medium.com/max/2000/1*KJQ-XK2yK-903OXHCRQpLw.png)

### [Vuejs](https://vuejs-tips.github.io/cheatsheet/)

![https://vuejs-tips.github.io/cheatsheet/](https://cdn-images-1.medium.com/max/2000/1*xKmyDitGEXGg1J9FBpbqHw.png)

### [Vuex](https://vuejs-tips.github.io/vuex-cheatsheet/)

![https://vuejs-tips.github.io/vuex-cheatsheet/](https://cdn-images-1.medium.com/max/2000/1*M-UIS7PPmvh_HuZVTqarzA.png)

### [Angular 4](https://angular.io/guide/cheatsheet)

![https://angular.io/guide/cheatsheet](https://cdn-images-1.medium.com/max/2000/1*tx7-kHpoRsiEyp9ch3yMhw.png)

### [Flexbox](https://yoksel.github.io/flex-cheatsheet/)

![https://yoksel.github.io/flex-cheatsheet/](https://cdn-images-1.medium.com/max/2000/1*q8xJa81twW6J-U_URHOJvQ.png)

### [SCSS](https://devhints.io/sass)

![https://devhints.io/sass](https://cdn-images-1.medium.com/max/2000/1*OlBKGGkX-lYD4Hv_3jzq0A.png)

### [Stylus](https://devhints.io/stylus)

![https://devhints.io/stylus](https://cdn-images-1.medium.com/max/2000/1*KzGNbC0CdMdUQjF_8LWy6g.png)

### [GraphQL](https://raw.githubusercontent.com/sogko/graphql-shorthand-notation-cheat-sheet/master/graphql-shorthand-notation-cheat-sheet.png)

![https://raw.githubusercontent.com/sogko/graphql-shorthand-notation-cheat-sheet/master/graphql-shorthand-notation-cheat-sheet.png](https://cdn-images-1.medium.com/max/2000/1*PBnThNh1zzpCJq_70ExyRA.png)

Missing your favorite cheatsheet? Please let me know in the comments!
]]></description>
            <link>https://hungvn.com/blog/tong-hop-cac-cheat-sheets-tot-nhat-cua-front-end</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tong-hop-cac-cheat-sheets-tot-nhat-cua-front-end</guid>
            <pubDate>Mon, 30 Apr 2018 15:36:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tất cả những gì bạn cần biết về CSS-in-JS]]></title>
            <description><![CDATA[
TL;DR:**Thinking in components — **No longer do you have to maintain bunch of style-sheets. CSS-in-JS abstracts the CSS model to the component level, rather than the document level (modularity).

#### Styled React Component Example

![](https://cdn-images-1.medium.com/max/1600/1*DFwkvCRyz9K0Mbl59r2hMg.png)

---

You probably heard terms like [**CSS-in-JS**](http://cssinjs.org/?v=v9.1.0), [**Styled Components**](https://www.styled-components.com), [**_Radium_**](https://github.com/FormidableLabs/radium), [**Aphrodite**](https://github.com/Khan/aphrodite) and you’re left there hanging **“why is this a thing? — **I’m perfectly happy with **CSS-in-CSS** (**_CSS_ in *.css***).**”**

I’m here to shine some light on why this is a thing and hopefully we will least understand the concept and understand why it’s a thing. With that said — please feel free to use CSS-in-CSS — on no terms are you obligated to use CSS-in-JS. **Whatever works best for you and makes you happy is hands down the best solution, always-always!**

CSS-in-JS is a delicate and controversial topic — I’m advocating having an open mind and weighing if this makes sense to you — ask yourself **“will it improve my workflow?” —\*\***in the end — that’s the only thing that matters — use tools that make you happier and more productive!\*\*

I’ve always felt awkward having to maintain a huge folder of stylesheets. I would like to try different approaches. I’ve seen many people asking if there are new styling ideas. CSS-in-JS is so far the best concept.

Let’s give CSS-in-JS a shot.

![Small-To-Medium size project CSS](https://cdn-images-1.medium.com/max/1600/1*bsbmmLcGl2kSJSuKW-JFqw.png)

---

### What is CSS-in-JS?

> [JSS is a more powerful abstraction](https://medium.com/@oleg008/jss-is-css-d7d41400b635) over CSS. It uses JavaScript as a language to describe styles in a declarative and maintainable way. It is a [high performance](http://cssinjs.org/performance) JS to CSS compiler which works at runtime and server-side. This core library is low level and framework agnostic. It is about 6KB (minified and gzipped) and is extensible via [plugins](http://cssinjs.org/plugins) API. —[ source](http://cssinjs.org/)

Keep in mind [**Inline styles**](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) **and CSS-in-JS are not the same!** They’re different — Quick demonstration time!

### [How Inline Styles Works](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style)

<Gist id="5812bd9006c91b9eb0fe08e3678d88c8" />

In the browser this will get attached to the DOM node like so:

<Gist id="02b07c1daa4816eb2a51eb8d1b494f3e" />

### How CSS-in-JS works

<Gist id="769908d4e065b363258d9ae733febac2" />

In the browser this will gets attached to the DOM like so:

<Gist id="e76c2883a81a11ee16f4b12906572e2a" />

### Difference

See the slight difference? CSS-in-JS attached a `<style>` tag on top of the DOM while inline styles just attached the properties to the DOM node.

**_Why does this matter?_**

**Not all CSS features can be aliased with JavaScript event handlers **, many pseudo selectors (like :disabled, :before, :nth-child) aren’t possible, styling the html and body tags isn’t supported etc.

**With CSS-in-JS**, you have all the power of CSS at your fingertips. Since actual CSS is generated, you can use every media query and pseudo selector you can think of. Some libraries (like jss, styled-components) even add support for neat, non-CSS-native features like nesting!

[**Brilliant article going in depth on how they’re different.**](https://mxstbr.blog/2016/11/inline-styles-vs-css-in-js/)

“Just write the darn CSS in CSS and be done with it.”

Yes — while that’s the case for how it’s been done for a long-long time — **the challenge is modern web is written in components not pages.**

**CSS was never actually made for component based approaches**. CSS-in-JS solves exactly this problem. Shout-out to [Vue](https://vuejs.org/) for solving this problem beautifully even tho Vues styles have no access to components state.

![Here’s Bob Ross painting rocks to cool down the tension 😄](https://cdn-images-1.medium.com/max/1600/1*jk3SeXoIgOfymKO-8JO23A.gif)

### What are the benefits of using CSS-in-JS?

- **Thinking in components — **No longer do you have to maintain bunch of style-sheets. CSS-in-JS abstracts the CSS model to the component level, rather than the document level (modularity).
- CSS-in-JS **leverages the full power of the JavaScript ecosystem** to _enhance_ CSS.
- “**True rules isolation**” — Scoped selectors are not enough. CSS has properties which are inherited automatically from the parent element, if not explicitly defined. Thanks to [jss-isolate](http://cssinjs.org/jss-isolate) plugin, JSS rules will not inherit properties.
- **Scoped selectors **— CSS has just one global namespace. It is impossible to avoid selector collisions in non-trivial applications. Naming conventions like BEM might help within one project, but will not when integrating third-party code. JSS generates unique class names by default when it compiles JSON representation to CSS.
- **Vendor Prefixing** —The CSS rules are automatically vendor prefixed, so you don’t have to think about it.
- **Code sharing **— Easily share constants and functions between JS and CSS.
- **Only the styles which are currently** in use on your screen are also in the DOM ([react-jss](https://github.com/cssinjs/react-jss)).
- [**Dead code elimination**](https://en.wikipedia.org/wiki/Dead_code_elimination)
- **Unit tests** for CSS!

### What are the drawbacks of using CSS-in-JS?

- **Learning curve**.
- **New dependencies.**
- **Harder for newer teammates to adapt to the code-base**. People who are new to front-end have to learn “more” things.
- **Challenging** the status quo. (not necessarily a con)

The pros out-weight the cons heavily — let’s give CSS-in-JS a shot! **Nothing to lose!**

---

### Most popular CSS-in-JS libaries

_Will provide a quick hello world example for all the popular CSS-in-JS libraries— help yourself to choose which one you like the most based on the syntax._

![NPM trends](https://cdn-images-1.medium.com/max/2000/1*xXIXJeI3l6_k-rXg6cqNjw.png)

#### [Styled Components](https://www.styled-components.com/)

![](https://cdn-images-1.medium.com/max/1600/1*QvSrt0RgwuOKYlLHLjkDQw.png)

<Gist id="5888c4756651dfef1e1015b822d09b27" />

### [JSS-React](https://github.com/cssinjs/react-jss)

![](https://cdn-images-1.medium.com/max/1600/1*z7kPKLW6meQuC5sznIYnkQ.png)

<Gist id="c90a6455e9dd7dce7b579b06d2e61413" />

### [glamorous](https://glamorous.rocks/)

![](https://cdn-images-1.medium.com/max/1600/1*tWuxJKAhaod4WNsm3MkMgQ.png)

<Gist id="47c1dc52980ed0197db2ceb5ebbb9ac0" />

#### [Radium](http://formidable.com/open-source/radium/) (caveat: uses inline styles)

![](https://cdn-images-1.medium.com/max/1600/1*UsS6OxCfH6r7JLWx-wNeIQ.png)

<Gist id="14b38638841f6c0539127ad52358d099" />

Note: Radium uses [decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841)!

#### [Aphrodite](https://github.com/Khan/aphrodite)

<Gist id="f7d862549b680f766e68751e0f3f77d1" />

#### [Stylotron](https://github.com/rtsao/styletron)

![](https://cdn-images-1.medium.com/max/1600/1*a0c0iulx7pZFScn0fsAn0w.png)

<Gist id="9919c99b28ca4a063a3245efc1e4dddd" />

These are really simple examples which demonstrate the core functionality. All of the libraries have much more functionality included — for example, **theming**, **dynamic props**, **server side rendering** and much more!

[Excellent post](https://medium.com/object-partners/css-in-js-benefits-drawback-and-tooling-80286b03f9aa) going in depth about all of the features CSS-in-JS enables.

[**Here’s the full list — go and give all the libraries a quick try!**](https://github.com/tuchk4/awesome-css-in-js)

Hate it or love it — **CSS-in-JS deserves a chance!**

#### [Convinced CSS-in-JS is not for me? There’s another option — CSS Modules!](https://glenmaddern.com/articles/css-modules)

Thanks for reading!
]]></description>
            <link>https://hungvn.com/blog/tat-ca-nhung-gi-ban-can-biet-ve-css-in-js</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tat-ca-nhung-gi-ban-can-biet-ve-css-in-js</guid>
            <pubDate>Mon, 30 Apr 2018 15:19:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Hiểu sâu về React Higher Order Components]]></title>
            <description><![CDATA[
# Giới thiệu

Chắc hẳn rất nhiều người trong chúng ta đã và đang sử dụng React, và tất nhiên là kèm theo hằng tá thư viện đi kèm hỗ trợ nó (lol) Và chắc hẳn bạn đã từng gặp thư viện yêu cầu bạn viết một đoạn code kiểu này để thư viện có thể hoạt động:

```javascript
import { connect } from 'react-redux';
...
export default connect(mapStateToProps, mapDispatchToProps)(Component);
// Kết nối Component với Store của Redux bằng thư viện react-redux
```

Hoặc là thế này

```javascript
var Radium = require('radium');
@Radium
class Button extends React.Component {
...
}
// Radium thư viện hỗ trợ inline style cho React element
```

Và boom Component của chúng ta nhận được props, styles và thậm chí là render ra một view khác

![](https://viblo.asia/uploads/8dd3d81c-5fc7-431b-867c-e96a511abb83.gif)

Các bạn đã bao giờ tự hỏi `connect()` `@Radium` kia là gì, tại sao lại viết như vậy. Vâng trong bài viết này chúng ta sẽ cùng tìm hiểu về một khái niệm nâng cao trong React - **Higher-Order Components.**

![](https://viblo.asia/uploads/d0174b65-4df5-4a89-8b4d-01a14fc0c757.gif)

# Higher-Order Components In a Nutshell

## What are Higher-Order Components (HoCs)?

Về bản chất, HoC không phải là một phần của React API, nó là một pattern xuất hiện từ những thành phần đặc tính của React. Thường được implement như một function, mà về cơ bản, là một class factory (vâng, là một class factory!)

> Higher Order Component (HoC) là một function nhận vào một component và trả về một component mới. EnhancedComponent = higherOrderComponent(WrappedComponent);

## What can I do with HOCs?

Ở cấp độ cao, HoC cho phép chúng ta:

- Code reuse, logic và tự động trừu tượng hóa (bootstrap abstraction)
- Chiếm quyền render (Render Highjacking)
- Trừu tượng hóa (abstraction) và điều khiển (manipulation) State
- Điều khiển Props

Chúng ta sẽ xem chi tiết về những mục này, nhưng trước tiên, chúng ta sẽ học cách implement HoCs bởi vì việc implement cho chúng ta thấy những điều có thể và hạn chế mà chúng ta thực sự có thể làm với HoC.

# HOC factory implementations

Có 2 cách implement HoCs thường thấy trong React: **Props Proxy (PP)** và **Inheritance Inversion (II)**. Cả 2 cách cho phép các cách khác nhau để thao tác với WrappedComponent.

Trước khi bắt đầu chúng ta cần một project

```javascript
create-react-app learnHOC
cd learnHOC/src/
touch HOC.js
npm start
```

## Props Proxy

Props Proxy (PP) được implement thông thường theo cách sau:

```javascript
function pP(WrappedComponent) {
  return class PP extends React.Component {
    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}
```

Phần quan trọng nhất ở đây là method render của HoC trả về một React Element của kiểu WrappedComponent. Chúng ta cũng truyền props mà HoC nhận được, vì thế phương pháp này mới có tên Props Proxy.

### What can be done with Props Proxy?

- Điều khiển props
- Truy cập instance thông qua Refs
- Trừu tượng hóa (Abstracting) State
- Bao WrappedComponent với elements khác

#### Điều khiển props

Chúng ta có thể đọc, thêm, sửa đổi và xóa props được truyền cho WrappedComponent.

Nhưng cẩn thận với việc xóa hay sửa đổi các prop quan trọng, chúng ta nên đặt namespace cho HoC props để nó không phá vỡ WrappedComponent.

Ví dụ: Thêm mới props.

```javascript
// HOC.js
import React from "react";

function pP(WrappedComponent) {
  return class PP extends React.Component {
    render() {
      const newProps = {
        newProps: "something news",
      };

      return <WrappedComponent {...this.props} {...newProps} />;
    }
  };
}

module.exports = {
  pP,
};
```

Sửa lại file App một chút

```javascript
// App.js
import {pP} from './HoC'

class App extends Component {
  render() {
    console.group('App');
    console.log('render');
    console.log(this.props);
    console.groupEnd();
    ...
  }
}

export default pP(App);
```

Và ở console chúng ta có kết quả ![](https://viblo.asia/uploads/48e1c152-e99c-48a3-9074-b6be4df55b6a.png)

#### Truy cập instance thông qua Refs

Chúng ta có thể truy cập this (instance của WrappedComponent) với ref, nhưng chúng ta sẽ cần một quá trình render đầy đủ của WrappedComponent để ref có thể được tính toán. Điều này có nghĩa là chúng ta cần trả về WrappedComponent element từ method render của HoC, để React có thể làm quá trình đối chiếu (reconciliation process) và chúng ta sẽ có ref đến WrappedComponent instance.

Ví dụ: Chúng ta sẽ tìm hiểu làm thế nào để truy cập instance methods và instance của chính WrappedComponent thông qua refs

```javascript
// HOC.js
function refsPP(WrappedComponent) {
  return class RefsPP extends React.Component {
    proc(wrappedComponentInstance) {
      console.group("refs Proc");
      console.log(wrappedComponentInstance);
      wrappedComponentInstance.test();
      console.groupEnd();
    }

    render() {
      const props = Object.assign({}, this.props, {
        ref: this.proc.bind(this),
      });
      return <WrappedComponent {...props} />;
    }
  };
}

module.exports = {
  pP,
  refsPP,
};
```

Sửa file App một chút

```javascript
import {pP, refsPP} from './HoC'

class App extends Component {
  test() {
    console.log('call Test');
  }
  .....
  }
}

export default refsPP(App);
```

Và ở console chúng ta có kết quả ![](https://viblo.asia/uploads/ff5e3971-58bf-406c-ae1b-ff012e790bee.png) Khi WrappedComponent được render xong thì ref callback sẽ được thực thi, và chúng ta sẽ có ref đến WrappedComponent instance. Điều này có thể được sử dụng để đọc/thêm các props và gọi các instance method.

#### Trừu tượng hóa (Abstracting) State

Chúng ta có thể trừu tượng hóa state bằng cách cung cấp props và callbacks cho WrappedComponent, tương tự như [Container Components làm với Presentational components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0). Ví dụ: Chúng ta sẽ thực hiện trừu tượng hóa state để kiểm soát input

```javascript
// HOC.js
function statePP(WrappedComponent) {
  return class StatePP extends React.Component {
    constructor(props) {
      super(props);
      this.state = { fields: {} };
    }

    getField(fieldName) {
      if (!this.state.fields[fieldName]) {
        this.state.fields[fieldName] = {
          value: "",
          onChange: event => {
            this.state.fields[fieldName].value = event.target.value;
            this.forceUpdate();
          },
        };
      }

      return {
        value: this.state.fields[fieldName].value,
        onChange: this.state.fields[fieldName].onChange,
      };
    }

    render() {
      const props = Object.assign({}, this.props, {
        fields: this.getField.bind(this),
      });

      return <WrappedComponent {...props} />;
    }
  };
}
```

Sửa file App một chút

```javascript
// App.js
import { pP, refsPP, statePP } from "./HoC";

class App extends Component {
  test() {
    console.log("call Test");
  }

  render() {
    console.group("App");
    console.log("render");
    console.log("name", this.props.fields("name"));
    console.log("email", this.props.fields("email"));
    console.groupEnd();
    return (
      <div className="App">
        ....
        <form>
          <label>Automatically controlled input!</label>
          <input type="text" placeholder="Name" {...this.props.fields("name")} />
          <input type="email" placeholder="Email" {...this.props.fields("email")} />
        </form>
      </div>
    );
  }
}
```

Và chúng ta có kết quả ![](https://viblo.asia/uploads/ea2e3283-f7ba-4b7e-a282-cc3a504b3324.png)

Việc trừu tượng hóa state có nhiều ứng dụng, và được sử dụng khá nhiều trong việc giải quyết các vấn đề mà Stateless component gặp phải như không có ref chẳng hạn.

#### Bao WrappedComponent với elements khác

Chúng ta có thể bao WrappedComponent với component hoặc element khác để styling, layout hoặc mục đích khác. Cách sử dụng cơ bản có thể hoàn thành bởi Parent Components nhưng chúng ta có nhiều sự linh hoạt hơn với HoCs như đã mô tả ở trên.

```javascript
// HOC.js
function elmWrapPP(WrappedComponent) {
  return class ElmWrapPP extends React.Component {
    render() {
      return (
        <div style={{ display: "block" }}>
          <WrappedComponent {...this.props} />
        </div>
      );
    }
  };
}
```

## Inheritance Inversion

Inheritance Inversion (II) thường được implement như sau:

```javascript
function iiHOC(WrappedComponent) {
  return class Enhancer extends WrappedComponent {
    render() {
      return super.render();
    }
  };
}
```

Như các bạn thấy, HOC trả về class (Enhancer) kế thừa (extends) WrappedComponent. Phương pháp này gọi là Inheritance Inversion là do thay vì WrappedComponent mở rộng (kế thừa) Enhancer class nào đó, nó lại được mở rộng (kế thừa) bởi Enhancer. Theo cách này, mối quan hệ giữa chúng dường như bị đảo ngược.

II cho phép HoC truy cập vào WrappedComponent instance thông qua this, điều này có nghĩa là **HoC có quyền truy cập state, props, component lifecycle hooks và cả phương thức render.**

Chúng ta sẽ không đi sau vào chi tiết chúng ta có thể làm gì với component lifecycle hooks, đó không phải là những gì cụ thể HoC làm, nó là React. Nhưng lưu ý rằng chúng ta hoàn toàn có thể tạo ra lifecycle hooks mới cho WrappedComponent. Và nhớ răng luôn gọi _super.[lifecycleHook]_ để không phá vỡ WrappedComponent.

#### Quá trình đối chiếu (Reconciliation process)

Trước khi bắt đầu chúng ta cần tóm tát vài lý thuyết.

React Elements mô tả những gì sẽ hiển thị khi React chạy quá trình đối chiếu của nó.

React Elements có thể có 2 loại: String và Function. String Type React Element (STRE) đại diện các DOM node và Function Type React Element (FTRE) đại diện các Component được tạo ra bằng cách mở rộng React.Component. Đọc thêm tại [post](https://facebook.github.io/react/blog/2015/12/18/react-components-elements-and-instances.html).

FTRE sẽ được phân giải ra thành cây STRE trong quá trình đối chiếu của React (kết quả cuối cùng luôn là các DOM Element).

Điều này rất quan trọng và nó có nghĩa là:

> Inheritance Inversion High Order Components không đảm bảo là đã giải quyết được toàn bộ cây con. Điều này sẽ được chứng thực khi học Render Highjacking.

### What can you do with Inheritance Inversion?

- Chiếm quyền render (Render Highjacking)
- Điều khiển state (Manipulating state)

#### Render Highjacking

Phương pháp này gọi là Render Highjacking bởi vì HoC kiểm soát render output của WrappedComponent và chúng ta có thể làm bất kì điều gì với nó.

Trong Render Highjacking chúng ta có thể

- Đọc, thêm, sửa, xóa props trong bất kì React Elements nào xuất ra bởi render.
- Đọc và sửa đổi React elements tree xuất ra bởi render.
- Hiển thị elements tree theo điều kiện.
- Bao element tree cho mục đích styling (giống như đã nói ở PP)\

_Note: render đề cấp đến WrappedComponent.render_

> Chúng ta không thể chỉnh sửa hoặc tạo props của WrappedComponent instace, bởi vì một React Component không thể chỉnh sửa props mà nó nhận được, nhưng chúng ta có thể thay đổi các props của các element xuất ra từ phương thức render.

Như chúng ta đã nói ở trên, II HoCs không đảm bảo toàn bộ cây con được giải quyết, điều này hàm ý một số giới hạn với kỹ thuật Render Highjacking. Quy tắc chung là với Render Highjacking chúng ta có thể thao tác với element tree mà WrappedComponent.render xuất ra không nhiều hơn cũng không ít hơn. Nếu Element tree đó có chưa một _[Function Type React Component](https://facebook.github.io/react/docs/components-and-props.html#functional-and-class-components)_ thì chúng ta sẽ không thể thao tác được với các con của Component đó. (Do chúng được hoãn lại bởi quá trình đối chiếu của React cho đến khi nó thực sự được render)

- Ví dụ 1: **Render có điều kiện** HOC sẽ render chính xác những gì mà WrappedComponent sẽ render trừ khi this.props.loggedIn = false. (Giả định là HoC sẽ nhận được loggedIn prop).

```javascript
// HOC.js
function rHII(WrappedComponent) {
  return class Enhancer extends WrappedComponent {
    render() {
      if (this.props.loggedIn) {
        return super.render();
      } else {
        return <div>Not loggedIn</div>;
      }
    }
  };
}
```

Và tất nhiên App của chúng ta không có props loggedIn (Lười quá (lol) ) nên kết quả sẽ là ![](https://viblo.asia/uploads/2ab60c9f-0e2b-4a5f-8f02-6bd187c6a718.png)

- Ví dụ 2: **Sửa đổi React Element tree** xuất ra bởi render.

```javascript
// HOC.js
function treeII(WrappedComponent) {
  return class Enhancer extends WrappedComponent {
    render() {
      const elementsTree = super.render()
      let newProps = {};
      var newChilds = elementsTree.props.children.map(function (child) {
        if (child.type === 'input') {
            var childNewProps = {value: 'may the force be with you'};
            var childProps = Object.assign({}, child.props, childNewProps)
            return React.cloneElement(child, childProps, child.props.children);
        }

        return child;
      });

      const props = Object.assign({}, elementsTree.props, newProps)
      const newElementsTree = React.cloneElement(elementsTree, props, newChilds)
      return newElementsTree
    }
  }
}<span class="hljs-comment">// App.js</span>

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">App</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Component</span></span> {
  render() {
    <span class="hljs-keyword">return</span> (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro" ref="appIntro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
        <input type="text" placeholder="Name"/>
      </div>
    );
  }
}

 export default treeII(App);
```

Trong ví dụ trên, nếu output render bởi WrappedComponent có chứa element con có type là `input' thì HoC sẽ thay đổi value của nó thành 'may the force be with you'.

Chúng ta có thể làm mọi thứ ở đây, chúng ta có thể duyệt qua toàn bộ các phần tử của element tree và thay đổi bất kì props của bất kì element nào trong tree. Và đây chính xác là những gì [Radium](https://github.com/FormidableLabs/radium) thực hiện.

> Note: Chúng ta không thể Render Highjack với Props Proxy. Mặc dù vẫn có thể truy cập vào phương thức render thông qua WrappedComponent.prototype.render, chúng ta sẽ cần phải mô phỏng WrappedComponent instance và các props của nó, và có khả năng là phải tự xử lý component lifecycle thay vì để React làm nó. Trong thực nghiệm của tôi, nó không có giá trị nhiều lắm và nếu chúng ta muốn Render Highjacking chúng ta nên sử dụng II thay vì PP. Hãy nhớ rằng React xử lý các component instances nội bộ và cách duy nhất để chúng ta thao tác với instances là thông qua refs.

#### Manipulating state

HOC có thể đọc, chỉnh sửa và xóa state của WrappedComponent instance, và chúng ta cũng có thể thêm state nếu cần. Hãy nhớ rằng chúng ta đang làm rối state của WrappedComponent, điều có thể dẫn chúng ta đến việc hủy hoại mọi thứ. Hầu hết các HOC nên được giới hạn để đọc hoặc thêm state, và sau đó được đặt tên (namespace) để không làm rối state của WrappedComponent.

Ví dụ: Debugging bằng cách truy cập props và state của WrappedComponent

```javascript
function IIHOCDEBUGGER(WrappedComponent) {
  return class II extends WrappedComponent {
    render() {
      return (
        <div>
          <h2>HOC Debugger Component</h2>
          <p>Props</p> <pre>{JSON.stringify(this.props, null, 2)}</pre>
          <p>State</p>
          <pre>{JSON.stringify(this.state, null, 2)}</pre>
          {super.render()}
        </div>
      );
    }
  };
}
```

HOC này sẽ bao WrappedComponent với element khác đồng thời hiện các props và state của WrappedComponent.

## Naming

Khi bao một component với HOC chúng ta đánh mất tên của WrappedComponent, điều này sẽ ảnh hưởng đến chúng ta trong quá trình dev và debugging.

Mọi người thường làm là tùy chỉnh tên của HOC bằng cách lấy tên của WrappedComponent và đặt trước một cái gì đó. Dưới đây trích từ React-Redux:

```javascript
HOC.displayName = `HOC(${getDisplayName(WrappedComponent)})`
//or
class HOC extends ... {
  static displayName = `HOC(${getDisplayName(WrappedComponent)})`
  ...
}
```

Function getDisplayName được định nghĩa như sau

```javascript
function getDisplayName(WrappedComponent) {
  return WrappedComponent.displayName ||
         WrappedComponent.name ||
         ‘Component’
}
```

Chúng ta thực sự không phải viết lại nó vì thư viện [recompose](https://github.com/acdlite/recompose) đã cung cấp function này rồi.

## Phụ lục

### HOC and parameters

Đôi khi rất hữu ích khi sử dụng các parameters cho HOCs. Điều này ẩn trong những ví dụ bên trên và nên được phát triển tự nhiên đến Javascript developers trung gian, nhưng vì lợi ích làm cho bài viết đầy đủ, chúng ta sẽ lướt qua nó một cách nhanh chóng.

Ví dụ: HOC parameters với Props Proxy thông thường. Điều quan trọng là HOCFactoryFactory function.

```javascript
function HOCFactoryFactory(...params) {
  // do something with params
  return function HOCFactory(WrappedComponent) {
    return class HOC extends React.Component {
      render() {
        return <WrappedComponent {...this.props} />;
      }
    };
  };
}
```

Và chúng ta có thể sử dụng như thế này

```javascript
HOCFactoryFactory(params)(WrappedComponent);
//or
@HOCFatoryFactory(params)
class WrappedComponent extends React.Component {}
```

### Difference with Parent Components

Như đã nói ở phần 'Bao WrappedComponent với elements khác', ở một số cách cơ bản cảu HOC ta có thể hoàn thành với Parent Component. Vậy điểm khác biệt giữ HOC và Parent Component là gì?

> Parent Components là React Components có vài components con. React có APIs để truy cập và thao tác với component con.

Ví dụ:

```javascript
class Parent extends React.Component {
    render() {
      return (
        <div>
          {this.props.children}
        </div>
      )
    }
  }
}

render((<Parent>{children}</Parent> ),  mountNode);
```

Giờ chúng ta sẽ duyệt qua xem Parent Components có và không thể làm gì khi so sánh với HOCs và thêm vài thông tin quan trọng:

- Có thể Render Highjacking tương tự như với II HOC
- Có thể điều khiển inner props tương tự như với II HOC
- Có thể trừu tượng hóa state, nhưng có nhược điểm. Chúng ta sẽ không thể truy cập state của Parent Component từ bên ngoài trừ khi chúng ta tạo hooks cho nó. Điều này hạn chế tính hữu ích của nó.
- Bao các elements với elements khác. Đây có thể là trường hợp duy nhất Parent component làm tốt hơn HOC. Nhưng tất nhiên là HOC cũng làm đc.
- Thao tác với child component gặp một số vấn đề. Ví dụ nếu childrent không chỉ có 1 root element (nhiều hơn 1 first level childrent), thì chúng ta phải thêm 1 element để bao tất cả children lại, mà điều này có thể gây rườm ra cho markup của chúng ta. Trong HOCs 1 top level children root được đảm bảo bởi React/JSX.
- Parent Components có thể được sử dụng tự do trong Elements tree, chúng không bị hạn chế 1 Component 1 lần như HOC.

Nói chung, nếu chúng ta có thể làm được nó với Parent Components thì chúng ta nên làm nó, bởi vì Parent Components ít "hack não" hơn HOCs, nhưng như những điều đã nói, với State nó kém linh hoạt hơn so với HoCs.

## Conclusion

Hi vọng là sau khi đọc bài này, mọi người sẽ hiểu hơn một chút về React HOCs. Chúng thực sự có ý nghĩa và đã được chứng minh khá tốt trong nhiều thư viện khác nhau. React mang lại rất nhiều sự đổi mới và những thư viện như Radium, React-Redux, React-Router trong số rất nhiều thư viện khác là những bằng chứng về điều đó.
]]></description>
            <link>https://hungvn.com/blog/hieu-sau-ve-react-higher-order-components</link>
            <guid isPermaLink="true">https://hungvn.com/blog/hieu-sau-ve-react-higher-order-components</guid>
            <pubDate>Mon, 30 Apr 2018 15:08:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách phân nhánh và chia việc trong nhóm với Git]]></title>
            <description><![CDATA[
Bạn vốn làm việc một mình một cõi, “thầu nguyên con” dự án. Dù phải code sấp mặt nhưng cuộc đời vẫn thật êm xuôi: tốc độ thần thánh 500 dòng/giờ, commit code mới pặc pặc vào master, cuối ngày chỉ việc git push, tắt máy, rồi dắt gấu đi nhậu (hoặc lội suối băng đèo về nhà thay tã cho con).

Ngờ đâu sếp (hoặc co-founder) xót thương bạn vất vả, bèn tuyển ngay 2 em đào nhí vào trợ giúp. Và mọi chuyện bắt đầu phức tạp từ đây: code trong team bị chồng chéo và xung đột liên tục, branch master đang thẳng thớm đẹp xinh bỗng phân nhánh như điên, tốc độ code của bạn giảm trong khi tốc độ chửi thề ngày một tăng nhanh. Bạn không còn thời giờ dắt gấu đi nhậu, cũng không thể lội kịp về nhà thay tã cho con nữa. Cuộc đời bế tắc.

![Nhìn hình này bạn có thấy quen không (nguồn: Xebia.com)?](https://res.cloudinary.com/duqeezi8j/image/upload/v1524414315/git-merge-hell-smaller_lxhizg.png)

Thôi đừng vội lật bàn quýnh cả sếp lẫn đào. Hãy thử làm theo một số quy ước sau đây, đảm bảo team dev nho nhỏ xinh xinh của bạn sẽ không còn “giẫm chân” nhau nữa. Công việc xuôi buồm mát mái, tình đồng nghiệp sẽ lại thương mến thương nè.

### Vậy, vấn đề chính ở đây là gì?

Không có gì nghiêm trọng cả, chỉ là chúng ta chưa có một quy ước phân chia nhánh (branch) hợp lý thôi. So với các chương trình quản lý phiên bản khác như SVN, khả năng phân nhánh của Git phải nói là siêu nhẹ và cực kì dễ dàng. Do đó, bạn có thể chia dự án thành 2 nhánh chính:

- master
- dev

Nhánh master sẽ là nơi chứa phần code **ổn định nhất**, sẵn sàng để triển khai bất cứ lúc nào. Trong khi đó, nhánh dev ban đầu được tách ra từ master, và sẽ chứa phần code **mới nhất** được phát triển.

> **Nói nhỏ:** Một số tài liệu sẽ đặt tên nhánh tách ra là develop. Tùy bạn chọn tên gì cũng được, nhưng theo Ehkoo thì gõ dev nhanh hơn gõ develop :p

**Nhắc bài chút xíu**
Để tạo nhánh mới trong Git, bạn dùng lệnh:

```
git checkout -b <tên nhánh mới> [nhánh gốc]
```

Chẳng hạn, để tạo nhánh dev từ master, bạn gõ git checkout -b dev master. Nếu không cung cấp tham số [nhánh gốc], nhánh mới tạo sẽ dựa trên nhánh hiện tại bạn đang ở. Để xem nhánh hiện tại là nhánh nào, bạn có thể dùng lệnh git branch.

```
$ git branch
  auth
* auth-session
  dev
  graphql
  master
```

Trong ví dụ trên thì nhánh hiện tại chính là auth-session.

### Phân chia công việc

Mỗi khi phát triển tính năng mới, bạn sẽ tạo một nhánh từ dev.

```
git checkout -b login dev
```

> **Đặt tên nhánh là gì đây?**
> Tùy bạn thôi. Một số tài liệu sẽ khuyến khích bạn dùng tiền tố `feature/<tên tính năng>` để dễ phân biệt. Nhưng theo kinh nghiệm của Ehkoo, ngoài nhánh master, dev, và các nhánh fix-xxx, thì tất cả các nhánh còn lại đều có thể ngầm hiểu là nhánh chức năng.

Nhánh này dưới quyền cai quản của bạn, nên mặc sức muốn làm gì thì làm nhé. Hãy commit thường xuyên, dù chỉ là những thay đổi nhỏ nhất. Cũng đừng ngần ngại rằng commit nhỏ sẽ khiến git log khó theo dõi. Chúng ta sẽ có cách xử lý chúng sau.

> **Câu hỏi: Ê, lỡ như có hai hay nhiều người cùng làm chung một tính năng thì sao?**
> Nếu vậy, bạn có thể tiếp tục chia nhỏ hơn nữa, để đảm bảo mỗi người làm việc trên một nhánh độc lập. Cũng theo kinh nghiệm riêng của Ehkoo, thì một tính năng _to_ sẽ có nhiều nhất là 2-3 người cùng phát triển. Nếu vượt quá con số này, thì nên xem lại định nghĩa và cách phân chia việc cho tính năng đó.

### Chuẩn bị merge vào dev

Sau khi code hoàn tất và tất cả unit tests đã chạy thành công, giờ là lúc bạn merge/gửi code để review tính năng mới vào dev. Thông thường, sẽ có 2 trường hợp xảy ra:

**Trường hợp 1: Không có gì mới trong dev**

Giả sử lúc đó Git history của dự án giống như thế này:

<Jsfiddle id="r7rp7sp5/31" />

Như bạn thấy, nhánh login màu vàng được rẽ ra từ nhánh dev màu xanh, và trong nhánh dev không có code gì mới. Đây là trường hợp lý tưởng, đảm bảo khi merge vào dev chúng ta sẽ không bị xung đột code.

**Trường hợp 2: Có commits mới trong nhánh dev**

<Jsfiddle id="r7rp7sp5/30" />

Trong trường hợp này, branch dev (màu xanh) đang có 2 commits phía trước branch login (màu vàng). Nếu trong 2 commits đó có chứa thay đổi liên quan đến dev, chẳng hạn như package.json, thì khả năng cao là sẽ xảy ra xung đột khi merge trực tiếp login vào. Mà dù có may mắn không xảy ra xung đột code, thì merge vào cũng sẽ làm history xấu đi.

<Jsfiddle id="r7rp7sp5/33" />

Do đó, chúng ta sẽ cần sửa lại history của nhánh login bằng cách dùng git rebase.

#### git rebase là gì?

git rebase sẽ đem những commits bên trong nhánh login và áp dụng lại vào sau commit mới nhất trong nhánh dev. Cú pháp của lệnh này là:

```
git rebase <tên nhánh muốn áp dụng lại>
```

Trong trường hợp hiện tại, chúng ta sẽ chạy những lệnh sau:

```
# Cập nhật repo hiện tại, đồng thời lấy về commits mới nhất của `dev`
git pull
# Chuyển qua nhánh `login`, có thể bỏ qua bước này nếu bạn chắc chắn
# mình đang ở `login`
git checkout login
# Tiến hành rebase
git rebase dev
```

Nếu xảy ra xung đột code, bạn có thể phát hiện và giải quyết chúng sớm. Nguyên tắc chung là không sửa code của người khác, và chỉ kết hợp thêm những gì bạn làm. Việc thực hiện rebase tại nhánh chức năng do bạn phụ trách giúp giảm thiểu khả năng mất code, vì bạn là người hiểu rõ nhất phần code bạn viết.

Sau khi giải quyết hết các xung đột trong code, bạn chạy git rebase --continue để tiếp tục tiến trình rebase. Bạn cũng có thể chạy git rebase --abort để hủy bỏ rebase và đưa nhánh login về lại trạng thái ban đầu.

> **Mách nhỏ:**
> Một cách giúp cho việc giải quyết xung đột trong code dễ dàng hơn là dùng git mergetool. Có rất nhiều công cụ hỗ trợ, và [Meld](http://meldmerge.org/) là một trong số đó.

Nếu chưa quen rebase, bạn có thể tạo một branch mới từ login, ví dụ: git checkout -b test login, và tiến hành rebase trên branch này. Sau khi chắc chắn là mọi thứ ổn thỏa, bạn có thể quay lại và tiến hành rebase cho login.

Khi rebase xong, mong là history của bạn trông sẽ giống như thế này:

<Jsfiddle id="r7rp7sp5/32" />

Bạn thấy quen không? Chính là trường hợp 1 đã nói ở trên đó.

#### rebase interactively

Ở phần trên, chúng ta có băn khoăn là commit thường xuyên dễ tạo ra nhiều commit nhỏ đôi khi không cần thiết. Bạn có thể dùng git rebase để dọn dẹp chúng bằng cách thêm tham số -i (interactively) như sau:

```
# Chắc chắn rằng bạn đang ở nhánh `login`
git checkout login
# Rebase lên dev interactively
git rebase dev -i
```

Bạn sẽ được chuyển đến một giao diện tương tự như bên dưới.

```
pick ff80e85 A way to organize routes per module
pick 67cf18d Try Netlify Functions
pick 5546901 Add Dashboard view
pick 2a66ae3 Change layout
pick 58755b4 Add Books module, 404 page.
pick fd79cb9 Refactor. Reduce inline styling.
pick c671f60 Restyling 404 page.
pick 33ef874 Basic layout for book management page.
pick 49c423a Clean up UI a bit
pick 3aa2840 Init
```

Theo lý thuyết, rebase sẽ đem từng commit và áp dụng lại theo thứ tự từ trên xuống dưới. Bởi vậy, bạn có thể thoải mái sắp xếp lại thứ tự của các commits trên. Bạn để ý lệnh pick ở phía trước mỗi commit. Lệnh này sẽ báo cho git biết hành động bạn muốn làm với commit, trong trường hợp này là áp dụng lại commit. Ngoài pick (p), chúng ta còn có:

- reword (r): áp dụng lại commit, và sửa commit message
- edit (e): áp dụng commit, nhưng dừng quá trình rebase lại để sửa code
- squash (s): kết hợp commit hiện tại vào commit trước nó
- fixup (f): giống như squash nhưng bỏ đi commit message
- exec (x): chạy một lệnh shell nào đó
- drop (d): bỏ, không sử dụng commit này

![Bạn có thể dùng các chữ viết tắt cho các commands](https://res.cloudinary.com/duqeezi8j/image/upload/v1524470951/Peek_2018-04-23_11-06_zkqjpt.gif)

Bằng cách dùng rebase interactively, chúng ta có thêm nhiều quyền để quản lý và sửa đổi commits theo ý mình, làm cho history sạch đẹp hơn.

### Merge vào dev

Sau khi dọn dẹp nhánh login sạch đẹp, chúng ta có thể merge nhánh này vào dev. Thông thường, bạn – dev cứng nhất team – sẽ là người tiến hành kiểm tra và merge. Bạn có thể chọn hai cách tiếp cận:

#### merge

Bạn có thể merge trực tiếp vào dev như thế này:

```
# Chuyển qua nhánh `dev`
git checkout dev
# Merge `login` vào `dev`
git merge login
```

Kết quả sẽ là:

<Jsfiddle id="r7rp7sp5/34" />

Như bạn thấy, một commit mới được tạo ra, giúp bạn dễ dàng nhận biết thời điểm nhánh login được merge vào. Cách thức này gọi là merge fast-forward. Khi dự án phát triển dần theo thời gian, history của dev sẽ như thế này.

<Jsfiddle id="0agufwbv/2" />

Bên cạnh đó, chúng ta cũng có cách merge non-fast-forward:

```
git merge login --no-ff
```

Và đây là kết quả:

<Jsfiddle id="r7rp7sp5/35" />

Tất cả commits của login đã được kết hợp vào dev. Boom! login biến mất khỏi thế gian như chưa hề tồn tại. SAD!

Lợi ích dễ thấy nhất của merge non-fast-forward là giúp cho history của bạn thẳng thớm gọn gàng, còn bất lợi là bạn không phân biệt được commits nào là của nhánh tính năng, cũng như thời điểm merge diễn ra. Trong trường hợp nhánh tính năng có quá nhiều commits nhỏ và dư thừa, chẳng hạn như những commits sửa lỗi chính tả, cập nhật thư viện…, history của bạn sẽ bị nhiễu.

#### rebase, squash và merge

Ngoài cách merge các commits của nhánh tính năng vào dev, bạn có thể rebase và squash tất cả commits lại làm một, sau đó tiến hành merge. Cách làm này giúp cho dev luôn ở trạng thái gọn gàng nhất, không chứa commit dư thừa. Trong trường hợp lý tưởng, history của dev sẽ giống như sau:

<Jsfiddle id="0agufwbv/5" />

Để cách làm này phát huy tối đa hiệu quả, yêu cầu commit message phải được viết thật rõ ràng và chi tiết.

### Merge vào master

Yay! Sau một thời gian quằn quại, cuối cùng team của bạn đã ra được sản phẩm tương đối ổn. Giờ là lúc merge vào master và triển khai lên server.

Lúc này, cũng như khi merge vào dev, bạn có thể chọn merge (fast-forward hoặc non-fast-forward) hay rebase, squash và merge, nhưng theo kinh nghiệm của Ehkoo, merge --no-ff sẽ là lựa chọn tốt nhất, giúp cho master và dev luôn song song với nhau.

### Hotfix

Hôm nay, thứ 6, ngày 1X. Bạn chạy npm run build rồi rsync code ở master lên server. Mọi thứ hoàn toàn bình thường. Bạn vào website, click vài cái. "Ngon, chạy rồi", bạn thầm nghĩ, “đi nhậu thoy!” Nhưng vừa vươn vai định gọi điện cho gấu, thì "ó e ò e", chuông điện thoại reng, số máy của sếp. “Hí hí, chắc được thưởng nóng chăng?” Bạn bắt máy, và nghe giọng sếp âu yếm GẦM ở đầu dây: “LỖI RỒI MÁÁÁ!!!”

Xin đừng trụy tim. Hãy hít một hơi thật sâu, rồi bình tĩnh tạo một branch mới từ master, fix-xxx chẳng hạn. Nhờ lắng nghe tiếng sếp gầm, bạn đã mau chóng mò ra lỗi trong đống code (vì bạn là dev cứng mà hihi). Bạn khẽ rủa thầm ku đào nhí viết code không kĩ, tự rủa nhẹ bản thân vì review sót. Nhưng thôi kệ, fix nhanh rồi còn về, kẻo gấu xé xác T^T.

Bạn bèn merge --no-ff nhánh fix-xxx vào cả hai nhánh master và dev. Bằng cách này, phần sửa lỗi sẽ xuất hiện ở cả hai branches, giúp history không bị rẽ nhánh bất ngờ.

Bạn push, và chuông điện thoại lại vang lên…

### Vài vấn đề linh tinh khác

#### Có cần nhánh staging không?

Trong một số dự án, ngoài dev, còn có một đội ngũ “thần bí” được gọi là QA/QC. Họ được sinh ra trong team là để bới lỗi của anh em nhà dev, nên quan hệ đôi bên không được tình thương mến thương cho lắm. Dầu vậy, họ vẫn cần một nhánh riêng có tên gọi staging. Nhánh này sẽ chứa phần code ở giữa master và dev. staging được tách ra từ dev, có nhiều tính năng hơn master, và tương đối ổn định để có thể merge vào master.

<Jsfiddle id="0agufwbv/6" />

Tùy vào tình hình cụ thể của team mà bạn quyết định có cần staging hay không.

#### Viết commit message như thế nào cho chuẩn?

Nếu bạn theo chuẩn rebase, squash và merge thì chuyện viết commit message tốt rất quan trọng, vì nó sẽ là tài liệu để mô tả toàn bộ một tính năng. Nhưng nên viết thế nào? Có một vài gợi ý cho bạn đây:

- Dòng đầu tiên không dài quá 80 chữ, luôn bắt đầu bằng động từ ở thì hiện tại, ngắn gọn súc tích, ví dụ: _Add module Authentication_. Bạn có thể chọn thêm tiền tố nếu cần thiết, chẳng hạn: _Feature: Add module Authentication_ hay _Fix: unable to get location params from URL_
- Bỏ trống hai dòng
- Sau đó mô tả chi tiết về tính năng đang làm, những điểm cần lưu ý, phần nào của tính năng cần được cải thiện…
- Khuyến khích bạn kèm theo chữ ký _signature_ khi commit bằng git commit -s

Một ví dụ

```
Feature: Add module Authentication

Signed-off-by: Long Dep Trai <long@ehkoo.com>

This module allows users to register/login into our website using
AWS Cognito account. Added routes:

* /auth/register
* /auth/login

Users after registration will receive a SMS to confirm their account.

TODO:

* Implement social identities
* Add Logout feature
* Add Forgot password feature
```

> **Tiếng Anh hay tiếng Việt?**
> Tùy thuộc vào team của bạn, nhưng phải thống nhất trong toàn dự án, và viết tiếng Việt thì nhớ đừng sai chính tả kẻo bị công an bắt nhé.

#### Có nên tag version hay không?

Câu trả lời là _HÊN XUI_, tùy tính chất từng team. Nếu tần suất triển khai code từ master của team không cao, khoảng vài tháng/lần thì tag version là cách tốt để theo dõi những thay đổi. Hoặc nếu bạn đang xây dựng lib hoặc làm việc open source.

Còn nếu team bạn theo chuẩn "move fast, break things", thì có lẽ không cần tag version đâu. Thêm nữa, để tag version phát huy hiệu quả tối đa, thì _CHANGELOG_ cần phải được viết kỹ càng. Đồng thời, đừng quên tag version theo [semver](https://semver.org/) nhé.

![Already broken](https://res.cloudinary.com/duqeezi8j/image/upload/v1524474052/tumblr_lc63ingGof1qz6pqio1_500_mybavi.png)

### Kết luận

Chúng ta có thể tóm tắt bài này lại như sau:

- Dự án được chia thành nhiều nhánh, bao gồm master, dev và có thể có staging
- Các nhánh tính năng được chia ra từ dev, phát triển độc lập, được rebase trước khi merge lại vào dev
- Rebase có thể thay đổi một chút history, hoặc squash lại thành một commit duy nhất
- Merge có thể là fast-forward hoặc non-fast-forward
- dev sẽ được merge vào master mỗi khi triển khai. Trường hợp có staging, dev sẽ được merge vào staging, và staging sẽ được merge vào master.
- Các nhánh hotfix sẽ được chia ra từ master, sau đó merge --no-ff vào master và dev

Dĩ nhiên bài viết này chỉ mang tính tham khảo, vì mỗi team mỗi công ty sẽ có những cách làm riêng. Tuy nhiên, nếu bạn không may lâm vào cảnh trái ngang như ở đầu bài, thì đây là một workflow rất nên nghiên cứu và áp dụng. Mong rằng trong tương lai, dự án của bạn sẽ không trở thành “kim tự tháp” như hình dưới đây.

![The pyramid of doom](https://res.cloudinary.com/duqeezi8j/image/upload/v1524414465/11406260_10204684523099229_6956873399787391385_o_mscrhf.jpg)
]]></description>
            <link>https://hungvn.com/blog/cach-phan-nhanh-va-chia-viec-trong-nhom-voi-git</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-phan-nhanh-va-chia-viec-trong-nhom-voi-git</guid>
            <pubDate>Thu, 26 Apr 2018 21:50:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về một số khái niệm trong Git]]></title>
            <description><![CDATA[
### Giới thiệu

Đối với các lập trình viên, việc sử dụng công cụ quản lý phiên bản **git** là điều không thể thiểu trong công việc hằng ngày và là một trong những kĩ năng cơ bản nhất mà ai cũng cần có được. **Git** có rất nhiều các khái niệm khác nhau nên nếu bạn chỉ là người mới làm quen với **git** thì đây chính là bài viết dành cho bạn. Bài viết sẽ giải thích tại sao chúng ta nên sử dụng **git** cũng như một số khái niệm thường gặp khi sử dụng **git**.

### Tại sao cần sử dụng git?

- Thử tưởng tượng khi làm một project và bạn muốn bổ sung hoặc làm thêm tính năng mới cho project của mình. Tuy nhiên để đảm bảo rằng bạn có thể quay lại sử dụng phần code trước đó bạn đã code trong trường hợp tính năng mới gây lỗi và bạn không nhớ phải xóa những gì để khôi phục lại trạng thái code trước đó thì bạn cần phải thực hiện copy toàn bộ project đó và paste ra đâu đó để lưu trữ rồi mới bắt đầu thực hiện code tính năng mới. Như vậy mỗi lần muốn làm tính năng mới, bạn phải lặp đi lặp lại thao tác trên và rất mất thời gian. Sử dụng **Git** có thể giải quyết vấn đề này chỉ trong 1 vài dòng lệnh
- Nếu project bạn đang làm có 2 thành viên cùng làm, mỗi lần một người hoàn thành một tính năng lại phải gửi toàn bộ source code đó thông qua usb, google driver hoặc công cụ lưu trữ online nào đó cho thành viên còn lại có thể download về và paste đè lại lên phần code của người đó. Công việc này cũng mất rất nhiều thời gian và tồn tại nhiều rủi rõ khi paste code chồng lên nhau. Để giải quyết vấn đề này, ta cũng có thể sử dụng **git** và một **remote repository**

### Các khái niệm cơ bản trong git

#### 1\. Repository là gì?

- Khi sử dụng git, lệnh đầu tiên mà chúng ta thường gõ:

```
$ git init
```

- Lệnh này sẽ tạo ra một thư mục ẩn có tên .git và đây chính là repository (hay kho chứa). Còn phần code hay hay thư mục của project nằm cùng với thư mục .git được gọi là Working Directory. Git sử dụng repository này để lưu trữ, giám sát toàn bộ thông tin về các trạng thái của và bất cứ thay đổi nào với project lúc này sẽ được git lưu trữ lại.
- Có hai loại repository gồm local repository - là repository nằm trên chính máy tính của chúng ta và remote repository - là repository nằm trên một máy chủ từ xa được cung cấp bởi các nhà phân phối như [Github](https://github.com/), [Gitlab](https://gitlab.com/) hay [Bitbucket](https://bitbucket.org/), ...

#### 2\. Branch là gì?

- Như đã nói ở trên về vấn đề khi ta muốn thêm một tính năng mới mà đảm bảo vẫn có thể dễ dàng khôi phục lại trạng thái trước đó thì ta có thể sử tạo 1 branch mới nhau sau:

```
$ git branch <tên-branch>
```

hoặc

```
$ git checkout -b <tên-branch>
```

- Branch mặc định là master
- Branch mới được tạo ra sẽ chứa toàn bộ trạng thái và những thay đổi đã thực hiện trên project trước khi được tạo
- Với mỗi repository ta có thể tạo nhiều branch khác nhau và các nhánh này là độc lập với nhau nên khi ta có thay đổi đối với project trên branch này sẽ không ảnh hưởng đến các branch khác
- Khi tính năng được ta thử nghiệm trên nhánh mới hoàn thiện và đã được kiểm tra đầy đủ, ta có thể tiến hành hợp nhất 2 nhánh với nhau (đưa những thay đổi của nhánh này gộp vào với nhánh khác)
- Có hai loại branch là local branch - là branch nằm trên máy tính của chúng ta và remote branch - là branch nằm trên máy chủ từ xa

#### 3\. Làm thế nào để xóa một branch?

- Trong trường hợp branch chúng ta tạo ra trước đó không còn cần thiết nữa, ta có thể tiến hành xóa chúng đi bằng cách sử dụng các lệnh như sau:
  - Đối với local branch:

  ```
  $ git branch -d <tên-branch>
  ```

  Với cách xóa trên, nếu branch cần xóa chưa được gộp thay đổi với branch khác sẽ lập tức báo lỗi vào yêu cầu gộp với branch khác trước khi thực hiện xóa bằng lệnh này

  ```
  $ git branch -D <tên-branch>
  ```

  Với cách xóa này thì branch được chỉ định sẽ lập tức bị xóa kể cả trong trường hợp nó chưa được gộp với branch khác
  - Đối với remote branch:

  ```
  $ git push --delete <tên-remote> <tên-branch>
  ```

  hoặc

  ```
  $ git push <tên-remote> --delete <tên-branch>
  ```

_Lưu ý: đối với cả local branch và remote branch ta có thể tiến hành xóa đồng thời nhiều branch bằng cách liệt kê tên các branch cần xóa liền nối tiếp nhau và cách nhau một khoảng trắng_

#### 4\. Push local branch lên remote server với một tên khác

- Thông thường khi chúng ta tiến hành push một local branch lên remote server thì tên branch mặc định của remote branch lúc này sẽ là tên của local branch, lệnh push như sau:

```
$ git push <tên-remote> <tên-branch>
```

- Nhưng nếu ta muốn đổi tên của remote branch đó trên server thì ta cần sử dụng lệnh như sau:

```
$ git push <tên-remote> <tên-branch>:<tên-remote-branch>
```

#### 5\. Phân biệt rebase và merge

- Khi muốn tiến hành gộp 2 branch lại với nhau, ta có thể sử dụng một trong hai lệnh sau:

```
$ git merge <tên-branch>
```

hoặc

```
$ git rebase <tên-branch>
```

Sẽ tiến hành gộp branch hiện tại với branch mà ta lựa chọn. Tuy có cùng chức năng là gộp nhánh nhưng cách hoạt động của merge và rebase lại khác với nhau, ta có thể so sánh sự khác biệt thông đó như sau:

- Giả sử ta có 2 branch cần gộp với nhau như hình sau:
  ![](https://viblo.asia/uploads/2916cb93-a062-4546-9414-16781503b1c1.png)

---

- Đối với sử dụng merge kết quả thu được sẽ như sau:
  ![](https://viblo.asia/uploads/8da09449-44e1-49e6-902e-0648cdcb2977.png)
  Việc sử dụng merge sẽ tạo ra một commit mới là kết hợp từ 2 commit cuối cùng của 2 nhánh cần gộp vào với nhau Log commit sẽ không bị thay đổi và thứ tự các commit sẽ được sắp xếp theo thời gian tạo commit

---

- Đối với sử dụng rebase kết quả thu được sẽ như sau:
  ![](https://viblo.asia/uploads/e26ee7ad-e024-4dda-b500-261cfe7b9dd9.png)
  Rebase sẽ đưa toàn bộ branch Feature lên trên 'đầu' branch master Làm thay đổi lịch sử commit

#### 6\. Khác nhau giữa fetch và pull

- Khi muốn cập nhật các thay đổi từ trên remote server về local repository ta cũng có hai cách để thực hiện điều này như sau:

```
$ git pull <tên-remote> <tên-remote-branch>
```

Lệnh này sẽ tiến hành kéo các thay đổi từ trên remote server về local của chúng ta đồng thời tiến hành merge các thay đổi đó ngay

```
$ git fetch <tên-remote> <tên-remote-branch>
```

Đối với lệnh fetch, các thay đổi từ remote server sẽ được kéo về máy nhưng không tự động merge vào source code của chúng ta mà chúng ta có thể thực hiện việc này sau khi đã review lại các thay đổi đó trước khi tiến hành merge. Các thay đổi này được đẩy sang một branch khác và ta có thể sử dụng lệnh:

```
$ git branch -a
```

Để xem được các branch sau khi fetch đồng thời cũng có thể checkout sang branch đó để xem các thay đổi.

- Có thể hiểu đơn giản lại sự khác nhau giữa fetch và pull như sau:
  - git pull = git fetch + git merge

#### 7\. Thế nào là git stash?

- Trong quá trình chúng làm việc, có những lúc chúng ta đang code dở một chức năng nào đó nhưng bất ngờ ở một chức năng trên branch khác đang có lỗi cần phải sửa gấp và chúng ta muốn lưu lại thay đổi đã làm trên nhánh hiện tại nhưng không muốn thực hiện commit dư thừa thì git stash là lệnh mà chúng ta có thể dùng để giải quyết vấn đề này.
- git stash cho bạn khả năng lưu lại trạng những thay đổi mà bạn đã tạo ra mà không cần thiết phải commit nó giúp bạn có thể dễ dàng chuyển sang nhánh khác làm việc và sau đó quay lại và tiếp tục những gì bạn đang làm ở nhánh đó.
- Các lệnh liên quan đến git stash
  - **Để lưu được những thay đổi mà không cần commit nó, ta cần thực hiện những lệnh sau**:

  ```
  $ git add .
  ```

  Để đưa toàn bộ các thay đổi đó vào trạng tháy staged, sau đó sử dụng lệnh sau để lưu thay đổi đó mà không cần commit:

  ```
  $ git stash # hoặc "git stash save"
  ```

  - **Để xem lại các thay đổi đã lưu, ta có thể dùng các lệnh sau**:

  ```
  $ git stash list
  stash@{0}: WIP on <branch-name>: <lastest commit>
  stash@{1}: WIP on <branch-name>: <lastest commit>
  stash@{2}: WIP on <branch-name>: <lastest commit>
  ```

  - **Để xem lại danh sách các lần đã lưu, trong trường hợp muốn xem nội dung thay đổi thì ta gõ lệnh sau**:

  ```
  $ git stash list -p
  ```

  - **Hoặc nếu muốn xem cụ thể nội dung thay đổi của một lần lưu cụ thể, ta dùng lệnh**:

  ```
  $ git stash show "stash@{n}"
  // với n là lần lưu tương ứng trong danh sách
  // Lưu ý phần stash@{n} phải nằm trong cặp ngoặc đôi
  ```

  - **Để lấy lại thay đổi được lưu trong danh sách trên ta dùng lệnh**:

  ```
  $ git stash apply "stash@{n}"
  ```

  Hoặc lấy thay đổi gần nhất và xóa lần lưu đó

  ```
  $ git stash pop
  ```

  - **Để xóa danh sách các thay đổi đã lưu, ta dùng lệnh**:

  ```
  $ git stash drop "stash@{n}"
  ```

  Để drop một lần lưu chỉ định hoặc

  ```
  $ git stash clear
  ```

  Để xóa toàn bộ những lần đã lưu

#### 8\. Làm thể nào để xóa bỏ trạng thài vài commit gần đây?

Để thưc hiện công việc này chúng ta có thể sử dụng 1 trong 2 lệnh sau:

```
$ git revert <commit-hash-code>
```

Lệnh này sẽ tạo ra một commit mới đảo ngược lại những thay đổi trong commit được chỉ định.

```
$ git reset --hard <commit-hash-code>
```

Keehnh này sẽ xóa toàn bộ các commit trước đó và đưa branch hiện tại trở về trạng thái của commit-hash-code đã chọn

#### 9\. Gộp một vài commit thành một commit duy nhất?

- Đôi khi trong lúc làm việc, ta thường tạo ra một số commit dư thừa và sau đó muốn gộp chung số commit đó lại với một message rõ ràng hơn về mục đích chung của toàn bộ các commit đó. Để làm được điểu này, ta có thể sử dụng những lệnh sau:

```
$ git rebase -i <commit-hash-code>
```

Với commit-hash-code là hash code của commit cuối cùng của nhóm cần gộp hoặc:

```
$ git rebase -i HEAD~<index>
```

Với index là số lượng commit cần gồm so với commit cuối cùng. Ngoài ra khi thực hiện việc rebase để gộp commit, ta có các lựa chọn khác như pick|squash|fixup để quyết định kiểu gộp. Cuối cùng ta cũng có thể dùng lệnh sau để gộp commit:

```
$ git reset --soft <commit-hash-code>
$ git add .
$ git commit -m"New commit"
```

Với commit-hash-code là mã hash của commit trước đó mà ta muốn gộp lại từ commit cuối cùng đến commit chỉ định.

#### 10\. Phân biệt giữa git reset, reset --soft, reset --hard

```
$ git reset <commit-hash-code>
```

Sẽ di chuyển HEAD về phía commit được chỉ định nhưng vẫn giữ nguyên trạng thái thay đổi của các file và đồng thời loại bỏ các file đó khỏi trạng thái staged

```
$ git reset --soft <commit-hash-code>
```

Tương tư như git reset nhưng toàn bộ các fle vẫn giữ được trạng thái staged.

```
$ git reset --hard <commit-hard-code>
```

Tương tự như 2 lệnh trên nhưng toàn bộ sự thay đổi của các file sẽ bị loại bỏ hoàn toàn nên hãy chú ý khi dùng lệnh này để tránh rơi vào trường hợp bao nhiêu công sức đổ xuống sông xuống biển
![](https://twemoji.maxcdn.com/2/72x72/1f604.png)

#### Thế nào là cherry-pick?

- Bạn có thể hiểu cherry-pick cũng có một số điểm tương đồng với merge và rebase là lấy thay đổi từ một branch này và gộp vào branch khác. Nhưng điểm khác nhau lớn nhất giữa cherry-pick và merge, rebase là cherry-pick chỉ gộp một commit được chỉ định từ một nhánh khác vào nhánh hiện tại trong khi merge và rebase sẽ gộp toàn bộ các commit lại. Để sử dụng cherry-pick, ta cần xem lại log các commit sau đó lấy mã hash của commit cần được cherry-pick và checkout sang nhánh cần được gộp commit của mã hash kia và thực hiện lệnh:

```
$ git cherry-pick <commit-hash-code>
```

- Một hình ảnh minh họa cho cherry-pick:
  ![](https://viblo.asia/uploads/58fb9676-c97d-4ad8-8431-172c129cdad1.png)
  - Giả sử ta muốn lấy commit C từ branch master và gộp vào branch cherry-pick
  - Sau khi thực hiện lệnh cherry-pick như đề cập ở trên, đây sẽ là kết quả ta thu được
    ![](https://viblo.asia/uploads/4db578c2-aa4c-44fa-a6ae-4af4ec1d548c.png)

  - Như ta có thể thấy commit C từ branch master được gộp vào với branch cherry--pick dưới tên commit là C'

#### Git flow là gì?

- Git flow là một quy trình làm việc với git được thiết kế bởi Vincent Driessen. Git flow đưa ra một mô hình phân nhánh giúp hỗ trợ việc quản lý các dự án lớn dễ dàng hơn. Sơ đồ tổng quan:
  ![](https://viblo.asia/uploads/c3f681b2-36bb-4dda-9831-64770c5bdbfb.png)

##### Các branch trong gitflow:

- Master branch: là branch dùng cho sản phẩm chính thức. Đây luôn là branch ổn định nhất và nó chưa lịch sử các lần release của dự án
- Develop branch: là nhánh dùng cho sản phẩm trong quá trình phát triển
- Feature: mỗi tính năng mới cho sẩn phẩm sẽ được tạo và phát triển trên một branch mới với tên quy ước feature/tên*branch. Các **feature** này sẽ tạo ra từ **develop branch** và khi được hoàn thiện sẽ được gộp trở lại với **develop branch** (\_Lưu ý: các Feature không được phép gộp trực tiếp với master branch*)
- Release: khi **develop branch** đã có đủ số tính năng cần thiết để có thể release, ta có thể tạo branch mới với tên quy ước release/tên_version. Branch này sau khi được tạo xong sẽ tiến hành merge nó với đồng thời cả **master branch** và **develop branch**
- Hotfix branch: khi sản phẩm trên **master branch** của chúng ta gặp phải trục trặc và cần có bản vá ngay lập tức thì ta sẽ tạo ra **hotfix branch**. Branch này tương tự như **release branch** nhưng nó được tạo ra từ **master branch** thay vì từ **develop branch** như release (\*Chú ý **hotfix branch** cũng cần được gộp lại với **master branch** với **develop branch**)

##### Các lệnh trong gitflow

- Để khởi tạo một git-flow cho một project, ta dùng lệnh sau

  ```
  $ git flow init
  ```

  - Lệnh này sẽ tạo ra hai branch ban đầu là master và develop

- Để bắt đầu một feature ta dùng lệnh

  ```
  $ git flow feature start <tên-feature>
  ```

  - Sẽ tạo ra một branch mới có tên dạng `feature/<tên-feature>`

- Sau khi feature đó được thực hiện xong, ta có thể công bố feature đó lên remote server để mọi người cùng có thể cập nhật bằng cách gõ lệnh:
  ```
  $ git flow feature publish <tên-feature>
  ```
- Để tiến hành gộp branch đó vào **develop branch** ta dùng lệnh:
  ```
  $ git flow feature finish <tên-feature>
  ```
- Để tạo một bản release ta dùng lệnh:
  ```
  $ git flow release start <verion-no>
  ```
- Để tiến hành merge bản release đó vào **master branch** và **develop branch** ta dùng lệnh:
  ```
  $ git flow release finish <version-no>
  ```
- Để tạo một bản hotfix ta dùng lệnh:
  ```
  $ git flow hotfix start <tên-hotfix>
  ```
- Sau khi bản hotfix hoàn thiện ta có thể tiến hành merge lại với **master branch** và **develop branch** như sau:
  ```
  $ git flow hotfix finish <tên-hotfix>
  ```

### Kết luận

Bài viết ở trên chủ yếu giới thiệu cho mọi người về các khái niệm trong git cũng như cách sử dụng nó trong công việc thường ngày của mình một cách hiệu quả hơn. Cám ơn bạn đã theo dõi.
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-ve-mot-so-khai-niem-trong-git</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-ve-mot-so-khai-niem-trong-git</guid>
            <pubDate>Thu, 26 Apr 2018 14:39:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Progressive Web App tương lai của nền tảng web]]></title>
            <description><![CDATA[
## Tóm tắt

"Mobile first" hay "Think mobile" là một trong những hot trend mà chúng ta thường được nghe gần đây, khi mà số lượng thiết bị di động và số lượng người sử dụng các thiết bị di động ngày càng lớn. Nhưng think như thế nào cho đúng là điều cần làm rõ. Bài viết này sẽ cung cấp thông tin cho bạn về cách tư duy theo [PWA](https://en.wikipedia.org/wiki/Progressive_web_app).

> PWA không hoàn toàn là một giải pháp về công nghệ, mà là một tập các tiêu chuẩn được định nghĩa cho các ứng dụng web hướng theo, nhằm mang lại trải nghiệm tốt nhất cho người dùng, với sự hỗ trợ của browser về các API có liên quan như Service Worker, Push Notification v.v...

Trước khi bàn đến các tiêu chuẩn của PWA và cùng tìm hiểu các nghiên cứu mới về trải nghiệm của người dùng, các công nghệ hứa hẹn... Chúng ta sẽ cùng điểm qua một vài cảm nhận và suy nghĩ trong lược sử thời gian của ngành công nghệ web. Bên cạnh đó, chúng ta cũng sẽ nói đôi chút về Native App đến Hybird App và từ đó hiểu thêm về lý do ra đời của PWA.

Bài viết sẽ cung cấp cho chúng ta cái nhìn tổng quát về các vấn đề ưu nhược khi phát triển ứng dụng web theo các tiêu chuẩn của PWA, những khó khăn mà lập trình viên có thể gặp phải, hơn nữa, bài viết sẽ cung cấp view nhìn để có thể scale được một dự án PWA về yếu tố con người cũng như về chi phí, hạ tầng.

Bài viết khá dài, nên bạn có thể phải kiên nhẫn đọc hết những phần bên dưới, hoặc lướt qua các các heading để có thể chọn các đề mục mà mình tâm.

## Một vài cảm nhận về nền tảng Web & App.

Từ Web App đến Single Page (Web) Application

Bạn có thể tìm thấy các nét sơ lược về lịch sử của trong ngành web theo [Wikipedia](https://vi.wikipedia.org/wiki/World_Wide_Web) với các cột mốc quan trọng ở đây [evolutionoftheweb](http://www.evolutionoftheweb.com/?hl=en), và theo quan điểm cá nhân của tác giả thì trong hơn 10 năm qua có thể kể đến hai nhóm sự kiện tiêu biểu:

1.  Sự ra đời của các browsers chịu thay đổi và mau lẹ trong sự thay đổi như Firefox, Chrome. Vì chính sự ra đời này, các tiến bộ mới được nhanh chóng cài đặt, phổ biến đến cộng đồng lập trình viên và người sử dụng.
2.  Sự ra đời của AJAX có thể nói là cột mốc đáng chú ý nhất của nền tảng web, đã có thời chúng ta đi đâu cũng nghe người ta nói về điều này như là một phương tiện mang đến sức mạnh to lớn cho bất kì một website nào. Một trong các ứng dụng mang đậm dấu ấn của sự thay đổi này là Gmail, nó thay đổi cách chúng ta suy nghĩ về một phần mềm quản lý email trên nền web.

Trình duyệt mới đi kèm công nghệ tiên tiến, chúng biến công việc phát triển website, ứng dụng web trở nên thú vị dành cho lập trình viên và không gian sáng tạo không giới hạn dành cho designer.

Cùng với sự bùng nổ của internet, cho đến sự ra đời của AJAX, đã khiến các website từng vốn chậm chạp giờ trở nên nhanh hơn, có hiệu năng và trải nghiệm giống như một phần mềm trên desktop và được gọi là một Single Page Application (SPA).

### Từ Native App đến Hybird App

Ngay từ những ngày bắt đầu, các ứng dụng di động đã tạo ra những điều "thật không thể tin nổi" về sự trải nghiệm đa dạng. Các thiết bị di động với cấu hình ngày càng mạnh mẽ với chu kỳ nâng cấp 1 đến 2 lần mỗi năm và người sử dụng ngày càng chịu móc hầu bao, bỏ thời gian cho các ứng dụng trên di động của mình.

Bên cạnh đó, các nền tảng di động còn có sự phong phú về chủng loại, phù hợp túi tiền, sở thích của người tiêu dùng đã nhanh chóng trở thành mảnh đất màu mỡ để các nhà khởi nghiệp nghĩ về các ứng dụng nhằm tạo kết nối giữa mọi người, giải quyết công ăn việc làm, nhu cầu học tập giải trí, cải thiện cuộc sống, chăm sóc sức khoẻ... như Grab là một ví dụ về ứng dụng di động đã tạo ra không chỉ việc làm cho cho sinh viên, mà căn bản là đã thay đổi cái nhìn và thói quen truyền thống về ngành dịch vụ xe ôm.

Có thể kể đến các nền tảng huy hoàng một thời như: Symbian của đế chế Nokia, Windows Phone với điện thoại O2 một thời làm mưa gió, dâu đen Blackberry những ngày hoàng kim đình đám... cho đến khi chỉ còn hai cái tên thống trị thị trường rộng lớn và màu mỡ này là iOS, Android như chúng ta đã biết. Dù vậy, trong trò chơi vương quyền vốn nguy hiểm này, tuy chưa biết kẻ nào sẽ chiến thắng cuối cùng, song có rất nhiều ông lớn vẫn không cam chịu, không dễ dàng bỏ cuộc chơi và tham vọng của mình.

Và ngày nay, các ứng dụng phát triển trên hai nền tảng Android của Google, và iOS của Apple đã lên đến những con số khổng lồ tạo ra một cộng đồng người sử dụng trung thành. Điều đó cũng có nghĩa là nếu bạn muốn xây dựng ứng dụng Native App bạn cũng phải sẵn sàng phát triển hai phiên bản khác nhau. Thật không may là chi phí phát triển cho hai nền tảng này không hề nhỏ, khi mà bạn biết rằng chi phí đó kèm theo việc maintain theo thời gian là một ác mộng, và phần lớn code của chúng gần như là không thể tái sử dụng cho nhau.

Đó là lúc người ta nghĩ đến điều làm thế nào để có thể viết một lần và chạy trên nhiều nền tảng, và có nhiều giải pháp cho điều này, ví dụ:

1.  Các nền tảng build/compile ra Native App như: (a) Xamarin, bạn có thể code với C# và build ra các nền tảng khác nhau như Android, iOS, Windows Phone. (b) React Native, bạn có thể Javascript để build ra Android, iOS.
2.  Các nền tảng cho phép porting các trang web hiện có, hoặc xây dựng app trên nền tảng html/css/js để build ra các ứng dụng chạy trên cả Andriod, iOS như PhoneGap, gọi là Hybird App bằng cách cung cấp bên dưới một Native App như là một Brigde Software để giúp ứng dụng có thể tương tác với phần cứng bên dưới.

Hybird app ra đời tận dụng được những ưu điểm của nền tảng web, tận dụng nguồn nhân lực to lớn từ nền tảng này, giờ đây dân lập trình web cũng có thể viết app, porting ứng dụng của mình lên nền tảng mobile một cách dễ dàng.

Thật vi diệu phải không?

## Các so sánh giữa Web và App

### Web App

#### Ưu điểm

1.  Chạy được trên nhiều nền tảng, từ mobile đến desktop, từ Andriod đến iOS, từ Windows đến Linux v.v...
2.  Người dùng không phải cài đặt ứng dụng nặng nề có khi hàng trăm Mb, không phải nâng cấp version, chúng luôn được cập nhật mới nhất.
3.  Có thể searchable từ Google
4.  Scale ứng dụng dễ dàng với một cộng đồng lập trình viên năng động và đông đảo dễ thuê mướn.

#### Nhược điểm

1.  Không thể can thiệp được sâu vào hệ thống mà phụ thuộc vào trình duyệt của người dùng.
2.  Các chức năng về offline có giới hạn như phụ thuộc vào trình duyệt có support hay không.
3.  Nhiều trình duyệt và các phiên bản khác nhau bạn sẽ tốn thời gian để đảm bảo chúng chạy giống nhau.

> Bonus: Bạn có thể xem qua hình bên dưới để nhìn thấy những gì mà Chrome có thể support

![](https://cdn-images-1.medium.com/max/800/0*SRxt2a6QvqkoUK5A.png)

### Native App

#### Ưu điểm

1.  Có thể sử dụng hầu hết các tính năng của thiết bị như camera, la bàn...
2.  Cảm giác và cái nhìn (feel and look) thân thiện với người dùng vì sử dụng các control native của thiết bị, do hệ điều hành của thiết bị cung cấp.
3.  Do sử dụng Native App, nên khi hệ điều hành của thiết bị được nâng cấp (ví dụ khi nâng cấp lên IOS 10, thì sẽ thừa kế được)
4.  Có thể work offline, truy cập vào danh bạ v.v...
5.  Có thể tận dụng các chức năng như tăng tốc nên tốc độ của Native App sẽ có peformance tốt.

#### Nhược điểm

1.  Chi phí phát triển cao, phải gần như làm cho 2 bản dành cho iOS, Android
2.  Phải optimize cho các dòng điện thoại không phải flagship
3.  Phải cài đặt, không thể được searchable
4.  Dung lượng cài đặt rất lớn chiếm một khoảng đáng kể đặc biệt với các thiết bị có bộ nhớ thấp, việc cài đặt còn làm tăng chí phí về mặt dung lượng sử dụng 3G và người sử dụng có thể sẽ phải cân nhắc thời điểm tải.
5.  Người dùng sau khi đã cài đặt thường cũng sẽ không nhớ tới ứng dụng và họ cũng dễ dàng remove vì chiếm tài nguyên và cảm thấy chật chội.
6.  Thời gian submit và release rất lâu phải chờ đội ngũ Reviewers của App Stores duyệt qua. Điều đó có nghĩa là, khi có một bug xảy ra việc fix bug để giảm đi tác động đến khách hàng là không thể thực hiện ngay được. Điều đó cũng có nghĩa là chi phí dành cho việc testing cũng trở nên lớn hơn.

### Hybird App

#### Ưu điểm

1.  Viết một lần và chạy trên nhiều nền tảng, chúng ta chỉ code một lần cái app của mình, phần còn lại cái cầu nối (Bridge Software) lo.
2.  Với các ứng dụng có porting từ web, hoặc có tính năng giống như mobile web, liên quan nặng về xử lý dữ liệu thì loại ứng dụng này là phù hợp.
3.  Có thể chạy background, offline.

#### Nhược điểm

1.  Peformance kém: Có thể nói các ứng dụng Hybird gặp phải các vấn đề lớn về performance, bởi phải chạy trên một bridge app được viết tất cả trong 1 cồng kềnh, chúng thật sự gần như là một một trình duyệt di động mở rộng (Extended Mobile Browser) có bổ sung thêm các API.
2.  Khó customize và optimize phù hợp với chức năng của mình, đặc biệt cho các ứng dụng như Game.
3.  Các API vẫn chưa hỗ trợ đầy đủ để theo kịp sự phát triển của phần cứng và sự đa dạng của các nền tảng khác nhau.

### PhoneGap - Nền tảng nổi bật của Hybird App

[PhoneGap](https://phonegap.com/) là một đại diện tiêu biểu cho nhóm nền tảng Hybird App, được phát triển bởi [Adobe System](http://www.adobe.com/) dùng để phát triển mobile app, nhưng không đòi hỏi user có kiến thức về Andriod, hay iOS, mà chỉ cần kiến thức về web như hình minh họa bên dưới.

![](http://docplayer.org/docs-images/24/4232987/images/25-0.png)

## Bảng thống kê so sánh các công nghệ

Nếu bạn cảm thấy quá mệt và loạn vì đống chữ ở phía trên, thì có thể nhìn vào bảng tổng hợp bên dưới để có cái nhìn nhanh về so sánh tương đối giữa các nền tảng này.

![](http://nuvemconsulting.com/wp-content/uploads/2013/05/file-295453993.jpg)

## Sự ra đời của PWA

#### Các thống kê thú vị

1.  5 tỉ thiết bị đã và sẵn sàng cho nền tảng web.
2.  Có hơn 1 tỉ trang web trên thế giới.
3.  Tới quý 2, 2015, cho thấy 90% thời gian người sử dụng điện thoại ở Mỹ là tương tác với Native App, chỉ có 10% sử dụng browser. Nhưng điều này không có nghĩa là bạn cần phải xây dựng một Native App cho ứng dụng của mình, vì phần lớn thời gian người sử dụng bỏ ra lại cho những App phổ biến như Facebook, Twitter, YouTube, Instagram v.v..
4.  Người dùng download app dễ dàng nhưng cũng dễ dàng gỡ bỏ app, bởi phần lớn các app được chạy các chương trình marketing hấp dẫn để thu hút người cài đặt, nhưng vì điện thoại rất dễ bị hết dung lượng nên user sẽ gỡ những app mà họ ít khi dùng đến. 65% người sử dụng điện thoại không hề download ứng dụng mới hàng tháng. Điều này có nghĩa là chi phí cài đặt ứng dụng ngày càng cao.
5.  Tất cả những điều này cho thấy mobile web vẫn còn rất quan trọng. Nhưng lại có thêm một nghịch lý là, trong khi tỉ lệ người dùng mobile web so với tỉ lệ người dùng desktop web tăng trưởng rất nhanh và cao, nhưng tỉ lệ convert thành giá trị như đơn hàng lại rất thấp. Một phần trong đó là vì các ứng dụng web hiện tại không được optimize cho mobile cho các vấn đề về UX/UI và trong điều kiện mạng chậm.
6.  Một website có thể tải về dưới 3s người sử dụng sẽ happy với website của bạn, và có nghĩa là tỉ lệ rời bỏ thấp, đơn hàng sẽ tăng lên. Còn từ 3s-10s thì người sử dụng chỉ có thể nói là sẽ cố kiên nhẫn. Quá 10s người sử dụng sẽ rời bỏ trang web của bạn vì họ nghĩ nó không hoạt động.

![](https://infographic.statista.com/normal/chartoftheday_3821_mobile_device_usage_n.jpg)

> (Phần viết này dựa trên sự suy đoán của tác giả) Sự phát triển mạnh mẽ của Native App, thách thức sự thống trị của Google Search Engine, nếu người sử dụng dùng app, họ sẽ không còn cần vào Google để tìm kiếm thông tin nữa và sản phẩm cốt lõi của Google sẽ gặp rất nhiều vấn đề, mà có thể kể đến là sự sụt giảm người sử dụng do các thông tin không còn đưa lên web để có thể crawl được, và kèm theo đó là sự sụt giảm về khả năng kiếm tiền của Google. Tác giả nghĩ đó cũng có thể là lý do khiến Google phải đẩy mạnh phát triển PWA để hỗ trợ cho nền tảng web, níu giữ người sử dụng ở lại nền tảng này.

Có thể nói, sự ra đời của Hybird App là một cộc mốc khá quan trọng thể hiện rõ cách nhìn và sự mong mỏi của các nhà phát triển trong việc optimize chi phí. Và câu hỏi đặt ra là, tại sao các trình duyệt bản thân nó không nên là một Bridge Software cung cấp các API để các ứng dụng web có thể truy cập vào phần cứng của thiết bị. Do vậy, chúng ta có thể tin rằng, điều đó sắp tới sẽ là một phần trong những thay đổi, bổ sung của các browsers.

Các tiêu chí về [PWA](https://developers.google.com/web/progressive-web-apps/):

- Progressive - Hoạt động cho tất cả mọi người, không liên quan tới việc lựa chọn browser, bởi chúng được xây dựng với những sự cải tiến như là một nguyên lý cốt lõi.
- Responsive - Có thể hoạt động tốt trên mọi thiết bị như desktop, mobile, tablet, với mọi kích thước màn hình.
- Connectivity independent - Có thể hoạt động ngay cả khi offline (dựa trên Service Worker) và hoạt động tốt trong điều kiện network chậm.
- App-like - Sử dụng app-shell để cung cấp các chức năng định hướng và sự tương tác giống như app.
- Fresh - Luôn update phiên bản mới nhất (dựa trên Service Worker)
- Safe - Tất cả phải được phục vụ thông qua HTTPS để tránh bị nghe lén và đảm bảo nội dung không bị giả mạo.
- Discoverable - Có để được nhận dạng như là ứng dụng (dựa trên Service Worker, và W3C manifests ) và cho phép Search Engines có thể tìm thấy.
- Re-engageable - Tạo ra sự tương tác lại ứng dụng dễ dàng thông qua các chức năng chẳng hạn như Push Notification.
- Installable - Có thể Add to Homescreen để giữ lại ứng dụng trên màn hình.
- Linkable - Dễ dàng share, chia sẽ điều mình muốn đến với người khác thông qua URL mà không cần phải cài đặt.

> 10 tiêu chí nhận dạng một ứng dụng được xem là PWA với sự giúp đỡ của Google Translator.

PWA không hoàn toàn là một giải pháp về công nghệ, mà là một tập các tiêu chuẩn được định nghĩa cho các ứng dụng web hướng theo nhằm mang lại trải nghiệm tốt nhất cho người dùng, với sự hỗ trợ của browser về các API có liên quan như Service Worker, Push Notification v.v...

Điều ý nghĩa của một ứng dụng theo tiêu chuẩn của PWA không phải là nó có thể tận dụng được sức mạnh từ phần cứng của người sử dụng hay không, như cách mà nhiều lập trình viên lần đầu nghe qua quan tâm, mà là nó giúp cho các ứng dụng web trở nên tốt hơn từ góc độ performance đến những cải tiến về UX/UI.

Để hiểu được PWA là gì, cần phải nhìn về Native App và Web App ở góc độ ưu nhược điểm của từng đối tượng. Và khi nhìn thấy nhược điểm của chúng, cũng là lý do đầy đủ để chúng ta hiểu PWA ra đời như là một giải pháp hoàn thiện cả hai nền tảng này bằng cách mang ưu điểm của cả hai.

#### Nghiên cứu mới về trải nghiệm người sử dụng

Ngày trước, một website tốt là một website có **Page Speed** cao, trong thời gian vài giây nó phải tải toàn bộ nội dung về thiết bị, tiếp theo đó trình duyệt hiển thị giao diện, cuối cùng là cho người dùng tương tác. Điều đó có nghĩa là, trong thời gian tải toàn bộ nội dung của website, người dùng chỉ nhìn thấy một màn hình trắng tinh khôi, hoặc là một dấu hiện đang tải trang với animation nhàm chán và có thể họ sẽ bắt đầu thấy mất kiên nhẫn trong các điều kiện như network bị chậm.

Theo nghiên cứu của Google, một website tốt phải cho một sự trải nghiệm liên tục không gián đoạn, nhằm thuyết phục người dùng tin rằng là nó đang hoạt động để họ không rời bỏ đi chỗ khác, cũng như không cảm thấy phải khó chịu khi phải chờ đợi.

Sự tải trang, các nội dung cần thiết để có thể tạo ra một ứng dụng hoàn chỉnh có thể chia thành nhiều giai đoạn phù hợp với nhu cầu và khả năng tương tác của người dùng. Ứng dụng không cần phải load tất cả mọi thứ lên sẵn trong khi có rất nhiều tính năng người dùng có thể chưa cần dùng tới hoặc là ít khi dùng tới.

#### Các giai đoạn trải nghiệm cơ bản

1.  **First Paint** - Định nghĩa việc website cần tải thật nhanh để người sử dụng thấy nó hoạt động chứ không phải là một màn hình trắng tinh vô hồn.
2.  **First Meaningful Paint** - Định nghĩa về việc website cần phải hiển thị những điều có ý nghĩa để người sử dụng có thể nhìn thấy ví dụ như những hình ảnh banner, video v.v... gọi là **Hero Element**
3.  **Time to Interactive** - Định nghĩa về cách làm thế nào người sử dụng có thể bắt đầu tương tác với website của bạn cũng trong thời gian nhanh nhất, có thể thao tác với điều họ cần, mà không cần phải đợi tải hoàn toàn trang, ví dụ như họ đã có thể bắt đầu với search box, hoặc xem video, đi vào sản phẩm chi tiết.

> Google đã phát triển một công cụ gọi là Lighthouse để phân tích website của bạn theo các tiêu chí này.

## Tại sao PWA có thể trở thành tương lai của ngành web

Như đã nói, việc mobile web vẫn có những thế mạnh mà không thể bị đánh bại, bởi những giá trị cốt lõi chưa thể bị thay thế trong tương lai gần như đã đề cập vốn rất chi tiết ở trên.

Nhưng với sự thay đổi nhanh về phần cứng cũng như về hệ sinh thái các phần mềm từ hệ điều hành cũng như Native App trên các thiết bị di động, đòi hỏi các ứng dụng web phải thay đổi để thích nghi với sự kỳ vọng cao hơn về nhu cầu trải nghiệm của người dùng. Rất khó để chấp nhận với một thiết bị đẹp, cấu hình mạnh mẽ, và đắt đỏ lại tải một trang web lên có vẻ chậm chạp, hiệu năng kém và thiết kế cẩu thả.

Những lý luận và tư tưởng của PWA là tuyệt vời và có thể áp dụng để làm cho sản phẩm của chúng ta tốt hơn, điều đó hứa hẹn một thị trường hấp dẫn về các website đã có cần phải thay đổi và các website mới cần phải được build trên các nền tảng công nghệ mới và tư tưởng mới.

Nếu chúng ta không nắm bắt đúng thời điểm, đúng điểm rơi của công nghệ, chúng ta sẽ bị bỏ lại phía sau, lạc hậu và khi phần lớn khách hàng quay lưng đi với mình thì đã muộn. Có rất nhiều bài học về điều này như của Nokia, của Yahoo... có thể sự đổ vỡ của các tập đoàn khổng lồ này đến từ nhiều nguyên nhân, nhưng trong số đó chắc chắn phần lớn từ các sản phẩm thiếu sáng tạo, kém hấp dẫn đối với người tiêu dùng, thậm chí không muốn nói là lạc hậu trong tồn tại của nó so với đối thủ.

## Những khó khăn khi ứng dụng PWA

1.  Nguồn nhân lực về PWA hiện tại đang thiếu hụt mà chưa dễ dàng được khoả lấp trong thời gian ngắn sắp tới, do các công nghệ và nền tảng vẫn còn mới. Tác giả sẽ viết một bài sắp tới để nói sâu hơn về vấn đề này cũng như giải pháp khắc phục cho các tổ chức muốn phát triển sản phẩm theo tư tưởng của PWA.
2.  Sự thiếu hỗ trợ đầy đủ từ các nhà phát triển chẳng hạn như từ Apple, nhưng điều này đang và sẽ sớm được khắc phục, bạn có thể tham khảo ở đây để thấy tính năng này [đang được phát triển](https://webkit.org/status/#?search=service%20workers) bởi Apple
3.  Những lo ngại của cộng đồng developer do cách hiểu sai là nó không thể sử dụng được phần cứng của thiết bị.
4.  Các lãnh đạo, cấp trên vẫn chưa thấy được nhiều value để chuyển đổi từ những website truyền thống sang nền tảng mới. Nhưng các con số và thống kê cũng cho thấy việc chuyển đổi theo tương tưởng và mô hình công nghệ mới hơn là điều không thể nào né tránh.

## Những nhà phát triển tiêu biểu

Bạn có thể nhìn qua các website này để tìm hiểu các website đó hoạt động như thế nào để tham khảo cho website của mình.

Ở nước ngoài có thể kể đến:

1.  Flipkart - Ấn độ, xem chi tiết [tại đây](https://developers.google.com/web/showcase/2016/flipkart).

- Với phiên bản PWA mobile thời gian user ở lại website là: 3.5 phút so với phiên bản mobile cũ không PWA là 70s.
- 3x tăng thời gian user ở lại website.
- 40% tỉ lệ tương tác tăng thêm.
- 70% nhiều hơn CR đến từ Add to Homescreen.
- 3x giảm tỉ lệ sử dụng dữ liệu.

1.  Aliexpress - Trung Quốc, xem chi tiết [tại đây](https://developers.google.com/web/showcase/2016/aliexpress).

- 104% CR cho người dùng mới tất cả trình duyệt; 82% CR tăng thêm trên iOS
- 2X số trang mà người sử dụng xem thêm với mỗi session cho tất cả trình duyệt.
- 74% tăng thêm thời gian người sử dụng với mỗi session tất cả trình duyệt.

Ở thị trường Việt Nam, các site nổi tiếng có thể kể đến:

1.  Tiki - đã released version PWA vào mùa hè 2017
2.  Sendo - dự kiến released vào cuối năm 2017

## PWA dưới góc nhìn cho doanh nghiệp

Đối với doanh nghiệp điều quan trọng là giảm chi phí, tăng doanh thu và lợi nhuận thì việc phát triển một ứng dụng PWA với các phương pháp luận và các giải pháp mới khiến cho chi phí phát triển dự án xét về lâu dài càng giảm, và lợi nhuận ngày càng được tối đa hoá.

Sản phẩm theo nền tảng này được thừa hưởng một hệ thống lý luận và phương pháp lập trình tốt để dễ dàng scale, maintain, improve, và thay đổi trong tương lai. Điều đó có nghĩa là các tính năng được thêm mới dễ dàng với chi phí thấp, rủi ro về lỗi được giảm.

## PWA dưới góc nhìn cho lập trình viên

### Bạn cần học gì, làm gì.

Nếu bạn chưa từng biết làm thế nào thì đọc bài viết này [Làm thế nào để trở thành Frontend developer](https://www.linkedin.com/pulse/l%C3%A0m-th%E1%BA%BF-n%C3%A0o-%C4%91%E1%BB%83-tr%E1%BB%9F-th%C3%A0nh-m%E1%BB%99t-frontend-developer-phu-tran-phong/)

### Khả năng scale của dự án PWA

PWA đã được đưa ra từ cách đây từ vài năm trước, nhưng đây là điểm rơi để các ứng dụng có thể chuyển đổi sang nền tảng này, do sự phát triển vô cùng mạnh mẽ của các framework, thư viện được xây dựng và phát triển trên nền Nodejs, đáng để kể đến như React, Angular, Polymer dựa trên trên các công cụ bundle như Grunt, Gulp, Webpack... Chúng khiến cho việc tổ chức, tối ưu code được dễ dàng, tổ chức team hiệu quả và tránh được các rủi ro. Khả năng scale của dự án là dễ dàng cả về yếu tố con người, vật lý, và chi phí.

Không có sự hỗ trợ về các công cụ phát triển phần mềm từ hệ sinh thái của Nodejs, rất khó để có thể ứng dụng được các triết lý mà PWA đã đề ra, vì có thể dự án sẽ có chi phí phát triển cực lớn và rủi ro phát sinh theo nó là không thể nào dự đoán hay kiểm soát.

### Từ góc nhìn outsourcing

1.  Làm thế nào để decoupling các task chức năng của ứng dụng, sao cho khi có nhiều tính năng thì có thể đẩy người vào, vì nếu không thể decoupling được tính năng, các chức năng được code độc lập, mỗi người làm một phần thì khi càng push người vào, thì sự phát triển của dự án chưa chắc tương xứng.
2.  Giúp debug dễ dàng, khi có vấn đề gì xảy ra không được như mong đợi.
3.  Dự án dễ testable, có thể viết chức năng test một cách dễ dàng.

### Từ góc nhìn production

1.  Bao gồm cả các yếu tố của outsourcing.
2.  Điều quan tâm là việc tính scale như thế nào khi có sự tăng tưởng của người sử dụng, đặc biệt là khi các phương pháp xây dựng một ứng dụng PWA phụ thuộc nặng nào Nodejs ngay cả khi bạn dùng framework/library nào đi chăng nữa thì các công cụ để xây dựng và tổ chức source code, build source code, debug sẽ cần đến gulp/grunt hoặc là Webpack. Nodejs về hiệu năng có thể được mọi người nghĩ là kém so với các ngôn ngữ khác và khó scale. Nhưng cái nhìn đơn giản đó là chưa đúng. Chúng ta cần nhìn về ứng dụng với các công nghệ được build stack với nhau như: Nginx, Redis, Database v.v... một ứng dụng chạy nhanh cần một thiết kế tốt, có thể hoạt động ổn định và scale theo chiều ngang chứ không nên được thiết kế chỉ dựa vào ngôn ngữ.
3.  Ở góc nhìn production, các kỳ vọng về sản phẩm, về chi phí, thời gian, con người đều có đủ phương pháp lý luận và tổ chức để có thể đi đến việc dễ dàng kiểm soát và đạt được các tiêu chí đề ra.

> Ở một bài viết tiếp theo, chúng ta sẽ xem xét một ứng dụng open source PWA mẫu, để tìm hiểu các công nghệ được stacked như thế nào.

## Kết luận

Qua một bài viết khá dài, tác giả hi vọng sẽ mang lại cho bạn một trong những bài viết đầy đủ và chi tiết nhằm cung cấp các view nhìn mang giá trị tham khảo về một trong những nền tảng rất hứa hẹn thay đổi tương lai của ngành lập trình và phát triển ứng dụng web.

Bài viết sẽ không tránh khỏi các thiếu sót mang tính chủ quan của tác giả và cả các sai sót về các thông số, cách trình bày, bố cục, lỗi chính tả... nên hi vọng bạn đọc thông cảm bỏ qua.

Nếu bạn có bất kì câu hỏi hay phản biện bổ sung nào vui lòng để lại comment bên dưới.

Rất cảm ơn quý đọc giả và các bạn vì đã kiên nhẫn đọc hết bài viết.

## Tham khảo

1.  [Getting started with Progressive Web Apps](https://addyosmani.com/blog/getting-started-with-progressive-web-apps/)
2.  [Mobile Web Hay Mobile App?](https://www.linkedin.com/pulse/mobile-web-hay-app-bui-quang-tinh-tu/)
3.  [Why "Progressive Web Apps vs. native" is the wrong question to ask](https://medium.com/dev-channel/why-progressive-web-apps-vs-native-is-the-wrong-question-to-ask-fb8555addcbb)
]]></description>
            <link>https://hungvn.com/blog/progressive-web-app-tuong-lai-cua-nen-tang-web</link>
            <guid isPermaLink="true">https://hungvn.com/blog/progressive-web-app-tuong-lai-cua-nen-tang-web</guid>
            <pubDate>Wed, 25 Apr 2018 18:15:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Biên niên sử về bố cục trong trang web]]></title>
            <description><![CDATA[
## Giới thiệu

Bài viết bàn về công nghệ các lập trình viên web áp dụng để thiết kế bố cục trong trang web (website layout) - qua các thời kỳ: table, float, block-inline, flexbox, JS, Twitter Bootstrap và grid.

## Thời trước 2010

Đây là thời kỳ tối cổ với công nghệ website, người ta hầu như ít đầu tư giao diện web, việc dựng bố cục, xương sườn cho trang web sử dụng thẻ HTML `<table>` là chính.

![](http://namluu.com/wp-content/uploads/2018/01/yyou-1.jpg)
![](http://namluu.com/wp-content/uploads/2018/01/yyou-2.jpg)

Layout Table rất đơn giản, với 1 table 3 rows, 1 row làm header, 1 row làm content, cái cuối làm footer.
**Nhược điểm** của layout table là: rất khó khăn khi tái cấu trúc lại bố cục, khó khăn khi thiết kế vì table mục đích chính là biểu diễn dữ liệu. Các cột có chiều rộng cố định không linh hoạt, nan giải khi xử lý trên nhiều kích thước màn hình.
Năm 2012, khi mới ra trường, công việc đầu tiên của tôi là đập bỏ và thay thế các layout dạng table. Tới nay thì không còn ai nghĩ tới việc việc thiết kế layout bằng table nữa.
Tuy nhiên còn rất nhiều tài liệu trong các trường đại học chưa được cập nhật nên đừng ngạc nhiên khi bạn được dạy thiết kế layout bằng thẻ table nhé.

## Từ 2012 - Float lật đổ Table

Khi layout table quá bất cập thì giải pháp thay thế tuyệt vời nhất trong giai đoạn này là dùng các thẻ HTML `<div>` kết hợp với CSS property: Float.
Các khối [block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block/) sẽ được tách ra và "trôi" qua trái, phải, tùy theo ý muốn của lập trình viên.

![](http://namluu.com/wp-content/uploads/2018/01/stopdesign-float.jpg)

**Ưu điểm**: code sạch sẽ hơn khi dùng table, dễ thay đổi chỉnh sửa, linh hoạt trên nhiều kích thước màn hình.
**Khuyết điểm**: dễ bị "vỡ trang", nếu lập trình viên chưa làm chủ được float, chưa biết cách sử dụng các tuyệt chiêu như: clear, overflow... Lạm dụng float trên các bố cục phức tạp.

## 2013 - thời của các CSS Frameworks

Vào giai đoạn này, các CSS Frameworks như [Bootstrap](https://getbootstrap.com/), [Foundation](https://foundation.zurb.com/),...
Các thư viện này hỗ trợ rất đắc lực cho các lập trình viên, dễ sử dụng, dễ thiết kế bố cục, chỉ cần gắn các class phù hợp. Bên cạnh đó chúng còn liên tục cập nhật và cải tiến không ngừng.
Phải nói trong thời gian đó, các CSS Frameworks nhất là Bootstrap, trở thành 1 xu hướng tới mức khi đi phỏng vấn code web, chắc ăn thế nào họ cũng hỏi bạn vài câu.
Để dùng tốt Bootstrap, bạn phải học các khái niệm như Grid View System, học thuộc các class thông dụng , tận dụng tối đa các chức năng có sẵn, người giỏi nhất lúc này là người code CSS, style ít nhất.
Hạn chế của các CSS Framework này là quá kềnh càng nếu ta không tận dụng hết chức năng (có thể khắc phục bằng bản tùy chỉnh).
Nâng cấp phiên bản cần sửa đổi lại tên các class (v2 xài span1 - span12, v3 xài col-, v4 xài col- ).

![](http://namluu.com/wp-content/uploads/2018/01/frontend-development-frameworks.jpg)

> Ngày nay các CSS Frameworks như Bootstrap đã phát triển hơn khái niệm CSS rất nhiều, ta nên gọi nó với tên **front-end component library**, vì nó còn tích hợp nhiều thư viện JavaScript bên trong. [Số lượng các front-end libraries ngày nay](https://usablica.github.io/front-end-frameworks/compare.html?v=2.0)

## 2015 - CSS3 và Flexbox

CSS3 đã hỗ trợ một công nghệ thiết kế layout mới, hiện đại hơn Float đó chính là Flexbox. Đúng như tên gọi flexible (linh hoạt), nó thực sự rất mạnh.

- Flexbox sẽ giúp bạn điều khiển được không những chiều ngang (horizontal) mà còn chiều dọc (vertical) điều mà CSS thường với position rất cứng nhắc.
- Flexbox có thể điều khiển được các phần tử bên trong, giúp bạn dễ dàng biểu diễn nội dung và bố cục trên các thiết bị di động.

![](http://namluu.com/wp-content/uploads/2018/01/fl.jpg)

**Khuyết điểm**: flexbox mạnh và mới nên bạn phải bỏ nhiều công sức để học và làm chủ được nó, khó hơn so với dùng float và Bootstrap. [Không khuyến khích dùng flexbox](https://jakearchibald.com/2014/dont-use-flexbox-for-page-layout/) để làm bố cục toàn trang trừ trường hợp đặc biệt, chỉ dùng để bố cục các thành phần bên trong. Lý do vì flexbox phụ thuộc vào nội dung bên trong nó, nên khi bài viết dài ngắn có thể làm "biến dạng" bố cục website của bạn, chưa kể tình huống khi web load chưa kịp.

> Kết hợp khôn ngoan là dùng grid system để làm bố cục bên ngoài, những phần bố cục cần sự linh hoạt thì dùng flexbox. Bootstrap 4 đã tích hợp flexbox vào grid view của mình, chứng tỏ sức mạnh của flexbox và không thể bàn cãi, đồng thời cho thấy cái tiện lợi khi dùng Bootstrap.

## 2017 - CSS Grid

Grid và 1 thuộc tính CSS rất mới, ra đời 3-2017. Tuy nhiên nó đã và đang được giới công nghệ web đặc biệt quan tâm vì những tính năng ưu việt.
Nếu như Flexbox phân bố các phần tử theo 1 chiều duy nhất thì Grid cho phép bạn điểu khiển phần tử theo 2 chiều - ngang và dọc.
Vì đây là 1 công nghệ mới, nên các [tài liệu chất lượng](https://medium.com/tag/grid-layout) về nó hầu hết là bằng tiếng anh, sắp tới mình sẽ có bài viết về công nghệ này, mới các bạn theo dõi.

![](https://cdn-images-1.medium.com/max/800/1*phV0oLsKV_qVjFVv5lY1vw.png)
]]></description>
            <link>https://hungvn.com/blog/bien-nien-su-ve-bo-cuc-trong-trang-web</link>
            <guid isPermaLink="true">https://hungvn.com/blog/bien-nien-su-ve-bo-cuc-trong-trang-web</guid>
            <pubDate>Wed, 25 Apr 2018 17:57:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Học Regular Expression và cuộc đời bạn sẽ bớt khổ]]></title>
            <description><![CDATA[
## Regular Expression (RegEx) à? Nghe quen quen.

> _**Đã bao giờ bạn ở vào các tính huống sau đây?**_

### Bạn cần xử lý validate (kiểm tra tính hợp lệ) các trường dữ liệu nhập vào ô Text

![](https://images.viblo.asia/1e7a1bf4-eb56-428c-b731-eb53970ffba9.png)

### Bạn cần copy và paste rất nhiều text từ chỗ này sang chỗ kia

Ví dụ từ XML sang C#

![](https://images.viblo.asia/4b3505d9-e466-427e-8ee4-e7327ec16d12.jpg)

hoặc CSV, Excel sang C#

![](https://images.viblo.asia/2a11aac3-36a4-43d9-b3de-b75f36b41ab8.jpg)

### Tìm kiếm một chuỗi nằm ở nhiều dòng trong Visual Studio hoặc Notepad++

Ví dụ tôi cần tìm và xóa bỏ (replace all) các comment như thế này ở code cũ.

![](https://images.viblo.asia/b77a555f-0486-4fef-bf15-637fa70473c9.jpg)

### Bạn cần bóc tách dữ liệu của một trang web.

Ví dụ extract (crawling) tách lấy dữ liệu từ một trang web để lưu lại vào cơ sở dữ liệu của bạn

![](https://images.viblo.asia/17aa1867-6f02-47b0-9884-6467e44a660d.jpg)

### Cơn ác mộng đọc một chuỗi string từ DB và cố gắng chuyển đổi nó sang DateTime

Chuỗi ngày tháng lưu vào CSDL rất đa dạng. Rất khó để dùng hàm DateTime.TryParse() để tự động chuyển đổi một chuỗi thành Datetime ngon lành cành đào.

![](https://images.viblo.asia/c40a1d3d-4f01-4f24-8749-119034a8f1ab.png)

### Tìm kiếm một chuỗi, lưu chuỗi đó lại và lấy chuỗi đã lưu chèn vào chỗ nào đó

Hay nói cách khác, ta cần thay một chuỗi bằng một chuỗi khác, trong chuỗi mới đó lại có chứa cả chuỗi vừa bị thay thế. Như ví dụ dưới đây sẽ cho các bạn thấy. Ta cần tìm ra ClassName, nhưng không phải thay thế ClassName đó bằng Class khác mà ta sẽ nhét nó vào 2 vị trí thay vì chỉ có 1 vị trí như hiện tại.

![](https://images.viblo.asia/7a2da882-3374-4327-ae69-57e43cadbc6a.jpg)

![](https://images.viblo.asia/cc4d46c2-54d1-44a5-9dea-a2c6de67837e.gif)

# Vậy RegEx có thể giúp gì cho chúng ta trong các trường hợp trên?

Regular Expression sinh ra là để giúp cho cuộc đời của bạn bớt khổ. Hãy tưởng tượng xem bạn phải nai lưng ra copy-paste bao nhiêu code. Bạn hoàn toàn có thể download các tool về để replace giúp bạn. Nhưng bạn cần bao nhiêu tool cho đủ đây.

Thay vào đó, bạn hãy thử học RegEx. Bộ cú pháp này sẽ giúp cho bạn thao tác với chuỗi như dao chém chuối. Như ta thấy các ví dụ bên trên, tất cả đều là XỬ LÝ CHUỖI ví dụ Cut Copy Paste hoặc Replace chuỗi. RegEx là ngôn ngữ giúp xử lý chuỗi rất mạnh.

RegEx không phải là một ngôn ngữ lập trình. Nó chỉ là một BỘ CÚ PHÁP dùng để bắt chuỗi. Nhưng nó cực kỳ phổ biến và bất kỳ ngôn ngữ lập trình nào cũng hỗ trợ. Nó có cả trăm ngàn ứng dụng và công cụ ăn theo.

Hãy lần lượt xem qua các ví dụ sau đây để học cách sử dụng Regular Expression nhé.

# Bắt đầu sử dụng Regular Expression

Để bắt đầu sử dụng và học cách dùng RegEx, mình hay dùng trang web [https://regex101.com/](https://regex101.com/). Giao diện như sau:

![](https://images.viblo.asia/df2fd4af-d0f0-4e92-bd56-5570086484d3.gif)

### Trước hết các bạn hãy đọc qua một lượt các quy tắc bắt chuỗi (matching) đơn giản nhất của RegEx

- `[xyz]` Tìm và so sánh tất cả ký tự nằm trong dấu ngoặc vuông và trùng khớp với 1 ký tự trong dấu ngoặc vuông. Ví dụ: [31] sẽ trùng khớp với **3** hoặc **1**, [0123456789] sẽ trùng khớp với bất kỳ một ký tự nào trong khoảng từ **0** đến **9**.
- `[a-z]` So sánh và trùng khớp với một ký tự nằm trong khoảng chỉ định. Ví dụ: `[a-z]` sẽ trùng khớp với một ký tự trong khoảng từ a đến z nằm trong chuỗi cần test. `[0-9]` sẽ trùng khớp với bất kỳ một ký tự nào trong khoảng từ **0** đến **9**.
- `[^xyz]` So sánh và không trùng khớp với những ký tự nằm trong khoảng chỉ định. Dấu ^ (dấu mũ) nằm trong dấu ngoặc vuông là một dấu phủ định. Ví dụ: `[^a-z]` sẽ không trùng khớp với tất cả các ký tự nằm trong khoảng từ **a** đến **z**.
- `^` Trùng khớp với phần đầu của chuỗi đích. Ví dụ: ^a sẽ trùng khớp với chữ **a** trong chuỗi `**abc**`, `^\w+` sẽ trùng khớp với chữ đầu tiên – chữ **"the"** của chuỗi **"The quick brown fox jumps over the lazy dog"**.
- `$` Trùng khớp với phần cuối của chuỗi đích. Ví dụ: c$ sẽ trùng khớp với chữ c trong chuỗi abc, \w+$ sẽ trùng khớp với chữ cuối - chữ **"dog"** của chuỗi **"The quick brown fox jumps over the lazy dog"**.
- `-` Trùng khớp với 1 hoặc nhiều lần ký tự đứng trước nó. Ví dụ \d+ sẽ chỉ trùng với chuỗi có từ 1 con số trở lên.
- `-` Trùng khớp với 0 hoặc nhiều lần ký tự đứng trước nó. Ví dụ \d\* sẽ trùng với chuỗi có chứa 1 chữ số hoặc k có chữ số nào cũng đc.
- `?` Trùng khớp với 0 hoặc 1 lần ký tự đứng trước nó. Tương tự như _ nhưng nó lại chỉ nhân lên 1 lần. _ thì nhân lên nhiều lần.
- `.` Trùng khớp với 1 ký tự đơn bất kỳ ngoại trừ ký tự ngắt dòng `(line-break)` và cũng không lấy được ký tự có dấu `(unicode)`. Ví dụ: . sẽ trùng khớp với ký tự `**a` hoặc b hoặc `c**` trong chuỗi `**abc**`. Nhưng . sẽ không bắt được các chữ ă hoặc ê.
- `x{n}` Trùng khớp đúng với n lần ký tự đứng trước nó. n là một số không âm. Ví dụ `\d{2}` sẽ bắt đc các số có 2 chữ số đứng liền nhau.
- `x{n,}` Trùng khớp với ít nhất n lần ký tự đứng trước nó. n là một số không âm.Ví dụ `\d{2,}` sẽ bắt đc các số có từ 2 chữ số trở lên đứng liền nhau.
- `x{n,m}` Trùng khớp với ít nhất n lần và nhiều nhất là m lần ký tự đứng trước nó. n và m là một số không âm và `n <= m`. Ví dụ: `a{1,3}` sẽ khớp với **hah, haah, `haaah**`nhưng không khớp với`**haaaah**`.
- `x|y` Trùng khớp với x hoặc y. Ví dụ: slow|fast sẽ khớp với chữ **slow** hoặc **fast** trong chuỗi đích.
- `\b` Trùng khớp với toàn bộ ký tự đứng trước nó. Ví dụ: hello\b sẽ trùng khớp với toàn bộ từ hello trong chuỗi **hello world** nhưng sẽ không khớp với chuỗi **helloworld**.
- `\B` Ngược lại với `\b`, `\B` sẽ không khớp với toàn bộ mà chỉ 1 phần ký tự đứng trước nó. Ví dụ: `hello\B` sẽ trùng khớp với chữ hello trong chuỗi **helloworld** nhưng sẽ không khớp với chuỗi **hello world**.
- `\d` Trùng khớp 1 ký tự số (digit).
- `\D` Trùng khớp 1ký tự không phải số (non-digit).
- `\s` Trùng khớp 1 ký tự khoảng trắng (whitespace) bao gồm khoảng trắng tạo ra bởi phím Tab.
- `\S` Trùng khớp với 1 ký tự không phải là khoảng trắng (non-whitespace).
- `\w` Trùng khớp với các ký tự là từ (word) bao gồm dấu \_ (underscore) và chữ số.
- `\W` Trùng khớp với các ký tự không phải là từ (non-word). Ví dụ: \W sẽ khớp với ký tự % trong chuỗi **"100%"**.
- `\uxxxx` Trùng khớp với 1 ký tự unicode. Ví dụ: \u00FA sẽ khớp với ký tự **"ú"**, \u00F9 sẽ khớp với ký tự **"ù"**.
- `\pL` Trùng khớp với một ký tự Unicode bất kỳ ngoại trừ dấu cách. Đây chính là cú pháp viết hoàn hảo hơn của dấu. Ví dụ `\pL+` sẽ lấy được chuỗi truyền, thuyết trong chuỗi **"truyền thuyết"**.

![](https://images.viblo.asia/bb00ea2c-cb41-4090-bce0-1b7ce1893791.gif)

Đừng lo, hãy xem qua các ví dụ từ từ rồi bạn sẽ hiểu

## Ví dụ đơn giản

### Tìm chuỗi số

![](https://images.viblo.asia/f2448336-4cd5-4ceb-a147-f617228b24ed.gif)

### Tìm ngày tháng

![](https://raw.githubusercontent.com/chungminhtu/regex_practices/master/Regex_CaptureDate.gif)

Link demo: [https://regex101.com/r/3dNzjU/1](https://regex101.com/r/3dNzjU/1)

### Tìm ngày tháng chính xác

Trong ví dụ trên thì ta thấy có chuỗi **"60/60/2018"** cũng được coi là ngày tháng, như thế là không chính xác. Ta hãy viết lại cho chuẩn.

![](https://raw.githubusercontent.com/chungminhtu/regex_practices/master/RegEx_CaptureDate_Advance.gif)

Link demo: [https://regex101.com/r/3dNzjU/2](https://regex101.com/r/3dNzjU/2)

## Cách "tóm lấy" string cần tìm đưa vào Group

![](https://raw.githubusercontent.com/chungminhtu/regex_practices/master/RegEx_MatchGroup.gif)

## Cách tạo ra code để dùng RegEx trong các ngôn ngữ lập trình

RegEx là bộ cú pháp, tuy nhiên để áp dụng nó vào các ngôn ngữ lập trình lại phải tuân thủ theo các thư viện và quy tắc lập trình để lấy ra được các Group đã capture (thu) được. Hãy xem các tạo code ngay sau đây:

![](https://raw.githubusercontent.com/chungminhtu/regex_practices/master/RegEx_GenerateCode.gif)

## Cách bắt lấy chuỗi bất kỳ

![](https://raw.githubusercontent.com/chungminhtu/regex_practices/master/RegEx_CaptureString.gif)
Link demo: [https://regex101.com/r/3dNzjU/3](https://regex101.com/r/3dNzjU/3)

# Sử dụng RegEx trong thực tế

Trong thực tế RegEx có thể được gõ trực tiếp ở bất kỳ trình Editor nào. Ví dụ mình hay dùng Notepad++, hoặc Visual Studio

![](https://github.com/chungminhtu/regex_practices/blob/master/Nodepad++KepChuoi.gif?raw=true)

# Tham khảo

Tham khảo thêm toàn bộ cú pháp RegEx bằng tiếng Anh tại: [https://www.cheatography.com/davechild/cheat-sheets/regular-expressions/](https://www.cheatography.com/davechild/cheat-sheets/regular-expressions/)

> Một số công cụ test RegEx Online

- [https://regex101.com/](https://regex101.com/)
- [http://regexr.com/](http://regexr.com/)
- [http://www.regexpal.com/](http://www.regexpal.com/)
- [http://regexper.com/](http://regexper.com/)

# Bài tập về nhà

Bạn ngứa tay muốn thử học RegEx ngay và luôn cho nóng. Vậy hãy thử thực hành bằng một số bài tập từ dễ đến khó sau đây nhé.

_**Bài tập nhập môn:**_

1.  Lấy ra các chữ có chữ test trong chuỗi sau: **“that tested test is testing the tester's tests”**
2.  Lấy ra các số điện thoại trong chuỗi sau: ** “p:444-555-1234 f:246.555.8888 m:1235554567”**
3.  Lấy ra các mã màu RGB trong chuỗi sau: **“#FF006C ABC 99AAB7FF 0xF0F73611”**
4.  Lấy ra các chữ có 4 ký tự trong chuỗi sau: **“drink beer, it's very nice!”**
5.  Lấy ra tên file trong chuỗi URL sau: **“[rapidshare.com/asd/asd/File.avi.html”](http://rapidshare.com/asd/asd/File.avi.html%E2%80%9D)**

> Đáp án ở phần comment nhé.

_**Bài tập dành cho học sinh giỏi (lớp học thêm)**_

1.  Tìm cách lấy các URL trong chuỗi HTML sau:

```html
Lorem gyum <b>Betrag</b> von
<a href="http://www.vektor.de">Vektoren</a>
(Länge eines Vektors)
<a href="gcfa.com">GCFA</a>
<a href="//cdn.com/test.js">CDN</a>
ist das Maß einer Menge sozu…
```

2.  Tìm cách loại bỏ toàn bộ COMMENT trong đoạn code sau:

```javascript
var sample = 0;
var my_string = "Hello World!";
// This is a comment!
function do_stuff(){
// This is another comment!
alert(‘somethings’);
/* this is a multiline
     comment */
}
```

3.  Tìm cách lấy ra chuỗi tiếng Nhật trong chuỗi sau: “

```
This is a demo story 前に来た時は北側からで、当時の光景はいまでも思い出せる。And it is true.
```

4.  Lấy ra những file ảnh và độ phân giải của ảnh từ chuỗi sau:

```
.bash_profile
workspace.doc
img0912.jpg (1280x720)
updated_img0912.png (1024x768)
documentation.html
favicon.gif
img0912.jpg (1920x1600)
access.htaccess
```

5.  Đọc nội dung từ trang tin rss sau: [http://rss.cnn.com/rss/edition.rss](http://rss.cnn.com/rss/edition.rss) Lấy ra các Tiêu đề, ngày giờ đăng, nội dung tin vắn

> Đáp án các bạn post vào phần comment và cùng trao đổi nhé.

Nếu các bài tập trên đây vẫn chưa đủ, các bạn hãy làm thêm các bài tập tại trang [https://regexone.com](https://regexone.com) nhé, rất nhiều ví dụ hay.

# Kết luận

Hi vọng bài viết nhỏ này đã giúp bạn học được cú pháp viết RegEx và áp dụng vào công việc thường ngày. Mình dùng Regex rất nhiều và nó là trợ thủ đắc lực trong quá trình code.

Các bạn thì sao? bạn đã dùng Regex vào những việc gì? Hãy kể tên bên dưới comment để mình cùng học hỏi với nhé.

Thanks các bạn đã đọc!
]]></description>
            <link>https://hungvn.com/blog/hoc-regular-expression-va-cuoc-doi-ban-se-bot-kho</link>
            <guid isPermaLink="true">https://hungvn.com/blog/hoc-regular-expression-va-cuoc-doi-ban-se-bot-kho</guid>
            <pubDate>Wed, 25 Apr 2018 15:27:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu Higher-Order Function (HOF) và Currying qua một số ví dụ]]></title>
            <description><![CDATA[
HOF và Currying là hai kỹ thuật không khó, thậm chí có thể bạn đang dùng nó hàng ngày mà không để ý. Cùng tìm hiểu chúng thông qua một số ví dụ.

### Background

Tôi cho rằng một kỹ sư phần mềm pro không phải là người viết ra những dòng code đánh đố người đọc hay đồng nghiệp, mà là người viết những dòng code mà khi người khác đọc nó liền cảm thấy trong sáng, dễ hiểu, dễ bảo trì.

Cũng như sự tiến hóa của con người, khi mà "ăn no, ăn sạch rồi ăn ngon", thì coding cũng có slogan tương tự: ["chạy được, chạy đúng, sau cùng là chạy nhanh"](http://wiki.c2.com/?MakeItWorkMakeItRightMakeItFast).
Vậy, sau khi chạy được và chạy đúng rồi, chúng ta nên suy nghĩ xem ngoài việc có thể chạy nhanh hơn ko, thì đoạn code này đã sáng sủa chưa? Nếu bị/được sửa thì có dễ ko?

HOF và Currying là 2 trong số ti tỉ kỹ thuật nhằm giúp chúng ta, những lập trình viên huyền thoại, đạt được tiêu chí trên.

Trước khi đi vào khái niệm cụ thể, chúng ta cùng xem ví dụ dưới đây:

### Ví dụ 1

Nhóc con nhà bạn nhờ bạn tìm những số tự nhiên khác 0 nhỏ hơn 20 và là số lẻ.
Là một ông bố mẫu mực với niềm kiêu hãnh nhiều năm kinh nghiệm fixed hàng trăm bug nhỏ và ~~tạo ra~~ hàng tá bug to, bạn muốn viết một chương trình hoành tráng để lấy le với con mình. Ok, you win!.
Dưới đây chắc hẳn là đoạn code đầu tiên xuất hiện trong đầu:

```javascript
function pickOddNumbers(maximum) {
  const result = [];

  for (let i = 1; i <= maximum; i += 1) {
    if (i % 2 === 1) result.push(i);
  }

  return result;
}

pickOddNumbers(20);
```

Nhưng đời không bao giờ là mơ, khi hôm sau nhóc con lại mếu máo: "Cô giáo cho thêm bài: Tìm những số tự nhiên khác 0 nhỏ hơn 20 mà nếu gấp 3 số đó rồi từ đi 2 thì thu được số chẵn.".
Bố chiều cô luôn. Vậy là bạn lại cho ra phiên bản mới:

```javascript
function pickSpecialNumbers(maximum) {
  const result = [];

  for (let i = 1; i <= maximum; i += 1) {
    if ((i * 3 - 2) % 2 === 0) result.push(i);
  }

  return result;
}

pickSpecialNumbers(20);
```

Đời vẫn ko như mơ khi cô giáo lại cho thêm bài tập: "Tìm những số tự nhiên khác 0 nhỏ hơn 20 mà nếu lấy phần dư số đó cho 9 rồi cộng thêm 2 thì thu số lẻ."
Ơ cô giáo từ từ, để bố em sửa function bên trên đã :))))

Cứ như vậy, mỗi lần cô giáo cho thêm yêu cầu là bạn lại phải sửa phiên bản cũ hoặc cho ra một bản mới, tuy yêu cầu khác nhau nhưng xử lý cơ bản là giống nhau, chỉ khác ở đoạn xử lý điều kiện cho số được chọn.
Và bạn chợt nhớ tới HOF, một ứng cử viên sáng giá cho việc làm đoạn code trên sạch hơn, gọn hơn, dễ sửa hơn.

### Định nghĩa HOF

Theo [wikipedia](https://en.wikipedia.org/wiki/Higher-order_function) thì:

```javascript
A higher-order function (also functional, functional form or functor) is a function that does at least one of the following:

・takes one or more functions as arguments,
・returns a function as its result.
```

Vietsub:

```javascript
HOF là một function mà cho phép thực hiện ít nhất 1 trong 2 khả năng sau:
・Nhận vào một hoặc nhiều function như là tham số, hoặc/và
・Trả về kết quả là một function.
```

_// Bạn có thể thấy có rất nhiều ngôn ngữ hỗ trợ HOF ở link wiki trên. Đến Java còn hỗ trợ nữa là :v_

Trăm nghe không bằng một thấy, trăm thấy không bằng một sờ, và chúng ta lại cùng sờ với ví dụ bên trên.
Lần này là bản nâng cấp có giá trị về mặt học thuật, vì được áp dụng HOF vào cơ mà :)))

```javascript
function pickNumbers(maximum, pickingCondition) {
  const result = [];

  for (let i = 1; i <= maximum; i += 1) {
    if (pickingCondition(i)) result.push(i);
  }

  return result;
}

// Chọn ra những số lẻ
pickNumbers(20, function (number) {
  return number % 2 === 1;
});

// Chọn ra những số mà gấp 3 số đó rồi trừ đi 2 thu số chẵn
pickNumbers(20, function (number) {
  return (number * 3 - 2) % 2 === 0;
});
```

Với việc đưa HOF vào function bên trên, giờ thì cô giáo thích gì cũng chiều được nhé,
chỉ cần thay đổi function kiểm tra điều kiện vào thôi, ko cần phải copy thành function mới nữa.

### Định nghĩa Currying

Lại theo [wikipedia](https://en.wikipedia.org/wiki/Currying):

```javascript
 Currying is the technique of translating the evaluation of a function
 that takes multiple arguments (or a tuple of arguments)
 into evaluating a sequence of functions, each with a single argument.
```

Vietsub:

```javascript
Currying là kỹ thuật mà cho phép chuyển đổi một function với nhiều tham số
thành những functions liên tiếp có một tham số.
// Ví dụ f(a,b,c) có thể được convert thành g(a)h(b, c) hay g(a)h(b)k(c), thậm chí là đổi thứ tự của các function tương ứng...
```

Vậy dễ dàng nhận thấy Currying là một trường hợp của HOF, vì nó thỏa mãn điều kiện trả về kết quả là một function.

Cụ thể áp dụng cho ví dụ trên, có thể viết thành dạng sau:

```javascript
function pickNumbers(maximum) {
  return function (pickingCondition) {
    const result = [];

    for (let i = 1; i <= maximum; i += 1) {
      if (pickingCondition(i)) result.push(i);
    }

    return result;
  };
}

// Chọn ra những số lẻ
pickNumbers(20)(function (number) {
  return number % 2 === 1;
});

// Chọn ra những số mà gấp 3 số đó rồi trừ đi 2 thu số chẵn
pickNumbers(20)(function (number) {
  return (number * 3 - 2) % 2 === 0;
});
```

So sánh ví dụ áp dụng Currying này với ví dụ sử dụng HOF ở trên, rõ ràng là ta chưa thấy sự ưu việt của Currying so với HOF, thậm chí còn thấy hơi rườm rà nữa.
Tuy nhiên, hãy cùng xem xét ví dụ dưới đây:

### Ví dụ 2

Viết một function lấy ra giá trị của một key của object, được chọn ra từ một mảng các objects với điều kiện. Đơn giản vậy thôi, nên việc cài đặt cũng có vẻ là đơn giản.

Với HOF:

```javascript
function getValue(objects, key, pickingCondition) {
  var object = null;

  for (var i = 0; i < objects.length; i++) {
    if (pickingCondition(objects[i])) {
      object = objects[i];
      break;
    }
  }

  return object ? object[key] : null;
}
```

Mỗi khi gọi function với key khác nhau, hẳn là sẽ phải gọi kiểu như vầy:

```javascript
var valueByKey1 = getValue(objects, "key1", pickingCondition);
var valueByKey2 = getValue(objects, "key2", pickingCondition);
```

Nếu như coi key là **biết trước**, chỉ thay đổi objects và pickingCondition, thì việc áp dụng Currying là hợp lý:

```javascript
function getValue(key) {
  return function (objects, pickingCondition) {
    let object = null;

    for (let i = 0; i < objects.length; i++) {
      if (pickingCondition(objects[i])) {
        object = objects[i];
        break;
      }
    }

    return object ? object[key] : null;
  };
}

// Wrap getValue thành những function ngắn hơn với tên sáng nghĩa:
var getValueByKey1 = getValue("key1");
var getValueByKey2 = getValue("key2");

// Sử dụng:
var valueByKey1 = getValueByKey1(objects, pickingCondition);
var valueByKey2 = getValueByKey2(objects, pickingCondition);
```

Khá là gọn gàng.

_// Ngoài lề: Nếu bạn làm việc với ReactJs, hẳn bạn đã biết tới thuật ngữ Higher-Order Component, hay các selectors mà redux-form cung cấp, thì chúng đều áp dụng kỹ thuật Currying này, cũng như HOF._

Dưới đây là một vài ví dụ cho thấy tác dụng tốt của Currying:

### Ví dụ 3

Viết function để kiểm tra độ dài của một xâu s có vượt quá n hay ko.

```javascript
// Cách 1: Không dùng Currying
function isLengthOver(s, n) {
  return s.length > n;
}

// Cách 2: Có Currying
function isLengthOver(n) {
  return function (s) {
    return s.length > n;
  };
}
```

Giả sử cả 2 cách viết trên được sử dụng cho việc validate của một field trên form, với n = 10 thì có sự khác biệt như sau:

Với cách 1:

```javascript
<input type="text" validate={value => isLengthOver(value, 10)} />
```

Với cách 2:

```javascript
<input type="text" validate={isLengthOver(10)} />
```

Quá khác bọt!

### Ví dụ 4

Viết function hiển thị tên group mà một nhân viên đang làm việc, với:

Input:

- employeeGroupId là id của group mà nhân viên đang làm việc,
- Mảng chứa toàn bộ groups có trong công ty.

Điều kiện rằng buộc:

- Một group luôn có id khác null,
- Nếu groupB là group con của groupA, thì groupB sẽ có parentGroupId là id của groupA. Group không là con khi parentGroupId của nó là null,
- Không có quan hệ vòng tròn. (Kiểu: groupA là con groupB, groupB là con groupC, groupC là con groupA)

Output:

- Full path của group mà nhân viên đang làm việc, phân cách bởi dấu /. Ví dụ Group A / Group B / Group C

Chắc hẳn bạn sẽ nghĩ tới cách dùng vòng lặp, kiểm tra chừng nào còn tìm thấy group có id bằng parentGroupId. Và tôi cũng nghĩ vậy :D

```javascript
const getGroupFullPathName = (groups, employeeGroupId) => {
  const groupNames = [];

  let group = groups.find(grp => grp.id === employeeGroupId);
  while (group) {
    groupNames.unshift(group.name);
    group = groups.find(grp => grp.id === group.parentGroupId);
  }

  return groupNames.join("/");
};
```

Nhưng đoạn code trên vẫn chưa ngon, do vi phạm rule [Don't make functions within a loop](https://eslint.org/docs/rules/no-loop-func) của ESLint.
Cụ thể: Mỗi khi vòng while được chạy thì groups.find(grp => grp.id === group.parentGroupId) lại sinh ra một anonymous function, chính là grp => grp.id === group.parentGroupId.

Cách khắc phục là ta viết một currying bên ngoài vòng while là được:

```javascript
const getGroupFullPathName = (groups, employeeGroupId) => {
  const groupNames = [];
  const condition = parentGroupId => group => group.id === parentGroupId;

  let group = groups.find(grp => grp.id === employeeGroupId);
  while (group) {
    groupNames.unshift(group.name);
    group = groups.find(condition(group.parentDepartmentId));
  }

  return groupNames.join("/");
};
```

### Kết luận:

Bài quá dài.

_// Nếu mấy ví dụ trên dùng cú pháp của es6 và dùng các api của Array thì sẽ ngắn hơn nhiều, nhưng lại khó nhìn rõ đâu là function được nhận vào/trả ra, nên các bạn chịu khó đọc với cú pháp cơ bản vậy :D_
]]></description>
            <link>https://hungvn.com/blog/tim-hieu-higher-order-function-hof-va-currying-qua-mot-so-vi-du-3</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tim-hieu-higher-order-function-hof-va-currying-qua-mot-so-vi-du-3</guid>
            <pubDate>Tue, 03 Apr 2018 11:20:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[CSS Grid vs Flexbox sử dụng như thế nào]]></title>
            <description><![CDATA[
## Tìm hiểu cách chúng khác nhau, và khi bạn nên sử dụng nó.

CSS Flexbox đã trở nên cực kỳ quen thuộc với các lập trình viên front-end trong vài năm gần đây. Điều này không đáng ngạc nhiên, bởi vì nó giúp chúng ta tạo ra các bố cục động (dynamic layout) và sắp xếp nội dung trong các container dễ dàng hơn rất nhiều.

Tuy nhiên, có một mô-đun mới gọi là CSS Grid và nó có nhiều khả năng giống như Flexbox. Trong một vài trường hợp nó tốt hơn so với Flexbox, và một số trường hợp khác thì không.

Điều này có vẻ gây nhầm lẫn cho các lập trình viên. Vì vậy, bài viết này sẽ so sánh hai mô-đun, cả mức độ vi mô và vĩ mô.

### Một chiều vs hai chiều

Nếu bạn rút ra một bài học từ bài viết này, thì đây là nó:

> Flexbox được tạo ra cho các bố cục một chiều và Grid được tạo ra cho các bố cục hai chiều.

Điều này có nghĩa là nếu bạn đang đặt các item theo một hướng (ví dụ ba nút bên trong header), thì bạn nên sử dụng Flexbox:

![](https://cdn-images-1.medium.com/max/1600/1*h6dcLWRp0lXeWklPAFK8cA.png)

Nó sẽ linh hoạt hơn CSS Grid. Và cũng dễ dàng hơn để bảo trì và yêu cầu mã ít hơn.

Tuy nhiên nếu bạn định tạo bố cục theo hai chiều - với cả các hàng và các cột - thì bạn nên sử dụng CSS Grid:

![](https://cdn-images-1.medium.com/max/2000/1*AxItLokVtaF56WMo_ZF6Pw.png)

Trong trường hợp này, CSS Grid sẽ linh hoạt hơn, làm cho code của bạn đơn giản hơn và dễ bảo trì hơn.

Tất nhiên bạn có thể kết hợp cả hai. Trong ví dụ ở trên, giải pháp hoàn hảo là sử dụng Grid cho việc bố cục trang, và sau đó dùng Flexbox để sắp xếp nội dung bên trong header. Điều này sẽ cung cấp cho bạn những chức năng tốt nhất của cả hai mô-đun.

### Content-first vs layout-first

Một khác biệt quan trọng nữa giữa 2 mô-đun là Flexbox tập trung vào **nội dung** trong khi Grid tập trung vào **bố cục**. Điều này có vẻ trừu tượng, vì vậy hãy xem một ví dụ cụ thể, nó sẽ dễ hiểu hơn.

Chúng ta sẽ sử dụng header. Đây là code HTML cho nó:

```html
<header>
  <div>Home</div>
  <div>Search</div>
  <div>Logout</div>
</header>
```

Trước khi chúng ta style nó với Flexbox, các div này sẽ được xếp chồng lên nhau như thế này:

![](https://cdn-images-1.medium.com/max/1600/1*VRnOqt5g9NVKY-NUh0vh7Q.png)

#### Flexbox header

Tuy nhiên, khi chúng ta style nó với display: flex; các item sẽ được đặt trên một dòng.

```css
header {
  display: flex;
}
```

![](https://cdn-images-1.medium.com/max/1600/1*XHmGGavmUsEi3-vd9v0vcg.png)

Để di chuyển nút _logout_ sang phía bên phải, chúng ta chỉ cần chọn phần tử đó và style với margin:

```css
header > div:nth-child(3) {
  margin-left: auto;
}
```

Kết quả sẽ như thế này:

![](https://cdn-images-1.medium.com/max/1600/1*1inbBN_44U2HSwFL3Ech-w.png)

Cái tôi muốn bạn để ý ở đây là chúng ta để các item tự quyết định vị trí của mình. Chúng ta không phải xác định trước bất cứ điều gì khác ngoài `display: flex;`.

Đây là khác biệt chính giữa Flexbox và Grid, và nó sẽ trở nên rõ ràng hơn khi chúng ta tạo header này bằng cách sử dụng Grid.

> Mặc dù CSS Grid không được tạo ra cho header một chiều, nhưng vẫn là một ý hay khi làm điều này vì nó dạy cho chúng ta về sự khác biệt cốt lõi giữa Flexbox và Grid.

#### Grid header

Chúng ta có thể tạo header theo nhiều cách khác nhau với CSS Grid. Tôi sẽ sử dụng một cách khá đơn giản, trong đó grid của chúng ta có mười cột.

```css
header {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
}
```

Nó sẽ giống hệt với giải pháp Flexbox.

![](https://cdn-images-1.medium.com/max/1600/1*VPeA-uXOph9dNuOEUAz_kQ.png)

Tuy nhiên, chúng ta có thể sử dụng Chrome inspector để kiểm tra các dòng cột:

![](https://cdn-images-1.medium.com/max/1600/1*RK-Kw7WoW6hXnpIYIPZF3Q.png)

Sự khác biệt chính với cách tiếp cận này là chúng ta phải xác định các cột - bố cục - đầu tiên. Chúng ta bắt đầu với việc xác định chiều rộng của các cột, và _sau đó_ chúng ta đặt nội dung vào các ô có sẵn trong grid.

> Cách tiếp cận này buộc chúng ta phải xác định số lượng cột mà chúng ta muốn chia trong header.

Trừ khi thay đổi grid, còn không chúng ta luôn có 10 cột. Một hạn chế mà chúng ta sẽ không phải đối mặt trong Flexbox.

Để thay đổi _logout_ sang phía bên tay phải, chúng ta sẽ đặt nó vào cột thứ mười, như sau:

```css
header > div:nth-child(3) {
  grid-column: 10;
}
```

Dùng Chrome inspector chúng ta sẽ thấy:

![](https://cdn-images-1.medium.com/max/1600/1*u5z2zikNjwyL84dcUhRgJA.png)

Chúng ta không thể chỉ đơn giản style nó với `margin-left: auto;` vì nút _logout_ đã được đặt trong một ô cụ thể trong bố cục, trong cột thứ ba. Để di chuyển nó, chúng ta phải tìm một ô khác cho nó.

### Kết hợp cả hai

Bây giờ chúng ta hãy xem cách kết hợp cả hai, sát nhập header vào bố cục trang web. Chúng ta sẽ bắt đầu bằng cách xây dựng bố cục trang web.

![](https://cdn-images-1.medium.com/max/1600/1*OcjCKOnh48lYnUuEJw_ZBA.png)

Đây là HTML:

```html
<div class="container">
  <header>HEADER</header>
  <aside>MENU</aside>
  <main>CONTENT</main>
  <footer>FOOTER</footer>
</div>
```

Đây là CSS:

```css
.container {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-template-rows: 50px 350px 50px;
}
```

Chúng ta sẽ đặt các item trên grid như sau:

```css
header {
  grid-column: span 12;
}
aside {
  grid-column: span 2;
}

main {
  grid-column: span 10;
}
footer {
  grid-column: span 12;
}
```

Tiếp theo, chúng ta sẽ chỉ cần thêm style cho header. Chúng ta sẽ biến header - một _item_ trong CSS Grid - thành một Flexbox container.

```css
header {
  display: flex;
}
```

Chúng ta có thể thiết lập nút logout sang bên phải:

```css
header > div:nth-child(3) {
  margin-left: auto;
}
```

Kết quả, chúng ta có một bố cục hoàn hảo sử dụng những tính năng tốt nhất từ cả Grid và Flexbox. Hai container sẽ trông như thế này:

![](https://cdn-images-1.medium.com/max/2000/1*jPJsp3kukI6WNQBntfHsWg.png)

Bây giờ, bạn đã hiểu rõ sự khác biệt nói chung và cụ thể giữa Flexbox và Grid, và biết cách sử dụng chúng cùng với nhau.

#### Trình duyệt hỗ trợ

Trước khi kết thúc, tôi cũng cần đề cập đến các trình duyệt hỗ trợ CSS Grid. Vào thời điểm này (25/03/2018), [84.14% website toàn cầu hỗ trợ CSS Grid](https://caniuse.com/#feat=css-grid), và nó đang tăng dần.

Tôi tin năm 2018 sẽ là năm của CSS Grid. Nó sẽ đột phá, và sẽ trở thành một kỹ năng phải có của các lập trình viên front-end. Giống như những gì đã xảy ra với CSS Flexbox trong vài năm gần đây.
]]></description>
            <link>https://hungvn.com/blog/css-grid-vs-flexbox-su-dung-nhu-the-nao</link>
            <guid isPermaLink="true">https://hungvn.com/blog/css-grid-vs-flexbox-su-dung-nhu-the-nao</guid>
            <pubDate>Sun, 25 Mar 2018 20:52:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Một số thủ thuật Chrome DevTools có thể bạn đã biết]]></title>
            <description><![CDATA[
### 1. Drag-and-drop in the Elements panel

In the Elements panel, you can drag and drop any HTML element and change its position across the page

![Drag-and-drop in the Elements panel](https://cdn-images-1.medium.com/max/1600/1*YJ4pbintkGmF67YSLH7UEQ.gif)

### 2. Reference the currently selected element in the Console

Select a node in the Elements panel, and type $0 in the console to reference it.

If you’re using jQuery, you can enter $($0) to access the jQuery API on this element.

![Reference the currently selected element in the Console](https://cdn-images-1.medium.com/max/1600/1*Ua9Z12CO8LYWcx5L2zpQAw.gif)

### 3. Use the value of the last operation in the Console

Use $\_ to reference the return value of the previous operation executed in the Console

![Use the value of the last operation in the Console](https://cdn-images-1.medium.com/max/1600/0*zxJYnGdu8QUPGSiW.gif)

### 4. Add CSS and edit the element state

In the Elements panel there are two super useful buttons.

The first lets you add a new CSS property with any selector you want, but pre-filling the currently selected element:

![Add CSS rules](https://cdn-images-1.medium.com/max/1600/0*SVTP4Rl82XYNc4Kp.gif)

The second one lets you trigger a state for the selected element, so you can see the styles applied when it’s active, hovered, or on focus.

![Edit the element state](https://cdn-images-1.medium.com/max/1600/0*1nCZIzP73fr2xAwQ.png)

### 5. Save to file the modified CSS

Click the name of the CSS file that you edited. The inspector opens it into the Sources pane, and from there you can save it with the live edits you applied.

This trick does not work for new selectors added using +, or into the element.style properties, but only for modified, existing ones.

![Save to file the modified CSS](https://cdn-images-1.medium.com/max/1600/1*7Q-CbjzcXYR20dbtmyMbJw.gif)

### 6. Screenshot a single element

Select an element and press cmd-shift-p (or ctrl-shift-p in Windows) to open the Command Menu, and select **Capture node screenshot**

![Screenshot a single element](https://cdn-images-1.medium.com/max/1600/0*CjWhHTmoZbCeMXSw.gif)

### 7. Find an element using CSS selectors

Pressing cmd-f (ctrl-f in Windows) opens the search box in the Elements panel.

You can type any string in there to match the source code, or you can also use CSS selectors to have Chrome generate an image for you:

![Find an element using CSS selectors](https://cdn-images-1.medium.com/max/1600/0*ipqpirAGqDRlEbes.gif)

### 8. Shift-enter in the Console

To write commands that span over multiple lines in the Console, press shift-enter.

Once you’re ready, press enter at the end of the script to execute it:

![Shift-enter in the Console to write multiline commands](https://cdn-images-1.medium.com/max/1600/0*QizwVdkFs7FC1kv1.gif)

You can clear the console using the _Clear_ button on the top-left of the console, or by pressing ctrl-l or cmd-k.

### 9. Go to…

In the Sources panel:

- cmd-o (ctrl-o in Windows), shows all the files loaded by your page.
- cmd-shift-o (ctrl-shift-o in Windows) shows the functions (or classes) in the current file.
- cmd-l (ctrl-l in Windows) goes to a specific line.

![Go to file](https://cdn-images-1.medium.com/max/1600/0*mxGuyBT02JoiSlb-.png)

### 10. Watch Expression

Instead of writing again and again a variable name or an expression you are going to check a lot during a debug session, add it to the _Watch Expression_ list.

![Watch Expression](https://cdn-images-1.medium.com/max/1600/0*gSpZcWiUho4z9DoW.gif)

### 11. XHR/Fetch debugging

From the debugger open the **XHR/Fetch Breakpoints** panel.

You can set it to break any time a XHR/Fetch call is sent, or just on specific ones:

![XHR/Fetch debugging](https://cdn-images-1.medium.com/max/1600/0*r_-hBTOJ23eSDX-g.png)

### 12. Debug on DOM modifications

Right-click an element and enable _Break on Subtree Modifications._ Whenever a script traverses that element’s children and modifies them, the debugger stops automatically to let you inspect what’s happening.

![Debug on DOM modifications](https://cdn-images-1.medium.com/max/1600/0*VYABHtIwKZ5eeu-p.png)
]]></description>
            <link>https://hungvn.com/blog/mot-so-thu-thuat-chrome-devtools-co-the-ban-da-biet</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mot-so-thu-thuat-chrome-devtools-co-the-ban-da-biet</guid>
            <pubDate>Sun, 25 Mar 2018 14:54:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Kiến thức cho phỏng vấn Javascript developer]]></title>
            <description><![CDATA[
JavaScript is the most popular programming language and has been since 2014, according to [Stack Overflow Survey](https://insights.stackoverflow.com/survey/2017#most-popular-technologies). It is no wonder that over 1/3rd of all developer jobs require some JavaScript knowledge. So, if you plan to work as a developer in the near future, you should be familiar with this extremely popular language.

The post’s purpose is to bring together all JavaScript concepts that are frequently brought up in developer interviews. It was written so you can review everything you need to know about JavaScript in a single place.

### **Types & Coercion**

There are 7 built-in types: null, undefined , boolean, number, string, object and symbol (ES6).

All of these are types are called primitives, except for object.

<Gist id="5e3f8d5dc70abac837cf272df2891934" />

- **Null vs. Undefined**

**Undefined** is the absence of a definition. It is used as the default value for uninitialized variables, function arguments that were not provided and missing properties of objects. Functions return undefined when nothing has been explicitly returned.

**Null** is the absence of a value. It is an assignment value that can be assigned to a variable as a representation of ‘no-value’.

- **Implicit coercion**

Take a look at the following example:

<Gist id="c0ad651bb55abd65e16dbb44c905d779" />

In this case, the string variable name is coerced to true and you have ‘Joey doesn’t share food!’ printed in our console. But how do you know what will be coerced to true and what will be coerced to false?

Falsy values are values that will be coerced to false when forced a boolean coercion on it.

Falsy values: "", 0, null, undefined, NaN, false.

Anything not explicitly on the falsy list is truthy —**boolean coerced to true**.

<Gist id="5eadf22657bd8cdc1d46770185bd04eb" />

Yes. You read it right. Empty arrays, objects and functions are boolean coerced to true!

- **String & Number coercion**

The first thing you need to be aware of is the + operator. This is a tricky operator because it works for both number addition and string concatenation.

But, the `*`, `/`, and `-` operators are exclusive for numeric operations. When these operators are used with a string, it forces the string to be coerced to a number.

<Gist id="77723e09a20beabad6e8e8adba4ad0b5" />

- **== vs. ===**

It is widely spread that == checks for equality and === checks for equality and type. Well, that is a misconception.

In fact, == checks for **equality with coercion** and === checks for equality without coercion — **strict equality**.

<Gist id="3cbeceb2e5fde3141f58919df6bd1798" />

Coercion can be tricky. Take a look at the following code:

<Gist id="64728b4693d4efa86823b04e0f6ef657" />

What would you expect for the following comparison?
console.log(a == b); (1)

This comparison actually returns True. Why?
What really happens under the hood is that if you are comparing a boolean with something other than a boolean, JavaScript coerces that boolean to a number and compares. (2)

This comparison is now between a number and a string. JavaScript now coerces that string to a number and compares both numbers. (3)

In this case, the final comparison 0 == 0 is True.

```javascript
"0" == false(1);
"0" == 0(2);
0 == 0(3);
```

For a fully comprehension on how such comparisons are performed, you can check ES5 documentation [here](http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3).

For a cheat sheet, you can click [here](http://dorey.github.io/JavaScript-Equality-Table/).

Some tricky comparisons to look out for:

<Gist id="27ace3848b30aa9c6c195ea47f2cbf94" />

### Value vs. Reference

Simple values (also known as primitives) are always assigned by value-copy: null, undefined , boolean, number, string and ES6 symbol.

Compound values always create a copy of the reference on assignment: objects, which includes arrays, and functions.

<Gist id="53602e9d38c3fc9e4c5799ef4d5ef680" />

To copy a compound value by value, you need to **make**a copy of it. The reference does not point to the original value.

<Gist id="7b7c1dfa5ce4fac0d9e2f5becb70351d" />

### Scop*e*

Scope refers to the execution context. It defines the accessibility of variables and functions in the code.

**Global Scope** is the outermost scope. Variables declared outside a function are in the global scope and can be accessed in any other scope. In a browser, the window object is the global scope.

**Local Scope** is a scope nested inside another function scope. Variables declared in a local scope are accessible within this scope as well as in any inner scopes.

<Gist id="af953afc4fa5cbc5730f33cdcc84cc6d" />

You may think of Scopes as a series of doors decreasing in size (from biggest to smallest). A short person that fits through the smallest door — **innermost scope** — also fits through any bigger doors — **outer scopes**.

A tall person that gets stuck on the third door, for example, will have access to all previous doors — **outer scopes** — but not any further doors — **inner scopes**.

### Hoisting

The behavior of “moving” var and function declarations to the top of their respective scopes during the compilation phase is called **hoisting**.

Function declarations are completely hoisted. This means that a declared function can be called before it is defined.

<Gist id="2e4cf346eb8a63a0db8b7e3fb09b3da8" />

Variables are partially hoisted. var declarations are hoisted but not its assignments.

let and const are not hoisted.

<Gist id="e1bdaf648836bb3a58aeb2605e6ff6cd" />

### Function Expression vs. Function Declaration

- **Function Expression** A Function Expression is created when the execution reaches it and is usable from then on — it is not hoisted.

<Gist id="97cc7170cf4d249bc510f92563aee5b0" />

- **Function Declaration** A Function Declaration can be called both before and after it was defined — it is hoisted.

<Gist id="5604017e8dafbaa179fc505b13f792fc" />

### Variables: var, let and const

Before ES6, it was only possible to declare a variable using var. Variables and functions declared inside another function cannot be accessed by any of the enclosing scopes — they are function-scoped.

Variables declared inside a block-scope, such as if statements and for loops, can be accessed from outside of the opening and closing curly braces of the block.

**Note**: An undeclared variable — assignment without var, let or const — creates a var variable in global scope.

<Gist id="09e19a0bfec70019ebe54bf507ed2efa" />

ES6 let and const are new. They are not hoisted and block-scoped alternatives for variable declaration. This means that a pair of curly braces define a scope in which variables declared with either let or const are confined in.

<Gist id="035ffb6832bc698e86c80ae9472d17ec" />

A common misconception is that const is immutable. It cannot be reassigned, but its properties can be **changed**!

<Gist id="75ee0da2b6ab311a011aa4e4fec4c8b4" />

### Closure

A **closure** is the combination of a function and the lexical environment from which it was declared. Closure allows a function to access variables from an enclosing scope — **environment** — even after it leaves the scope in which it was declared.

<Gist id="debafd05414b713b065189f236ea8d88" />

The above example covers the two things you need to know about closures:

1.  Refers to variables in outer scope.
    The returned function access themessage variable from the enclosing scope.
2.  It can refer to outer scope variables even after the outer function has returned. 
    sayHiToJon is a reference to the greeting function, created when sayHi was run. The greeting function maintains a reference to its outer scope — **environment** — in which message exists.

One of the main benefits of closures is that it allows **data encapsulation**. This refers to the idea that some data should not be directly exposed. The following example illustrates that.

By the time elementary is created, the outer function has already returned. This means that the staff variable only exists inside the closure and it cannot be accessed otherwise.

<Gist id="d1d6074cb995bb41393f5375f0fdd306" />

Let’s go deeper into closures by solving one of the most common interview problems on this subject:
What is wrong with the following code and how would you fix it?

<Gist id="6911302e191138cb2ec8411372dff9a0" />

Considering the above code, the console will display four identical messages "The value undefined is at index: 4". This happens because each function executed within the loop will be executed after the whole loop has completed, referencing to the last value stored in i, which was 4.

This problem can be solved by using IIFE, which creates a unique scope for each iteration and storing each value within its scope.

<Gist id="30f45b336aecb5f891f2c0f0b8541799" />

Another solution would be declaring the i variable with let, which creates the same result.

<Gist id="ce8a4a5f3e5c9b48e17ff9baa6330934" />

### Immediate Invoked Function Expression (IIFE)

An IIFE is a function expression that is called immediately after you define it. It is usually used when you want to create a new variable scope.

The **(surrounding parenthesis)** prevents from treating it as a function declaration.

The **final parenthesis()** are executing the function expression.

On IIFE you are calling the function exactly when you are defining it.

<Gist id="bd2a30ed9e8e084adf21668c82245f81" />

Using IIFE:

- Enables you to attach private data to a function.
- Creates fresh environments.
- Avoids polluting the global namespace.

### Context

**Context** is often confused as the same thing as Scope. To clear things up, lets keep the following in mind:
**Context** is most often determined by how a function is invoked. It always refers to the value of this in a particular part of your code.
**Scope** refers to the visibility of variables.

### Function calls: call, apply and bind

All of these three methods are used to attach thisinto function and the difference is in the function invocation.

.call() invokes the function immediately and requires you to pass in arguments as a list (one by one).

.apply() invokes the function immediately and allows you to pass in arguments as an array.

.call() and .apply() are mostly equivalent and are used to borrow a method from an object. Choosing which one to use depends on which one is easier to pass the arguments in. Just decide whether it’s easier to pass in an array or a comma separated list of arguments.

**Quick tip:** **A**pply for **A**rray — **C**all for **C**omma.

<Gist id="5250167cbfd155b45817fd1903378c6e" />

**Note**: If you pass in an array as one of the arguments on a call function, it will treat that entire array as a single element. 
ES6 allows us to spread an array as arguments with the call function.

```javascript
char.knows.call(Snow, ...["nothing", "Jon"]); // You know nothing, Jon Snow
```

.bind() returns a new function, with a certain context and parameters. It is usually used when you want a function to be called later with a certain context.

That is possible thanks to its ability to maintain a given context for calling the original function. This is useful for asynchronous callbacks and events.

.bind() works like the call function. It requires you to pass in the arguments one by one separated by a comma.

<Gist id="8f811c287891fd1b177d5db6993b9c76" />

### 'this' keyword

Understanding the keyword thisin JavaScript, and what it is referring to, can be quite complicated at times.

The value of thisis usually determined by a functions execution context. Execution context simply means how a function is called.

The keyword thisacts as a placeholder, and will refer to whichever object called that method when the method is actually used.

The following list is the ordered rules for determining this. Stop at the first one that applies:

- **new** **binding** — When using the new keyword to call a function, thisis the newly constructed object.

<Gist id="382cc89b2759c87cc962670e5a301f1a" />

- **Explicit binding** — When call or apply are used to call a function, thisis the object that is passed in as the argument.
  **Note**: .bind() works a little bit differently. It creates a new function that will call the original one with the object that was bound to it.

<Gist id="9563de1a62e500ecd0e3a06738f7d4f9" />

- **Implicit binding** — When a function is called with a context (the containing object), thisis the object that the function is a property of.
  This means that a function is being called as a method.

<Gist id="1396312d7f2691b0ecde4365249530c9" />

- **Default binding** — If none of the above rules applies, thisis the global object (in a browser, it’s the window object).
  This happens when a function is called as a standalone function.
  A function that is not declared as a method automatically becomes a property of the global object.

<Gist id="5a6d2419f84087903cee98c530bbdd0c" />

**Note**: This also happens when a standalone function is called from within an outer function scope.

<Gist id="54b951399b507020ef9a5dd442b2f389" />

- **Lexical this** — When a function is called with an arrow function =>, thisreceives the thisvalue of its surrounding scope at the time it’s created.
  thiskeeps the value from its original context.

<Gist id="3c89befdc4bb2e2cce7aac85f4c62568" />

### Strict Mode

JavaScript is executed in strict mode by using the “use strict” directive. Strict mode tightens the rules for parsing and error handling on your code.

Some of its benefits are:

- **Makes debugging easier **— Code errors that would otherwise have been ignored will now generate errors, such as assigning to non-writable global or property.
- **Prevents accidental global variables** — Assigning a value to an undeclared variable will now throw an error.
- **Prevents invalid use of delete** — Attempts to delete variables, functions and undeletable properties will now throw an error.
- **Prevents duplicate property names or parameter values** — Duplicated named property in an object or argument in a function will now throw an error. (This is no longer the case in ES6)
- **Makes eval() safer **— Variables and functions declared inside an eval() statement are not created in the surrounding scope.
- **“Secures” JavaScript eliminating this coercion** — Referencing a this value of null or undefined is not coerced to the global object. This means that in browsers it’s no longer possible to reference the window object using this inside a function.

### **`new` keyword**

The new keyword invokes a function in a special way. Functions invoked using the new keyword are called **constructor functions**.

So what does the new keyword actually do?

1.  Creates a new object.
2.  Sets the **object’s** prototypeto be the prototypeof the **constructor function**.
3.  Executes the constructor function with this as the newly created object.
4.  Returns the created object. If the constructor returns an object, this object is returned.

<Gist id="fc8349759be2c7aee1c3fe61d1651ac0" />

What is the difference between invoking a function with the new keyword and without it?

<Gist id="f4db26183f24b85d19b55c29bdc4a9b5" />

### Prototype and Inheritance

Prototype is one of the most confusing concepts in JavaScript and one of the reason for that is because there are two different contexts in which the word **prototype** is used.

- **Prototype relationship** Each object has a **prototype**object, from which it inherits all of its prototype’s properties.
  .**proto** is a non-standard mechanism (available in ES6) for retrieving the prototypeof an object _(\*)_. It points to the object’s “parent” —the **object’s prototype**. 
  All normal objects also inherit a .constructor property that points to the constructor of the object. Whenever an object is created from a constructor function, the .**proto** property links that object to the .prototype property of the constructor function used to create it.
  _(\*)_ \_Object.getPrototypeOf()\_is the standard ES5 function for retrieving the prototype of an object.
- **Prototype property** Every function has a .prototype property. 
  It references to an object used to attach properties that will be inherited by objects further down the prototype chain. This object contains, by default, a .constructor property that points to the original constructor function. 
  Every object created with a constructor function inherits a constructor property that points back to that function.

<Gist id="559d31ffa79f9f8f29781c2e7365fc25" />

#### **Prototype Chain**

The prototype chain is a series of links between objects that reference one another.

When looking for a property in an object, JavaScript engine will first try to access that property on the object itself.

If it is not found, the JavaScript engine will look for that property on the object it inherited its properties from — the **object’s prototype**.

The engine will traverse up the chain looking for that property and return the first one it finds.

The last object in the chain is the built-in Object.prototype, which has null as its **prototype**. Once the engine reaches this object, it returns undefined.

#### Own vs Inherited Properties

Objects have own properties and inherited properties.

Own properties are properties that were defined on the object.

Inherited properties were inherited through prototype chain.

<Gist id="a538f482a3e0f347b6cecbd36f713b60" />

**Object.create(**_obj_**) **— Creates a new object with the specified **prototype**object and properties.

<Gist id="8dba6a2cfcb71f65799dcdf67b49b497" />

#### **Inheritance by reference**

An inherited property is a copy by reference of the **prototype object’s**property from which it inherited that property.

If an object’s property is mutated on the prototype, objects which inherited that property will share the same mutation. But if the property is replaced, the change will not be shared.

<Gist id="077b60ea3ab52644fc05b1e2d4e63d2e" />

#### **Classical Inheritance vs. Prototypal Inheritance**

In classical inheritance, objects inherit from classes — like a blueprint or a description of the object to be created — and create sub-class relationships. These objects are created via constructor functions using the new keyword.

The downside of classical inheritance is that it causes:
inflexible hierarchy
tight coupling problems
fragile base class problems
duplication problems
And the so famous gorilla/banana problem — *“What you wanted was a banana, what you got was a gorilla holding the banana, and the entire jungle.”*

In prototypal inheritance, objects inherit directly from other objects. Objects are typically created via Object.create(), object literals or factory functions.

There are three different kinds of prototypal inheritance:

- **Prototype delegation** — A delegate prototype is an object which is used as a model for another object. When you inherit from a delegate prototype, the new object gets a reference to the prototype and its properties. 
  This process is usually accomplished by using Object.create().
- **Concatenative inheritance **— The process of inheriting properties from one object to another by copying the object’s prototype properties, without retaining a reference between them. 
  This process is usually accomplished by using Object.assign().
- **Functional inheritance** — This process makes use of a _factory function(\*)_ to create an object, and then adds new properties directly to the created object.This process has the benefit of allowing data encapsulation via closure.
  **_(\*)Factory function_** is a function that is not a class or constructor that returns an object without using the new keyword.

<Gist id="d44e8a9eb035553e5eaefbed5939df2f" />

You can find a complete article on this topic by [Eric Elliott](https://medium.com/@_ericelliott) [here](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9).

#### Favor composition over class inheritance

Many developers agree that class inheritance should be avoided in most cases. In this pattern you design your types regarding what they **are**, which makes it a very strict pattern.

Composition, on the other hand, you design your types regarding what they **do**, which makes it more flexible and reusable.

Here is a nice video on this topic by [Mattias Petter Johansson](https://medium.com/@mpjme)

<YouTube id="wfMtDGfHWpA" />

### Asynchronous JavaScript

JavaScript is a single-threaded programming language. This means that the JavaScript engine can only process a piece of code at a time. One of its main consequences is that when JavaScript encounters a piece of code that takes a long time to process, it will block all code after that from running.

JavaScript uses a data structure that stores information about active functions named **Call Stack**. A Call Stack is like a pile of books. Every book that goes into that pile sits on top of the previous book. The last book to go into the pile will be the first one removed from it, and the first book added to the pile will be the last one removed.

The solution to executing heavy pieces of code without blocking anything is **asynchronous callback functions**. These functions are executed later — **asynchronously**.

The asynchronous process begins with an asynchronous callback functions placed into a **Heap or** region of memory. You can think of the Heap as an **Event Manager**. The Call Stack asks the Event Manager to execute a specific function only when a certain event happens. Once that event happens, the Event Manager moves the function to the Callback Queue. **Note**: When the Event Manager handles a function, the code after that is not blocked and JavaScript continues its execution.

The Event Loop handles the execution of multiple pieces of your code over time. The Event Loop monitors the Call Stack and the Callback Queue.

The Call Stack is constantly checked whether it is empty or not. When it is empty, the Callback Queue is checked if there is a function waiting to be invoked. When there is a function waiting, the first function in the queue is pushed into the Call Stack, which will run it. This checking process is called a ‘tick’ in the Event Loop.

Let’s break down the execution of the following code to understand how this process works:

<Gist id="8de2cd85cb86c29450d440bd8431f00b" />

1.  Initially the Browser console is clear and the Call Stack and Event Manager are empty.
2.  first() is added to the Call Stack.
3.  console.log("First message") is added to the Call Stack.
4.  console.log("First message") is executed and the Browser console displays **“First message”**_._
5.  console.log("First message") is removed from the Call Stack.
6.  first() is remove from the Call Stack.
7.  setTimeout(second, 0) is added to the Call Stack.
8.  setTimeout(second, 0) is executed and handled by the Event Manager. And after 0ms the Event Manager moves second() to the Callback Queue.
9.  setTimeout(second, 0) is now completed and removed from the Call Stack.
10. third() is added to the Call Stack.
11. console.log("Third message") is added to the Call Stack.
12. console.log("Third message") is executed and the Browser console displays **“Third message”**_._
13. console.log("Third message") is removed from the Call Stack.
14. Call Stack is now empty and the second() function is waiting to be invoked in the Callback Queue.
15. The Event Loop moves second() from the Callback Queue to the Call Stack.
16. console.log("Second message") is added to the Call Stack.
17. console.log("Second message") is executed and the Browser console displays **“Second message”**.
18. console.log("Second message") is removed from the Call Stack.
19. second() is removed from the Call Stack.

**Note**: The second() function is not executed after 0ms. The **time** you pass in to setTimeout function does not relate to the delay of its execution. The Event Manager will wait the given timebefore moving that function into the Callback Queue. Its execution will only take place on a future ‘tick’ in the Event Loop.
]]></description>
            <link>https://hungvn.com/blog/kien-thuc-cho-phong-van-javascript-developer</link>
            <guid isPermaLink="true">https://hungvn.com/blog/kien-thuc-cho-phong-van-javascript-developer</guid>
            <pubDate>Tue, 02 Jan 2018 22:12:14 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cải thiện tốc độ Web App với Tinder]]></title>
            <description><![CDATA[
Tinder recently swiped right on the web. Their new responsive [Progressive Web App](https://developers.google.com/web/progressive-web-apps/) — [Tinder Online](https://tinder.com) — is available to 100% of users on desktop and mobile, employing techniques for [JavaScript performance optimization](https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e), [Service Workers](https://developers.google.com/web/fundamentals/primers/service-workers/) for network resilience and [Push Notifications](https://developers.google.com/web/fundamentals/push-notifications/) for chat engagement. Today we’ll walk through some of their web perf learnings.

![](https://cdn-images-1.medium.com/max/2000/1*1HmfQhMAQL8kukiNtMZRjA.png)

### Journey to a Progressive Web App

Tinder Online started with the goal of getting adoption in new markets, striving to hit feature parity with V1 of Tinder’s experience on other platforms.

**The MVP for the PWA took 3 months to implement using** [**React**](https://reactjs.com) **as their UI library and** [**Redux**](https://redux.js.org) **for state management.** The result of their efforts is a PWA that delivers the core Tinder experience in **10%** of the data-investment costs for someone in a data-costly or data-scarce market:

![](https://cdn-images-1.medium.com/max/2000/1*cqYbI-L0zukfYS0ZAwUtqA.png)Comparing the data-investment for Tinder Online vs the native apps. It’s important to note that this isn’t comparing apples to apples, however. The PWA loads code for new routes on demand, and the cost of additional code is amortized over the lifetime of the application. Subsequent navigations still don’t cost as much data as the download of the app.

Early signs show good swiping, messaging and session length compared to the native app. With the PWA:

- Users swipe more on web than their native apps
- Users message more on web than their native apps
- Users purchase on par with native apps
- Users edit profiles more on web than on their native apps
- Session times are longer on web than their native apps

### Performance

The mobile devices Tinder Online’s users most commonly access their web experience with include:

- Apple iPhone & iPad
- Samsung Galaxy S8
- Samsung Galaxy S7
- Motorola Moto G4

Using the [Chrome User Experience report](https://developers.google.com/web/tools/chrome-user-experience-report/) (CrUX), we’re able to learn that the majority of users accessing the site are on a 4G connection:

![](https://cdn-images-1.medium.com/max/2000/1*gO4n3kBs5Zy1eAkMQqxx7w.png)

_Note: Rick Viscomi recently covered CrUX on_ [_PerfPlanet_](https://calendar.perfplanet.com/2017/finding-your-competitive-edge-with-the-chrome-user-experience-report/) _and Inian Parameshwaran covered_ [_rUXt_](https://calendar.perfplanet.com/2017/introducing-ruxt-visualizing-real-user-experience-data-for-1-2-million-websites/) _for better visualizing this data for the top 1M sites._

Testing the new experience on [WebPageTest](https://www.webpagetest.org/result/171224_ZB_13cef955385ddc4cae8847f451db8403/) and [Lighthouse](https://github.com/GoogleChrome/lighthouse/) (using the Galaxy S7 on 4G) we can see that they’re able to load and get interactive in **under 5 seconds**:

![](https://cdn-images-1.medium.com/max/2000/1*e-EHgbBBNXyuce8Z836Sgg.png)

There is of course **lots of room** to improve this further on [median mobile hardware](https://www.webpagetest.org/lighthouse.php?test=171224_NP_f7a489992a86a83b892bf4b4da42819d&run=3) (like the Moto G4), which is more CPU constrained:

![](https://cdn-images-1.medium.com/max/2000/1*VJ3ZbSQtIjxsIW8Feuiejw.png)

Tinder are hard at work on optimizing their experience and we look forward to hearing about their work on web performance in the near future.

### Performance Optimization

Tinder were able to improve how quickly their pages could load and become interactive through a number of techniques. They implemented route-based code-splitting, introduced performance budgets and long-term asset caching.

### Route-level code-splitting

Tinder initially had large, monolithic JavaScript bundles that delayed how quickly their experience could get interactive. These bundles contained code that wasn’t immediately needed to boot-up the core user experience, so it could be broken up using [code-splitting](https://webpack.js.org/guides/code-splitting/). **It’s generally useful to only ship code users need upfront and lazy-load the rest as needed**.

To accomplish this, Tinder used [React Router](https://reacttraining.com/react-router/) and [React Loadable](https://github.com/thejameskyle/react-loadable). As their application centralized all their route and rendering info a configuration base, they found it straight-forward to implement code splitting at the top level.

**In summary:**

React Loadable is a small library by James Kyle to make component-centric **code splitting** easier in React. **Loadable** is a higher-order component (a function that creates a component) which makes it easy to **split** up bundles at a component level.

Let’s say we have two components “A” and “B”. Before code-splitting, Tinder statically imported everything (A, B, etc) into their main bundle. This was inefficient as we didn’t need both A and B right away:

![](https://cdn-images-1.medium.com/max/2000/1*DoTby4l_-A3TNdiUSZ0LmA.png)

After adding code-splitting, components A and B could be loaded as and when needed. Tinder did this by introducing React Loadable, [dynamic import()](https://webpack.js.org/guides/code-splitting/#dynamic-imports) and [webpack’s magic comment syntax](https://medium.com/faceyspacey/how-to-use-webpacks-new-magic-comment-feature-with-react-universal-component-ssr-a38fd3e296a) (for naming dynamic chunks) to their JS:

![](https://cdn-images-1.medium.com/max/2000/1*aPY-1uGEvPV1dNKrrD8z4Q.png)

For “vendor” (library) chunking, Tinder used the webpack [**CommonsChunkPlugin**](https://webpack.js.org/plugins/commons-chunk-plugin/) to move commonly used libraries across routes up to a single bundle file that could be cached for longer periods of time:

![](https://cdn-images-1.medium.com/max/2000/1*R-kXPcn937BNoFXLukPJPg.png)

Next, Tinder used [React Loadable’s preload support](https://github.com/thejameskyle/react-loadable#loadablecomponentpreload) to preload potential resources for the next page on control component:

![](https://cdn-images-1.medium.com/max/2000/1*G2JvbNCsm4eBXbGgyW6OmA.png)

Tinder also used [Service Workers](https://developers.google.com/web/fundamentals/primers/service-workers/) to precache all their route level bundles and include routes that users are most likely to visit in the main bundle without code-splitting. They’re of course also using common optimizations like JavaScript minification via UglifyJS:

```javascript
new webpack.optimize.UglifyJsPlugin({
      parallel: true,
      compress: {
        warnings: false,
        screw_ie8: true
      },
      sourceMap: SHOULD_SOURCEMAP
    }),
```

#### Impact

After introducing route-based code-splitting their main bundle sizes went down from 166KB to 101KB and DCL improved from 5.46s to 4.69s:

![](https://cdn-images-1.medium.com/max/2000/1*1Tt8bnnkyIi8aEw0BjRgMw.png)

### Long-term asset caching

Ensuring [long-term caching](https://webpack.js.org/guides/caching/) of static resources output by webpack benefits from using [chunkhash] to add a cache-buster to each file.

![](https://cdn-images-1.medium.com/max/2000/1*nofQB3Q-8IUo9f1Eipd0xw.png)

Tinder were using a number of open-source (vendor) libraries as part of their dependency tree. Changes to these libraries would originally cause the [chunkhash] to change and invalidate their cache. To address this, Tinder began defining a [whitelist of external dependencies](https://gist.github.com/tinder-rhsiao/89cd682c34d1e1307111b091801e6fe5]%28https://gist.github.com/tinder-rhsiao/89cd682c34d1e1307111b091801e6fe5) and splitting out their webpack manifest from the main chunk to improve caching. The bundle size is now about 160KB for both chunks.

### Preloading late-discovered resources

As a refresher, [resource prioritization](https://developers.google.com/web/fundamentals/performance/resource-prioritization) is a declarative instruction to the browser to load critical, late-discovered resources earlier on. In single-page applications, these resources can sometimes be JavaScript bundles.

![](https://cdn-images-1.medium.com/max/1600/1*CaObLc_tGJvnllyV3CGD5w.png)

Tinder implemented support for to preload their critical JavaScript/webpack bundles that were important for the core experience. This reduced load time by 1s and first paint from 1000ms to about 500ms.

![](https://cdn-images-1.medium.com/max/2000/1*AtzElAKy_pCvRjZN__YSsQ.png)

### Performance budgets

Tinder adopted **performance budgets** for helping them hit their performance goals on mobile. As Alex Russell noted in “[Can you afford it?: real-world performance budgets](https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/)”, you have a limited headroom to deliver an experience when considering slow 3G connections being used on median mobile hardware.

To get and stay interactive quickly, Tinder enforced a budget of ~155KB for their main and vendor chunks, asynchronous (lazily loaded) chunks are ~55KB and other chunks are ~35KB. CSS has a limit of 20KB. This was crucial to ensuring they were able to avoid regressing on performance.

![](https://cdn-images-1.medium.com/max/2000/1*OgDLsMxsy6IO79NmjQtcng.png)

### Webpack Bundle Analysis

[Webpack Bundle Analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) allows you to discover what the dependency graph for your JavaScript bundles looks like so you can discover whether there’s low-hanging fruit to optimize.

![](https://cdn-images-1.medium.com/max/1600/1*qsiUA0G50a4p3y2e4p7CyA.png)

Tinder used Webpack Bundle Analyzer to discover areas for improvement:

- **Polyfills:** Tinder are targeting modern browsers with their experience but also support IE11 and Android 4.4 and above. **To keep polyfills & transpiled code to a minimum, they use For polyfills, they use** [**babel-preset-env**](https://github.com/babel/babel-preset-env) **and** [**core-js**](https://github.com/zloirock/core-js)**.**
- **Slimmer use of libraries:** Tinder replaced [localForage](https://github.com/localForage/localForage) with direct use of IndexedDB.
- **Better splitting:** Split out components from the main bundles which were not required for first paint/interactive
- **Code re-use:** Created asynchronous common chunks to abstract chunks used more than three times from children.
- **CSS:** Tinder also removed [critical CSS](https://www.smashingmagazine.com/2015/08/understanding-critical-css/) from their core bundles (as they had shifted to server-side rendering and delivered this CSS anyway)

![](https://cdn-images-1.medium.com/max/1600/1*ZL3i2BRHo8Sq_dv1NyA8Dw.png)

Using bundle analysis led to also also taking advantage of Webpack’s [Lodash Module Replacement Plugin](https://github.com/lodash/lodash-webpack-plugin). The plugin creates smaller Lodash builds by replacing feature sets of modules with noop, identity or simpler alternatives:

![](https://cdn-images-1.medium.com/max/2000/1*of2Mv5ypTySRpTZQZVRj7A.png)

Webpack Bundle Analyzer can be integrated into your Webpack config. Tinder’s setup for it looks like this:

```javascript
plugins: [
      new BundleAnalyzerPlugin({
        analyzerMode: 'server',
        analyzerPort: 8888,
        reportFilename: 'report.html',
        openAnalyzer: true,
        generateStatsFile: false,
        statsFilename: 'stats.json',
        statsOptions: null
      })
```

The majority of the JavaScript left is the main chunk which is trickier to split out without architecture changes to Redux Reducer and Saga Register.

### CSS Strategy

Tinder are using [Atomic CSS](https://acss.io/) to create highly reusable CSS styles. All of these atomic CSS styles are inlined in the initial paint and some of the rest of the CSS is loaded in the stylesheet (including animation or base/reset styles). Critical styles have a maximum size of 20KB gzipped, with recent builds coming in at a lean < 11KB.

Tinder use [CSS stats](http://cssstats.com/stats?url=https%253A%252F%252Ftinder.com&ua=Browser%2520Default%0A) and Google Analytics for each release to keep track of what has changed. Before Atomic CSS was being used, average page load times were ~6.75s. After they were ~5.75s.

![](https://cdn-images-1.medium.com/max/2000/1*Uv_at6Xs7QYHZJ0iy8c7GQ.png)

Tinder Online also uses the PostCSS [Autoprefixer plugin](https://twitter.com/autoprefixer) to parse CSS and add vendor prefixes based on rules from [Can I Use](http://caniuse.com):

```javascript
new webpack.LoaderOptionsPlugin({
    options: {
    context: paths.basePath,
    output: { path: './' },
    minimize: true,
    postcss: [
        autoprefixer({
        browsers: [
            'last 2 versions',
            'not ie < 11',
            'Safari >= 8'
        ]
        })
      ]
    }
}),
```

### Runtime performance

#### Deferring non-critical work with requestIdleCallback()

To improve runtime performance, Tinder opted to use [requestIdleCallback()](https://developers.google.com/web/updates/2015/08/using-requestidlecallback) to defer non-critical actions into idle time.

```javascript
requestIdleCallback(myNonEssentialWork);
```

This included work like instrumentation beacons. They also simplified some HTML composite layers to reduce paint count while swiping.

**Using requestIdleCallback() for their instrumentation beacons while swiping:**

before..

![](https://cdn-images-1.medium.com/max/1600/1*oHJ8IjCs7AKdCrt9b28ZPw.png)

and after..

![](https://cdn-images-1.medium.com/max/1600/1*UTQuSSp7MGMY06mwYtQmaw.png)

### Dependency upgrades

**Webpack 3 + Scope Hoisting**

In older versions of webpack, when bundling each module in your bundle would be wrapped in individual function closures. These wrapper functions made it slower for your JavaScript to execute in the browser. [Webpack 3](https://medium.com/webpack/webpack-3-official-release-15fd2dd8f07b) introduced “scope hoisting” — the ability to concatenate the scope of all your modules into one closure and allow for your code to have a faster execution time in the browser. It accomplishes this with the Module Concatenation plugin:

```javascript
new webpack.optimize.ModuleConcatenationPlugin();
```

**Webpack 3’s scope hoisting improved Tinder’s initial JavaScript parsing time for vendor chunk by 8%.**

**React 16**

React 16 introduced improvements that [decreased React’s bundle size](https://reactjs.org/blog/2017/09/26/react-v16.0.html#reduced-file-size) compared to previous versions. This was in part due to better packaging (using Rollup) as well as removing now unused code.

**By updating from React 15 to React 16, Tinder reduced the total gzipped size of their vendor chunk by ~7%.**

The size of react + react-dom used to be~50KB gzipped and is now just ~**35KB**. Thanks to [Dan Abramov](https://twitter.com/dan_abramov), [Dominic Gannaway](https://twitter.com/trueadm) and [Nate Hunzaker](https://twitter.com/natehunzaker) who were instrumental in trimming down React 16’s bundle size.

### Workbox for network resilience and offline asset caching

Tinder also use the [Workbox Webpack plugin](https://developers.google.com/web/tools/workbox/get-started/webpack) for caching both their [Application Shell](https://developers.google.com/web/fundamentals/architecture/app-shell) and their core static assets like their main, vendor, manifest bundles and CSS. This enables network resilience for repeat visits and ensures that the application starts-up more quickly when a user returns for subsequent visits.

![](https://cdn-images-1.medium.com/max/2000/1*yXpAzyA1ODPk2OSOTA6Lhg.png)

### Opportunities

Digging into the Tinder bundles using [source-map-explorer](https://www.npmjs.com/package/source-map-explorer) (another bundle analysis tool), there are additional opportunities for reducing payload size. Before logging in, components like Facebook Photos, notifications, messaging and captchas are fetched. Moving these away from the critical path could save up to 20% off the main bundle:

![](https://cdn-images-1.medium.com/max/2000/1*G1nq7BNZPEo2mFr_my5zjA.png)

Another dependency in the critical path is a 200KB Facebook SDK script. Dropping this script (which could be lazily loaded when needed) could shave 1 second off initial loading time.

### Conclusions

Tinder are still iterating on their Progressive Web App but have already started to see positive results from the fruits of their labor. Check out Tinder.com and stay tuned for more progress in the near future!

_With thanks and congrats to Roderick Hsiao, Jordan Banafsheha, and Erik Hellenbrand for launching Tinder Online and their input to this article. Thanks to Cheney Tsai for his review._

**Related reading:**

- [A Pinterest PWA performance case study](https://medium.com/dev-channel/a-pinterest-progressive-web-app-performance-case-study-3bd6ed2e6154)
- [A Treebo React & Preact performance case study](https://medium.com/dev-channel/treebo-a-react-and-preact-progressive-web-app-performance-case-study-5e4f450d5299)
- [Twitter Lite and high-performance PWAs at scale](https://medium.com/@paularmstrong/twitter-lite-and-high-performance-react-progressive-web-apps-at-scale-d28a00e780a3)

This article was cross-posted from [Performance Planet](https://calendar.perfplanet.com/2017/a-tinder-progressive-web-app-performance-case-study/). If you’re new to React, I’ve found [React for Beginners](https://goo.gl/G1WGxU) a comprehensive starting point.
]]></description>
            <link>https://hungvn.com/blog/cai-thien-toc-do-web-app-voi-tinder</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cai-thien-toc-do-web-app-voi-tinder</guid>
            <pubDate>Mon, 25 Dec 2017 18:29:59 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[JavaScript Start-up Performance]]></title>
            <description><![CDATA[How JavaScript parse, compile, and execution costs slow down page start-up, and the practical techniques you can use to fix them.]]></description>
            <link>https://hungvn.com/blog/javascript-start-up-performance</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-start-up-performance</guid>
            <pubDate>Sat, 16 Dec 2017 14:46:39 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Hiểu rõ về Regular Expressions: RegEx không khó như tưởng tượng]]></title>
            <description><![CDATA[
Are you one of those people who stays away from regular expressions because it looks like a foreign language? I was one. Not anymore.

Think of all those sounds, traffic signs and smells that you can recognize. Regular expressions are no different. It’s like a sign language to analyze strings.

We are going to get our head around regular expressions today. At least, **regularly** used expressions.

Much like any programming language, a regular expression is a succinct language in its own right.

We will know how to put regular expressions to good use by the end of this article. We will solve simple problems and learn loads in the process.

Are you willing to invest 30 minutes and come out enlightened in RegEx? Settle down then.

#### Why regular expressions?

We each have our own ‘why’, don’t we? One may be to test if the string is a valid hex color code. You may be writing a processor library such as [Sass](https://github.com/search?l=&q=regexp+repo%3Asass%2Fsass&ref=advsearch&type=Code&utf8=%E2%9C%93) that leverages RegEx.

I’ll let the universe throw the **why** at you and help you cover the **how**.

### 0\. Get Your Playground Ready

#### References

Most of the time, I find this page adequate to get going: [Regular Expressions from MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions). In fact, that page is all you need. You can stop reading this post. Right now. Close this tab. 😉

Still with me? Thanks. You need a sandbox to play around in. Luckily, one is available on your browser. Just use the DevTools in your browser’s console.

#### Familiarize yourself with the syntax

To start with, we are going to use the /expression/.test('string') syntax.

An expression is any regular expression that we build. A string is the string under test. The test method returns true or false depending on the match.

Slashes mark the start and end of the expression. Treat them like the double quotes (“) and single quotes (‘) that you use to the mark start and end of a plain string.

The expression between / is a literal. **They are treated as literal characters.** Variable names wouldn’t be resolved down to their contents.

To make it dynamic, we’ll have to go via the constructor route, using new RegEx(variable_name) syntax. This will come to rescue towards the end of the post.

**Do it right now.** Just type this into your browser console.

```javascript
/a/.test("a"); //true
/a/.test("b"); //false
```

If that works, you are ready. Don’t worry about what it is. That’s what we are going to breakdown into pieces in the following lines.

Let’s dive in…

### 1\. Start Small With Letters

Let’s start small. We need to find if a string has a particular character. Look for the character a in a string.

Here is the expression in all its glory:

```javascript
/a/.test("abc"); //true
/a/.test("bcd"); //false
/a/.test("cba"); //true
```

The expression does what we asked for, “Look for a in the string under test”. In our case, abc and bca do have the character a. But bcd does not have it.

#### Breakdown

Now, that’s a lot of slashes and backslashes. Let’s break them down.

We’ve seen that /expression/ is how we build regular expressions. So no question about slash there. In fact, we can even **assign it to a variable** and make it look better.

**The same code:**

```javascript
let e = /a/;
e.test("abc"); //true
e.test("bcd"); //false
e.test("cba"); //true
```

The expression between slashes is just a single character a in our case. We are looking only for that one character.

#### Reach Multi-Characters

Let’s scale the solution.

What if you want to find more than one character?

Put them in sequence. Treat them as a substring.

Here is an example:

```javascript
/ab/.test("abacus"); //true
/bac/.test("abacus"); //true
/abc/.test("abacus"); //false
/abas/.test("abacus"); //false
```

The string under test should contain the exact expression within slashes. We get a match if that condition is met.

bac is within abacusbut abas is not in abacus as it is. Even though we have those characters scrambled, we do not get an exact match.

#### Review Ground Covered

Symbol /.../ . Slash (/) marks the start and end of the regular expression. Ignore the dots, that’s where we place the pattern. The /a/ character between slashes is a pattern matched on string under test. The /abc/ characters between slashes are looked up as a sub-string during the pattern matching test on string under test.

### 2\. Patterns in Numbers

Let’s spice it up a bit. Let’s say you want to find out if a string is full of numeric characters.

Here it is:

```javascript
let e = /0|1|2|3|4|5|6|7|8|9/;
e.test("42"); //true
e.test("The answer is 42"); //true
```

First of all, the pattern looks pretty long. But the same long streak of characters **can be expressed in just two characters**. I reserved it towards end of this section for a dramatic closure.

The second case shouldn’t be true. We’ll deal with it a bit later.

For now, the pipe symbol (|) means **or**. Outside of regular expressions, we’ve used it as a bitwise **or** and conditional **or** with double pipes (||). That’s the same guy.

I could call that easy and call it a day. But you would scream for something better, right? We are developers. We spend the best part of our day thinking about better Bash and Git aliases to save few keystrokes.

Should I type in nine pipe symbols? Nah.

Here we go again:

```javascript
e = /[0123456789]/;
e.test("42"); //true
e.test("The answer is 42"); //still true
```

This is better. 9 pipes were replaced with 2 square brackets. 7 characters were saved. That’s 77.7% less keystrokes.

By the way, anything within square brackets is considered as Either this or that. It is a character set. In our case, the string should contain either 0, or 1, or 2, or…bear with me, I promised myself to write 1000 words a day, or 3 or 4 or 5. All right, let’s stop. You get it.

What are you saying? It still looks quite lengthy? Not satisfied?

Okay, here we go once again:

```javascript
e = /[0-9]/;
e.test(42); //true
e.test("42"); //true
e.test("The answer is 42"); //true!
```

How about that? Looks much cleaner, doesn’t it? Anything within square brackets [] means **or**. 0-9 marks a range, meaning zero to nine.

So the test looks for characters from zero to nine in the test string.

As you can see, the test takes numbers too.

#### The prefix and suffix patterns

Let’s now address that failing second case. The answer is 42 matches our test because our pattern looks for numeric characters somewhere **within** the string. **Not start to end**.

Let’s bring in ^ and $ to help us.

- ^ means the **start** of the string. He is a double agent and he’ll trip us off. His second avatar is unmasked only in the last section.
- $ means the **end** of the string.

Let’s get the prefix pattern sorted out:

```javascript
/^a/.test("abc"); //true
/^a/.test("bca"); //false
/^http/.test("https://pineboat.in"); //true /^http/.test("ftp://pineboat.in"); //false
```

Any pattern that follows ^ should be at the start of the string under test.

The second string starts with b while our pattern looks for a. The fourth one looks for http while the string starts with ftp. This is the reason they fail.

#### The suffix patterns

The suffix pattern follows. $ at the end of the pattern directs the test to look for end of string.

```javascript
/js$/.test("regex.js"); //true
/js$/.test("regex.sj"); //false
```

That should sound in your head like, “Look for js and then the end of the string”. Better yet, “Look for a string that ends in js”.

#### Pattern match End to End

That paves the road to pattern match start to end, you might as well call it end to end.

```javascript
let e = /^[0-9]$/;
e.test("42"); //false - NO!
e.test("The answer is 42"); //false
e.test("7"); //true
```

Surprisingly, the first one failed when we added ^ and $.

`/^[0-9]$/` reads like, “Go to the start of the string. Look for a **single numeral** from the character set. Check if the string ends right there.” That’s the reason the last entry returned true. It is just a single number, start to end.

That’s not what we wanted. We wanted to test if the string had one or more numerals.

We are very close. One last thing we need to learn is how to instruct the pattern to look for more than one character in the set.

#### Tale of Three Musketeers

A question mark (?), a plus (+) and an asterisk (\*) met at a battle ground. Each is differently sighted.

The humble question mark (?)says, “I can see none or just one.”

Plus (+) says, “I need to see at least one or more.”

Asterisk (\*) says, “I get you both. I can see none, one, or more.”

**One of them is cleverly hiding what he is capable of.**

The question mark gets on stage first:

```javascript
/a?/.test(""); //true
/a?/.test("a"); //true
/a?/.test("b"); //true!
/a?/.test("aa"); //true
/^a?$/.test("aa"); //false
```

- Matches empty string "" 
  as ? stands for 0 or 1
- Matches a 
  one match
- Matches b matches 0 occurrence
- Matches aa 
  one match and the second a is not part of the pattern
- `/^a?$/` does not match aa It looks for zero or one a, start to end, nothing more, nothing less

The plus (+) looks at question mark and remarks, “I’m impressed, but your focus is so binary!”. And takes the stage to show off:

```javascript
/a+/.test("a"); //true
/a+/.test("aa"); //true
/a+/.test("ba"); //true!
/^a+$/.test("aa"); //true
/a+/.test(""); //false
/a+/.test("b"); //false
/^a+$/.test("ab"); //false
```

Remember what plus (+) said? It can match one or more occurrences of preceding pattern.

All those returning true have one or more a. We even managed to get a whole string comprised only of a in the last one that returned true with `/^a+$/`.

false should make sense now, but a word on the last one that returned false. `/^a+$/` looks for a start to end, no other characters allowed. This is why ab failed the test.

Finally, star (\*) of the show gets on stage. He boasts that, “I can duel alone or duel you both at once” and says, “I can match zero, one or more”.

```javascript
/a*/.test("a"); //true
/a*/.test("aa"); //true
/a*/.test("ba"); //true
/a*/.test(""); //true
/a*/.test("b"); //true
/^a*$/.test("aa"); //true
/^a*$/.test(""); //true
/^a*$/.test("ab"); //false
```

Except the last one, _ was able to handle all else. /^a_$/ reads like, 0 or more a start to end. Which is why empty string "" passed the test and "ab" failed.

#### Back to the Universal Answer

Remember where were we before we met the three musketeers? Yes, “The answer is 42”.

Now if we need to look for only numerals, one or more, start to end, what do we do?

```javascript
//Let's throw in a plus
let e = /^[0-9]+$/;
e.test("4"); //true
e.test("42"); //true
e.test("The answer 42"); //false - Hurray
```

The plus sign (+) in [0-9]+ comes to our rescue. Plus means more than one occurrence of the character or pattern in front of it. In our case, more than one numerals.

It also fails the match for our last case The answer is 42 because, there are no numerals at the start of the string.

#### Practice Patterns

- Can you try to write a pattern for hexadecimal numbers (consisting of numerals 0–9 and letters a-f, with an optional # in front)?
- How about a binary number? Can you test if a string is full of just 0 and 1?

#### That Dramatic End

Oh, I almost forgot. [0-9] stands for any of the numeric character set and also has a shorthand version \d.

```javascript
let e = /^\d+$/;
e.test("4"); //true e.test("42"); //true e.test("The answer 42"); //false - Hurray
```

Just two characters denoting numerals. And No, it doesn’t get any shorter than that.

There are a whole bunch of such special patterns to specify clusters such as numbers (\d), alpha numeric characters (\w), white spaces (\s).

#### Review

- [123] The expression within square brackets are a character set
  Any one of the characters match will pass the test. Just ONE character.
- [0-9] 
  Looks for a single numeric digit between 0 to 9
- [0-5] 
  Looks for a single numeric digit between 0 to 5
- [a-z] 
  Looks for a single letter between a to z
- [A-F] 
  Looks for a single letter between A to F
- [123]+ 
  Plus (+) looks for one or more occurrence of the characters within the set This one matches a “23132” sub-string that consists of 1, 2 and 3 within a larger string “abc23132”.
- | Pipe symbol stands for **or**
- \d 
  A shorthand for numerals
  Matches a single numeric digit.
- \D 
  A shorthand for non-numeric characters
  Anything other than numerals that’ll be matched by \d

### 3\. Recurrence Match to Find Duplicates

This is the actual problem I was trying to solve. I dove deep into regular expressions, which eventually led to this post.

You’ve been given a string. Find out if it has been infused with duplicate characters before sunset.

Here is the solution for duplicate characters appearing immediately after an occurrence:

```javascript
let e = /(\w)\1/;
e.test("abc"); //false
e.test("abb"); //true
```

The expression does not match any part of the string abc as there are no duplicate characters in sequence. So it returns false.

But it matches bb part of the string abb and returns true.

Go ahead, type that on your DevTool console. Look at this!

Let’s break it down to understandable pieces.

#### Backslash `\` Unleashed

I’ve been a little quiet about the backslash that was introduced in the last section. To those who have **been there** and **done that**, it may not have been a surprise. They might have **escaped** the confusion. But if you are new to programming world, you need to know more about backslash.

In the regular expression language, backslash is special. The backslash alters the meaning of the characters that follow them. Ring a bell?

What do you call \n when you encounter it in a string? Yes, a new line. We’ve got something similar here.

In fact, `\n` is what you use as a pattern if you want to look for a new line. That’s called escaping the usual meaning of n and giving it a whole new attire called new line.

- `\d` A shorthand for numerals
  Matches a single numeric digit
- `\D` A shorthand for non-numeric characters
  Anything other than numerals that’ll be matched by \d
- `\s`
  Shorthand for single white space character such as space, new line or tab.
- `\S` Antonym of `\s`
  anything other than white space
- `\w` 
  Shorthand for alpha-numeric character
  Matches a-z, A-Z, 0–9 and underscore \_.
- `\W`
  Antonym of \w

#### Recallable Matches

We started this section with the solution for finding duplicate characters. /(\w)\1/ matched "abb". That shows use of memory and recall within regular expressions.

Consider the use of brackets in this format (expression). The resulting string that matches the expression within a bracket is remembered for later use.

\1 remembers and uses the match from first expression that is within brackets. Likewise, \2 from second set of brackets. And so on.

Let’s translate our expression (\w)\1 to plain English:

Match any alpha-numeric character on a given string. Remember it as \1. Check if that character appears right next to the first occurrence.

#### Extension 1 — Reverse Pairs

Let’s say we want to find two characters appearing in reverse order right next to each other. That is like abba. ab is reversed as ba and is right next to each other.

Here is the expression:

```javascript
let e = /(\w)(\w)\2\1/;
e.test("aabb"); //false
e.test("abba"); //true
e.test("abab"); //false
```

The first (\w) matches a and remembers it as \1. The second (\w) matches b and remembers it as \2. Then the expression expects \2 to occur first followed by \1. Hence, abba is the only string that matches the expression.

#### Extension 2 — No duplicates

This time, we are going to look at sequence of characters with no duplicates. No character should be followed by the same character. Plain and simple.

Here, take a look at the solution:

```javascript
let e = /^(\w)(?!\1)$/;
e.test("a"); //true
e.test("ab"); //false
e.test("aa"); //false
```

Not the one we wanted, but close. The middle one shouldn’t be false. But we threw in a few more symbols that need explaining. That means confronting the most powerful musketeer once again.

#### Return of the Question Mark

Remember the three musketeers we met earlier. The humble **question mark is actually the most powerful manipulator** that can get other symbols to do his bidding. That is, if you take the backslash for granted.

A combination of brackets, question mark and exclamation mark (?!), is called a **look ahead**. A negative look ahead to be precise. a(?!b) matches a only if it is **not** followed by b.

Across JavaScript ecosystem, the exclamation mark means **not**. But its cousin CSS takes a u-turn and !important means it is actually very important and should not be overridden. I almost scrolled past [Chen’s tweet](https://twitter.com/vijayabharathib/status/910772769964548096) thinking it is marked not important. I digress.

On the other hand, (?=) is a positive **look ahead**. a(?=b) matches a only if it is followed by b.

We had a solution. (\w)(?!\1) looks for a character without recurrence. **But only for one character.** We need to group it and look for 1 or more occurrences of characters with the use of plus (+). That’s all.

```javascript
let e = /^((\w)(?!\1))+$/;
e.test("madam"); //false
e.test("maam"); //false
```

But it doesn’t seem to be working. If we group the pattern within plain brackets like ((\w)(?!\1)), the \1 does not represent(\w), it represents higher level bracket pair that groups the pattern. So it fails.

What we need is a **forgetful** grouping option. That’s where the question mark, ?, strikes back. It pairs with a colon, (?:) and wipes out any function of memory that the brackets can bring in.

One last time:

```javascript
let e = /^(?:(\w)(?!\1))+$/;
e.test("madam"); //true
e.test("maam"); //false
```

This time, the first level of brackets are not remembered, thanks to ?:, hence, \1 remembers the match returned by \w.

It helps us use the plus + against the overall grouping to find similar pairs of characters start to end, which works like magic.

In English, “Look for a character. Look ahead to ensure it is not followed by the same character. Do this from start to end for all characters.”

#### Review

- \w represents all the alpha-numeric characters
  If you capitalize ‘w’ and use \W', that would mean all characters **other than** alpha-numeric
- ( ) 
  The expression within a bracket is remembered for later use
- \1 remembers and uses the match from first expression that is within brackets
   \2 from second set of brackets. And so on.
- a(?!b) 
  A combination of brackets, question mark and exclamation mark (?!), is called a **look ahead** This matches a only if it is **not** followed by b
- a(?=b) The other side of the coin
  Match a only if it is followed by b. (?:a) 
  **Forgetful grouping** Look for a but don’t remember it
  You can’t use \1 pattern to reuse this match

### 4\. Alternating Sequence

The usecase is simple. Match a string that uses only two characters. Those two characters should alternate throughout the length of the string. Two sample tests for “abab” and “xyxyx” will do.

It wasn’t easy. I got it wrong on several attempts. This [answer](https://stackoverflow.com/questions/45504400/regex-match-pattern-of-alternating-characters) directed me down the right street.

Here is the solution:

```javascript
let e = /^(\S)(?!\1)(\S)(\1\2)*$/;
e.test("abab"); //true
e.test("$#$#"); //true
e.test("#$%"); //false
e.test("$ $ "); //false
e.test("xyxyx"); //false
```

This is where you say, “I’ve had enough!” and throw in the towel.

But wait for the Aha moment! You are 3 feet away from the gold ore, not the right time to stop digging.

Let’s first make sense out of results before we arrive at ‘**how?**’ abab matches. $#$# matches, this is no different from abab.

#$% fails as there is a third character. $ $ fails though they are pairs, because space is excluded in our pattern.

All is well except, xyxyx fails, because our pattern doesn’t know how to handle that last x. We’ll get there.

Let’s take a look at the tools added to our belt. It’ll start to make sense soon.

#### One piece at a time

You already know most of the pieces. `\S` is the opposite of `\s`. `\S` looks for non white space characters.

Now comes the plain English version of `/^(\S)(?!\1)(\S)(\1\2)*$/`.

- Start from the start /^
- Look for a non-white space character (`\S`)
- Remember it as \1
- Look ahead and see if the first character is not followed by the same character (?!\1). 
  Remember this is a **negative look ahead**.
- If we are good so far, look for another character (`\S`)
- Remember it as \2
- Then look for **0 or more pairs of first two matches** (`\1\2`)\*
- Look for such pattern until end of the string $/

Apply that to our test cases. "abab" and "$#$#" match.

#### Tail End

After looking at the solution you may think this does not demand a separate section. But the simplicity of it is elegant. Let’s fix that one failing case xyxyx. As we’ve seen, the last trailing x is the problem. We have a solution for xyxy. All we need is a pattern to say “Look for an optional occurrence of first character”.

As usual, let’s start with the solution.

```javascript
let e = /^(\S)(?!\1)(\S)(\1\2)*\1?$/;
e.test("xyxyx"); //true e.test("$#$#$"); //true
```

The question mark strikes again. There is no escaping him. It’s better we make him our ally than our enemy. A question mark ? after a character or pattern means 0 or 1 match for the preceding pattern. It is non-greedy in gobbling up characters.

In our case, `\1?` means, 0 or 1 match of the first character remembered through first set of brackets.

Easy. Relax.

#### Review

- `\S`
  Represents all characters excluding white space such as a space and new lines
  Note that it is capital S
- `a*` 
  The asterisk or star, looks for 0 or more occurrences of the preceding character. In this case, it is 0 or more a
  Remember plus (+) which looks for 1 or more? Yeah, these guys are cousins.
- `a(?!b)`
  This combination of brackets, question mark and exclamation mark (?!) is called a **look ahead**. 
  This matches a only if it is not followed by b. 
  For example, it matches a in aa, ax, a$ but does not match ab Though it uses bracket, it does not remember the matching character after a.
- `\s` 
  Small caps s matches a single white space character such as a space or new line.
- `a(?=b)` 
  This matches a that is followed by b.
- `^ab*$` 
  You may think this translates to 0 or more occurrences of ab, but it matches a followed by 0 or more b For example: This matches abbb, aand ab, but does not match abab
- `^(ab)*$` 
  This matches 0 or more pairs of ab That means it will match empty string "", aband abab, but not abb
- `a?` 
  `?` matches 0 or 1 occurrence of preceding character or pattern
  `\1?` matches 0 or 1 recurrence of first remembered match

### 5\. Match an email address

#### Warning for Production

Regular expressions alone may not help validate emails. Some would even argue that regular expressions should not be used as it can never match 100% of the emails.

Think about all the fancy domain names popping up. Also consider inclusion of symbols within email addresses, such as dot (.) and plus (+).

You need to validate email twice. Once on the client side to help users avoid misspelled addresses. Start with a semantic input tag type `<input type='email'>`. Some of the browsers automatically validate it without any extra scripting on the front end.

Validate it once again on the server by actually sending a confirmation email.

Haven’t you seen one such lately? Just try to subscribe to this [pineboat](https://www.pineboat.in/). You’ll get an actual email asking you to confirm that it is yours. That confirmation is a solid proof that your email is valid.

That was smooth sailing, wasn’t it?

#### RegEx for Email

Now that we added the disclaimer, you’d actually want to see a pattern right? No, search for regular expression for an email address. One such result from [perl module](http://www.ex-parrot.com/~pdw/Mail-RFC822-Address.html) goes for more than a page.

So, I am not even going to attempt it. Such long regular expressions are generated by computers through pattern builders. Not for mere mortals like us.

### 6\. Match a Strong Password

If you are a coffee person, this is the right time to get a strong one. Because we are at last section of this post, but the longest one so far.

It introduces very few new operators and patterns. But it reuses many patterns. As usual, we reserve the shortest optimized one for last.

The ASCII range is the best part of this post. Because, I learned it while researching for this post.

Now, the problem. Remember that registration form that took several attempts before you could meet their strong password requirements? Weak, good, strong, and very strong? Yeah, we are going to build that validation.

The password should:

- have a minimum of 4 characters
- contain lowercase
- contain uppercase
- contain a number
- contain a symbol

This is a tricky one. Once you start consuming letters, you can’t come back to check if they meet any other condition.There in lies our clue. **We can’t look back, but we can look ahead!**

#### Length of the string

Let’s first test if the string password is 4 characters long. Pretty simple. Use .length on the password string. Done, right? No, who needs a simple solution? Let’s spice it up.

```javascript
//expression with just lookahead
//wouldn't consume any character
e1 = /^(?=.{4,})$/;
e1.test("abc"); //false
e1.test("abcd"); //false //after lookahead,
//pattern to consume character is needed.
e2 = /^(?=.{4,}).*$/;
e2.test("abc"); //false
e2.test("abcd"); //true
```

- You may remember (?=) from our previous work on [“no duplicates”](https://www.pineboat.in/post/regular-expressions-your-ally/#extension-2-no-duplicates) That’s a look ahead use
  It does not consume any character
- The dot (.) is an interesting character
  It means, **any character**.
- `{4,}`
  Stands for at least 4 preceding characters with no maximum limit
- `\d{4}`
  Would look for exactly 4 numerals
- `\w{4,20}`
  Would look for 4 to 20 alpha-numeric characters

Let’s translate `/^(?=.{4,})$/`. “Start from the beginning of the string. Look ahead for at least 4 characters. Don’t remember the match. Come back to the beginning and check if the string ends there.”

Doesn’t sound right. Does it? At least the last bit.

Which is why we brought in the variation `/^(?=.{4,})._$/`. An extra dot and a star. It reads like this, “Start from the beginning. Look ahead for 4 characters. Don’t remember the match. Come back to the beginning. Consume all the characters using .\_ and see if you reach the end of the string.”

This makes sense now. Doesn’t it?

Which is why abc fails and abcd passes the pattern.

#### At least One Number

This is going to be easy.

```javascript
e = /^(?=.*\d+).*$/;
e.test(""); //false
e.test("a"); //false
e.test("8"); //true
e.test("a8b"); //true
e.test("ab890"); //true
```

Start from the beginning of the string /^. Look ahead for 0 or more characters ?=._. Check if 1 or more numbers follow \d+. Once it matches, come back to the beginning (because we were in look ahead). Consume all the characters in the string until end of the string ._$/.

#### At Least One Lowercase Letter

This one follows the same patter as above.

```javascript
e = /^(?=.*[a-z]+).*$/;
e.test(""); //false
e.test("A"); //false
e.test("a"); //true
```

Translation? Sure. “Start from the… okay.” Instead of `\d+`, we have `[a-z]+` which is a character set of letters from a to z.

#### At least One Uppercase Letter

Let’s not overkill. `[A-Z]` instead of `[a-z]` from the previous section will do.

#### At least One Symbol

This is going to be challenging. One way to match symbols is to place a list of symbols in a character set. `/^(?=._[-+=_)(\*&\^%\$#@!~”’:;|\}]{[/?.>,<]+)`.\_$/.test(“$”) That’s all the symbols in a character set. Properly escaped where necessary. It’ll take months for me to write it in plain English.

So to save all of us from eternal pain, here is a simple one:

```javascript
//considers space as symbol
let e1;
e1 = /^(?=.*[^a-zA-Z0-9])[ -~]+$/;
e1.test("_"); //true
e1.test(" "); //true
//does not take space
let e2;
e2 = /^(?=.*[^a-zA-Z0-9])[!-~]+$/;
e2.test(" "); //false
e2.test("_"); //true
//the underscore exception
let e3;
e3 = /^(?=.*[\W])[!-~]+$/;
e3.test("_"); //false
```

Wait, what’s that ^ coming again from the middle of no where? If you have reached this far, this is where you realize that unassuming innocent ^ that marks start of a string is a double agent. Which means, the end is not too far. He has been exposed.

Within a character set, ^ negates the character set. That is, [^a-z] means, any character other than a to z.

[^a-zA-Z0-9] then stands for any character other than lower case alphabets, upper case alphabets, and numerals.

We could have used \W instead of the long character set. But \W stands for all alpha-numeric characters **including underscore \_.** As you can see in the third set of examples above, that will not accept underscore as a valid symbol.

#### CharSet Range

The curious case of [!-~]. They stand next to each other in the keyboard, but their ASCII values are diagonally opposite.

Remember a-z? A-Z? 0–9? These are not constants. They are actually based on the ASCII range of their values.

The [ASCII table](http://www.asciitable.com/) has 125 characters. zero (0) to 31 are not relevant to us. Space starts from 32 going all the way up to 126 which is tilda(~). The exclamation mark is 33.

So [!-~] covers all the symbols, letters and numbers we need. The seed for this idea came from [another solution](https://stackoverflow.com/questions/8359566/regex-to-match-symbols) to the symbol problem.

#### Assemble the Troops

Bringing it all together, we get this nice looking piece of regular expression `/^(?=.{5,})(?=._[a-z]+)(?=._\d+)(?=._[A-Z]+)(?=._[^\w])[ -~]+$/`.

That’s starting to haunt and intimidate us. Though we’ve been studying them individually.

This is where the syntax for dynamically building expression object comes in handy. We are going to build each piece separately and assemble them later.

```javascript
//start with prefix
let p = "^";
//look ahead
// min 4 chars
p += "(?=.{4,})";
// lower case
p += "(?=.*[a-z]+)";
// upper case
p += "(?=.*[A-Z]+)";
// numbers
p += "(?=.*\\d+)";
// symbols
p += "(?=.*[^ a-zA-Z0-9]+)";
//end of lookaheads

//final consumption
p += "[ -~]+";
//suffix
p += "$";

//Construct RegEx
let e = new RegEx(p);
// tests
e.test("aB0#"); //true
e.test(""); //false
e.test("aB0"); //false
e.test("ab0#"); //false
e.test("AB0#"); //false
e.test("aB00"); //false
e.test("aB!!"); //false
// space is in our control
e.test("aB 0"); //false
e.test("aB 0!"); //true
```

If your eyes are not tired yet, you’d have noticed two strange syntax in the above code.

- One, we didn’t use /^, instead we used just ^. We didn’t use $/ to end the expression either, instead just $.
  The reason is that the RegEx constructor automatically adds starting and trailing slashes for us.
- Two, to match numbers we used \\d instead of the usual \d. This is because the variable p is just a normal string within double quotes. To insert a backslash, you need to escape the backslash itself. 
  \\d resolves to \d within the RegEx constructor

Apparently, there should be server side validations for passwords too. Think about SQL injection vulnerabilities if your framework or language doesn’t handle it already.

### 7\. Conclusion

That brings us to the end of the story. But this is the beginning of a journey.

We just scratched the pattern matching portion of RegEx with test method. exec method builds on this foundation to return matched sub-strings based on pattern.

String object has methods such as match, search, replace, and split that widely uses regular expressions.

Hope this sets you off to explore those capabilities further with a solid understanding on composing patterns for RegEx.

### 8\. Call To Action

No, after all this difficulty we’ve been through, I am not going to ask you to subscribe.

Just make good software.

If any code blocks presented here do not work, leave a comment on this [github issue](https://github.com/pineboat/pineboat.github.io/issues/3) I created specially for this post.

Hope it was useful! Share it if others would benefit.

You’ve been wonderful. Appreciate your time. This content is far long by recent standards. Thanks for reading.

Originally published at [www.pineboat.in](https://www.pineboat.in/post/regular-expressions-your-ally/).
]]></description>
            <link>https://hungvn.com/blog/hieu-ro-ve-regular-expressions-regex-khong-kho-nhu-tuong-tuong</link>
            <guid isPermaLink="true">https://hungvn.com/blog/hieu-ro-ve-regular-expressions-regex-khong-kho-nhu-tuong-tuong</guid>
            <pubDate>Fri, 15 Dec 2017 22:23:22 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React, Inline Functions, and Performance]]></title>
            <description><![CDATA[
My wife and I just got through a huge remodel. We were beyond excited to show people the new digs. We showed my mother-in-law. She walked in the beautifully remodeled bedroom, looked up at the fantastically framed window and said: “No blinds?” 😐

![](https://cdn-images-1.medium.com/max/2000/1*_WL8zajmqcczto2bjiBqpw.jpeg)Our new bedroom; holy crap it looks like a magazine picture. Also, no blinds.

I find myself with the same emotion when I'm talking about React. I'll be getting through the first lecture of a workshop, showing off some cool new OSS, and invariably somebody says: “inline functions? I heard those are slow.”

It wasn't always this way. But the last few months it comes up literally every day. As an instructor and library author, it gets exhausting. Unfortunately, I'm a dummy and I rant on twitter instead of writing something that might be insightful to others. So, this is my attempt at the better option 😂.

### What is an “inline function”

In the context of React, an inline function is a function that is defined while React is “rendering”. There are two meanings of “render” in React that people often get confused about: (1) getting the React elements from your components (calling your component's render method) during an update and (2) actually rendering updates to the DOM. When I refer to “rendering” in this article, I'm talking about #1.

Here are a few examples of inline functions:

<Gist id="63ed1cd4ce795c83d4c7baf08320cc0c" />

### Premature optimization is the root of all evil

Before we go any further, we need to talk about how to optimize a program. Ask any performance expert and they will tell you not to prematurely optimize your program. All of them. Yes, every single one of them. 100% of people with deep performance experience will tell you not to prematurely optimize your code.

> If you aren't measuring, you can't even know if your optimizations are better, and you certainly won't know if they make things worse!

I remember a talk my friend Ralph Holzmann gave about how gzip works that really solidified this idea for me. He talks about an experiment he did with LABjs, an old script loading library. You can watch from 30:02 to about 32:35 [in this video](https://vimeo.com/34164210) to hear about it, or just keep reading.

At the time, the source for [LABjs](https://github.com/getify/LABjs) did something a little awkward for performance. Instead of using normal object notation (obj.foo) it stored the keys in strings and used bracket notation to access the objects (obj[stringForFoo]). The idea was that after minifying and gzipping, the unnaturally written code would be smaller than the naturally written code. [You can see it here](https://github.com/getify/LABjs/blob/b23ee3fcad12157cf8f6a291cb54fd7550ac7f3b/LAB.src.js#L7-L34).

Ralph forked the code and removed the optimizations by writing the code naturally, without thinking about how to optimize for minification and gzip.

Turns out, removing the “optimizations” shaved off 5.3% of the file size! If you aren't measuring, you can't even know if your optimizations are better, and you certainly won't know if they make things worse!

Not only can premature optimization explode development time while hurting code cleanliness, it can even backfire and _cause_ performance problems as it did for LABjs. Had the author been measuring, rather than just imagining performance issues, he would have saved development time, had cleaner code, and better performance.

Don't prematurely optimize. Alright, back to React.

### Why do people say inline functions are slow?

Two reasons: Memory/garbage collection concerns, and shouldComponentUpdate.

#### Memory and garbage collection

First, folks (and [eslint configs](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md)) are concerned about memory and garbage collection costs around creating inline functions. This mostly spilled over from the days before arrow functions became ubiquitous. Lots of code would call bind inline, which has historically had poor performance. For example:

<Gist id="15bc885c2ed7c2f10fca8b381c76f331" />

Performance issues with Function.prototype.bind [got fixed here](http://benediktmeurer.de/2015/12/25/a-new-approach-to-function-prototype-bind/) and arrow functions are either a native thing or are transpiled by babel to plain functions; in both cases we can assume it's not slow.

Remember, you don't sit back and imagine “I bet that code is slow”. You write your code naturally, _then_ you measure it. If there are performance problems, fix them. We don't need to prove an inline arrow function is fast, somebody else needs to prove it's slow. Otherwise it's a premature optimization.

As far as I've seen, nobody has presented an analysis of their app that indicates inline arrow functions are slow. Until then, it's not even worth talking about — but I'll offer one more thought anyway 😝

If the cost of creating an inline function is high enough to warrant an eslint rule against it, why would we want to move that expense to the hot path of initialization?

<Gist id="b9c376506948aa6ead758860b8305f52" />

By prematurely optimizing we've slowed down the initialization of the component by 3x! If all the handlers were inline, the initial render would only have to create one function. Instead, we've created three. We haven't measured anything though, so we have no reason to believe any of this is a problem.

If you want to completely miss the point, go make an eslint rule that requires inline functions everywhere to speed up the initial render 🤦🏾‍♀️.

#### PureComponent and shouldComponentUpdate

This is where the real meat of the problem lives. You can see real performance improvements by understanding two things: shouldComponentUpdate and JavaScript strict equality comparisons. If you don't understand them well, you can inadvertently make your React code harder to work with in the name of performance.

When you call setState, React will compare the old React elements to a new set of React elements (this is called r*econciliation*, you can [read about it here](https://reactjs.org/docs/reconciliation.html)) and then use that information to update the real DOM elements. Sometimes that can get slow if you've got a lot of elements to check (like a big SVG). In these cases, React provides an escape hatch called shouldComponentUpdate.

<Gist id="1ca57cfea6f5a4a8a4b9e5ac468f9b91" />

If your component has shouldComponentUpdate defined, before React compares the old and new elements, it will ask shouldComponentUpdate if anything changed. If it returns false, then React will completely skip the element diff, saving some time. If your component is large enough, this can have considerable impact on performance.

The most common way to optimize a component is to extend React.PureComponent instead of React.Component. A PureComponent will diff your props and state in shouldComponentUpdate so you don't have to.

```javascript
class Avatar extends React.PureComponent { ... }
```

Avatar will now use a “strict equality comparison” on its props and state when being asked to update, hopefully speeding things up.

#### Strict Equality Comparison

There are six primitive types in JavaScript: string, number, boolean, null, undefined, and symbol. When you do a “strict equality comparison” on two primitives that hold the same value, you'll get true. For example:

```javascript
const one = 1;
const uno = 1;
one === uno; // true
```

When PureComponent diffs props it uses a strict equality comparison. This works out great for inlined primitive values: `<Toggler isOpen={true}/>`.

The prop diffing problem arises because of non-primitive types — err, excuse me, _type_. There is only one other type and that's Object. What about functions and arrays you say? _Well, actually_ those are just objects.

> Functions are regular objects with the additional capability of being callable.

> - [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures)

LOL, okay JavaScript. So anyway, strict equality checks on objects, even with seemingly similar values, will evaluate to false:

<Gist id="bbaa6a0a5fb5a24f941e7388b53f8f76" />

So, if you inline an object in your JSX, it will fail the PureComponent prop diff and move on to diffing the more expensive React elements. The element diff will come up empty and now we've wasted time on both diffs.

<Gist id="70f9ca97de0606212424694a3629428d" />

Since functions are objects and PureComponent does a strict equality check on props, an inline function will _always_ fail the prop diff and move on to the element diff in the reconciler.

You can see this isn't just about inline functions. The function is simply the lead singer of the object, function, array three-piece performance postulation proliferation.

In order to make shouldComponentUpdate happy, you have to keep referential identity of the function. For experienced JavaScript developers, it's not too bad. But, [Michael](https://medium.com/@mjackson) and I have led workshops with over 3,500 people at varying levels of experience and it ain't easy for a lot of folks. ES classes don't offer any help either, leading us down all sorts of JavaScript paths:

<Gist id="187e82831d36fe8fa91952b616a33527" />

Learning how to keep referential identity of a function leads to surprisingly long conversations.

There's usually no reason why we're forcing people to do this other than an eslint config yelled at them. I'd like to show that you can have inline functions and performance optimizations both at the same time. But first, I have a personal performance story.

### My own experience with PureComponent

When I first learned about PureRenderMixin (the thing from earlier versions of React that later became PureComponent) I put in a bunch of measurements and measured my app's performance. I then added PureRenderMixin to every single component. When I took the optimized set of measurements I was hoping to have a cool story to tell about how much faster everything got.

Much to my surprise, my app got slower 🤔.

Why? Well, think about it. If you have a Component how many diffs are there? If you have a PureComponent how many diffs are there? The answers are “just one” and “at least one and sometimes two”, respectively. If a component _usually_ changes when there's an update, then a PureComponent will be doing two diffs instead of just one (props and state in shouldComponentUpdate, and then the normal element diff). Which means it's going to be _slower usually_ but _faster occasionally_. Apparently, most of my components changed most of the time, so on the whole, my app got slower. Oops.

There are no silver bullets when it comes to performance. You have to measure.

### The three scenarios

At the start of the article I showed three types of inline functions. Now that we have some background, let's talk about each one them. But please remember to keep PureComponent on the shelf until you have a measurement to justify it.

#### DOM component event handler

```javascript
<button
  onClick={() => this.setState(…)}
>click</button>
```

It's common to do nothing more than setState inside of event handlers for buttons, inputs, and other DOM components. This often makes an inline function the cleanest approach. Instead of bouncing around the file to find the event handlers, they're colocated. The React community generally welcomes colocation.

The button component (and every other DOM component) can't even be a PureComponent, so there are no shouldComponentUpdate referential identity concerns here.

So, the only reason to think this is slow is if you think simply defining a function is a big enough expense to worry about. We've discussed that there is no evidence anywhere that it is. It's simply armchair performance postulation. These are fine until proven otherwise.

#### A “custom event” or “action”

```javascript
<Sidebar
  onToggle={isOpen => {
    this.setState({ sidebarIsOpen: isOpen });
  }}
/>
```

If Sidebar is a PureComponent we will be breaking the prop diff. Again, since the handler is simple, the colocation can be preferable.

With an event like onToggle, why is Sidebar even diffing it? There are only two reasons to include a prop in the shouldComponentUpdate diff:

1.  You use the prop to render.
2.  You use the prop to perform a side-effect in componentWillReceiveProps, componentDidUpdate, or componentWillUpdate.

Most on `<whatever>` props do not meet either of these requirements. Therefore, most PureComponent usages are over-diffing, forcing developers to maintain referential identity of the handler needlessly.

We should only diff the props that matter. That way people can colocate handlers and still get the performance gains you're seeking (and since we're concerned about performance, we're diffing less!).

For most components, I'd recommend creating a PureComponentMinusHandlers class and inherit from that instead of inheriting from PureComponent. It could just skip all checks on functions. Have your cake and eat it too.

Well, almost.

If you receive a function and pass that function directly into another component, it'll get stale. Check this out:

<Gist id="9e40e895750ec93a0fa64e15afef52fc" />

[Here's a codesandbox running that app](https://codesandbox.io/s/v38y6zk8ml).

So, if you like the idea of inheriting from a PureRenderWithoutHandlers, make sure you don't ever pass your ignored handlers _directly_ to other components — you need to wrap them one way or another.

Now we either have to maintain referential identity, or we have to avoid referential identity! Welcome to performance optimization. At least with this approach it's the optimized component that has to deal with it, not the code using it.

I'm going to be candid, that example app is an edit I made after publishing that [Andrew Clark](https://medium.com/@acdlite) brought to my attention. And here you thought I was smart enough to know when to manage referential identity and when not to! 😂

#### A render prop

<Gist id="f06440f6bf807759e7b43527671ec14b" />

Render props are a pattern used to create a component that exists to compose and manage shared state. ([You can read more about them here](https://cdb.reacttraining.com/use-a-render-prop-50de598f11ce).) The contents of the render prop are unknowable to the component. For example:

<Gist id="1e7e22cbd92ba132dbbff893f0b51d7b" />

That means an inline render prop function won't cause problems with shouldComponentUpdate: It can't ever know enough to be a PureComponent.

So, the only other objection is back to believing that simply defining functions is slow. Repeating from the first example: there's no evidence to support that. It's simply armchair performance postulation.

### In summary

1.  Write your code naturally, code to the design.
2.  Measure your interactions to find slow paths. [Here's how](https://reactjs.org/blog/2016/11/16/react-v15.4.0.html#profiling-components-with-chrome-timeline).
3.  Use PureComponent and shouldComponentUpdate only when you need to, skipping prop functions (unless they are used in lifecycle hooks for side-effects).
]]></description>
            <link>https://hungvn.com/blog/react-inline-functions-and-performance</link>
            <guid isPermaLink="true">https://hungvn.com/blog/react-inline-functions-and-performance</guid>
            <pubDate>Fri, 08 Dec 2017 14:43:28 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cải thiện tốc độ Web App với Pinterest ]]></title>
            <description><![CDATA[
Pinterest’s new mobile web experience is a [Progressive Web App](https://developers.google.com/web/progressive-web-apps/). In this post we’ll cover some of their work to load fast on mobile hardware by keeping JavaScript bundles lean and adopting Service Workers for network resilience.

![](https://cdn-images-1.medium.com/max/2000/1*7mUxFg5KuYdenGZHp23MtA.png)Login to [https://pinterest.com](https://pinterest.com) on your phone to experience their new mobile site

#### **Why a Progressive Web App (PWA)? Some history.**

The Pinterest PWA started because they were focused on international growth, which led them to the mobile web.

After analyzing usage for unauthenticated mobile web users, they realized that their old, slow web experience only managed to convert 1% of users into sign-ups, logins or native app installs. The opportunity to improve this conversation rate was huge, leading them to an investment in the PWA.

**Building and shipping a PWA in a quarter**

Over **3 months**, Pinterest rebuilt their mobile web experience using React, Redux and webpack. Their mobile web rewrite led to several positive improvements in core business metrics.

Time spent is up by **40%** compared to the old mobile web experience, user-generated ad revenue is up **44%** and core engagements are up **60%**:

![](https://cdn-images-1.medium.com/max/2000/1*RgNMMtvegu9ZiB4XEbGTyg.png)

Their mobile web rewrite also led to several improvements in performance.

#### **Loading fast on average mobile hardware over 3G**

Pinterest’s old mobile web experience was a monolith — it included large bundles of CPU-heavy JavaScript that [pushed out how quickly](https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e) Pin pages could load and get interactive.

Users often had to wait **23 seconds** before any UI was usable at all:

![](https://cdn-images-1.medium.com/max/2000/1*nGQaIgpJ_EyAVRirfS22qg.png)Pinterest’s old mobile web site took 23 seconds to get interactive. They would send down over 2.5MB of JavaScript (~1.5MB for the main bundle, 1MB lazily loaded in) taking multiple seconds to get parsed and compiled before the main thread finally settled down enough to be interactive.

Their new mobile web experience is a drastic improvement.

Not only did they break-up & shave hundreds of KB off their JavaScript, taking down the size of their core bundle from 650KB to 150KB but they also improved on key performance metrics. [First Meaningful Paint](https://developers.google.com/web/tools/lighthouse/audits/first-meaningful-paint) was down from 4.2s to 1.8s and [Time To Interactive](https://developers.google.com/web/tools/lighthouse/audits/time-to-interactive) reduced from 23s to 5.6s.

![](https://cdn-images-1.medium.com/max/2000/1*9vUPBQYxm4LEviK0t8Np9Q.png)

This is on average Android hardware over a slow 3G network connection. On repeat visits, the situation was even better.

Thanks to Service Worker caching of their main JavaScript, CSS and static UI assets they were able to bring down time to interactive on repeat visits all the way down to 3.9s:

![](https://cdn-images-1.medium.com/max/2000/1*NUIGbZcPJQkGIh1218ryKw.png)

Although Pinterest vend iOS & Android apps, they were able to deliver the same core home feed experience these apps do on the web in a fraction of the upfront download cost — just ~150KB minified & gzipped. This contrasts with the 9.6MB required to deliver this experience for Android and 56MB for iOS:

![](https://cdn-images-1.medium.com/max/2000/1*CoC8Oa6JjA5KVX2lNktd1Q.png)

It’s important to note that this isn’t comparing apples to apples, however. The PWA loads code for new routes on demand, and the cost of additional code is amortized over the lifetime of the application. Subsequent navigations still don’t cost as much data as the download of the app.

![](https://cdn-images-1.medium.com/max/1600/1*UW2k5EXjEg5HSxh8Wu3vQA.png)Pinterest’s Progressive Web App in Firefox, Edge and Safari on mobile.

#### **Route-based JavaScript chunking**

Getting a web page to load and get interactive quickly benefits from **only loading the code a user needs** upfront. This reduces **network transmission & JavaScript parse/compile times.** Non-critical resources can then be lazily loaded as needed.

Pinterest started breaking up their multi-megabyte JavaScript bundles by splitting them into three different categories of webpack chunks that worked quite well:

![](https://cdn-images-1.medium.com/max/2000/1*5vr9mzdnTIiWS3N7GxbxxA.png)

- a **vendor** chunk which contained external dependencies (react, redux, react-router, etc) ~ 73KB
- an **entry** chunk which contained a majority of the code required to render the app (i.e. common libs, the main shell of the page, our redux store) ~ 72KB
- **async** route chunks which contained code pertaining to individual routes ~13–18KB

A Network waterfall for the experience highlights how a shift to progressively delivering code as needed avoids the need for monolithic bundles:

![](https://cdn-images-1.medium.com/max/1600/0*Vuue9Hw2iHkOt5Pm.)For long-term caching, Pinterest also use a chunk-specific hash substitution for each filename.

Pinterest uses webpack’s [CommonsChunkPlugin](https://webpack.js.org/plugins/commons-chunk-plugin/) to break out their vendor bundles into their own cacheable chunk:

<Gist id="03bf9415585e74a090b6d6c43c104a79" />

They also used [React Router](https://github.com/ReactTraining/react-router) for adding [code-splitting](https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/guides/code-splitting.md) to the experience:

<Gist id="5d91614739a12c5d5e77c5ebfb29de2c" />

#### Use babel-preset-env to only transpile what target browsers need

Pinterest use Babel’s [babel-preset-env](http://2ality.com/2017/02/babel-preset-env.html) to only transpile ES2015+ features unsupported by the modern browsers they target. Pinterest targets the last two versions of modern browsers, and their .babelrc setup looks a little like:

<Gist id="8ab162aa3df26ab9cd25ea035c7eddc0" />

There are further optimizations they can do to only conditionally serve polyfills as needed (e.g the [Internationalization API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl) for Safari) but this is planned for the future.

**Analyzing room for improvement with Webpack Bundle Analyzer**

[Webpack Bundle Analyzer](https://github.com/webpack-contrib/webpack-bundle-analyzer) is an excellent tool for really understanding what dependencies you’re sending down to your users in JavaScript bundles.

Below, you’ll see a lot of purple, pink and blue blocks in its output for an earlier build of Pinterest. These are **async** chunks for routes being lazily loaded in. Webpack Bundle Analyzer allowed Pinterest to visualize that most of these chunks contained **duplicate code**:

![](https://cdn-images-1.medium.com/max/2000/1*wjPqRO7rwz7ckQcSa_5AtQ.png)

Webpack Bundle Analyzer helped visualize the size ratio of this problem between all their chunks.

Using the information about duplicate code in chunks, Pinterest were able to make a call. **They moved duplicate code in async chunks to their main chunk. It increased the size of the entry chunk by 20% but decreased the size of all lazily loaded chunks by up to 90%!**

![](https://cdn-images-1.medium.com/max/2000/1*zc2QXjCC2WE4YfLXJsKyBQ.png)

#### **Image Optimization**

Most of the lazy-loading of content in the Pinterest PWA is handled by an infinite [Masonry](https://masonry.desandro.com) grid. It has built-in support for virtualization and only mounting children that are in the viewport.

![](https://cdn-images-1.medium.com/max/2000/1*3Qc0arFwl1wlMGqabRWe1Q.png)

Pinterest also uses a progressive loading technique for images in their PWA. A placeholder with the dominant color is initially used for each Pin. Pin images are served as [Progressive JPEGs](https://images.guide/#jpeg-compression-modes), which improve image quality with each scan:

![](https://cdn-images-1.medium.com/max/2000/1*s55es4BBR2tW5OJZNg4Smg.png)

#### **React performance pain-points**

Pinterest ran into some rendering performance issues with React as part of their use of this [Masonry](https://masonry.desandro.com/) grid. **Mounting and unmounting large trees of components (like Pins) can be slow.** There’s a lot that goes into a Pin:

![](https://cdn-images-1.medium.com/max/2000/1*ld75N4yvmlAkRkNM6saGow.png)

Although at the time of writing Pinterest are using React 15.5.4, their hope is that [React 16](https://reactjs.org/blog/2017/09/26/react-v16.0.html) (Fiber) will help a lot with reducing time spent unmounting. In the mean time, **Virtualizing the grid** helped significantly with component unmount time.

Pinterest also throttle insertion of Pins so that they can measure/render the first Pins quicker, but means there’s more overall work for the device’s CPU.

#### Navigation Transitions

To improve perceived performance, Pinterest also update the selected state of navigation bar icons independent of the route. This enables navigations from one route to another to not feel slow due to blocking on the network. The user gets visual UI painted quickly while we’re waiting for the data to arrive:

![](https://cdn-images-1.medium.com/max/2000/1*Kya9741M8sng5-vaz_-mew.png)

#### **Experience using Redux**

Pinterest use [normalizr](https://github.com/paularmstrong/normalizr) (which normalizes nested JSON according to a schema) for all of their API data. This is viewable from the Redux DevTools:

![](https://cdn-images-1.medium.com/max/1600/1*KxIjlPIfJzuGPDOfjPq2cA.png)

The downside to this process is that denormalization is slow so they ended up heavily relying on [reselect](https://github.com/reactjs/reselect)’s selector pattern for memoizing denormalization during renders. They also always denormalize at the lowest level possible to ensure individual updates don’t cause large re-renders.

As an example, their grid item lists are just Pin IDs with the Pin component denormalizing itself. If there are changes to any given Pin, the full grid does not have to re-render. The trade-off is that there are a lot of Redux subscribers in the Pinterest PWA, though this hasn’t resulted in noticeable perf issues.

#### **Caching assets with Service Workers**

Pinterest use the Workbox libraries for generating and managing their Service Workers:

<Gist id="acb95e3a138c850e476cc9a769096990" />

Today, Pinterest cache any JavaScript or CSS bundles using a cache-first strategy and also cache their user-interface (the application shell).

![](https://cdn-images-1.medium.com/max/1600/1*dfohRhGZpHXNzZQdJvaRDQ.png)In a **cache-first** setup, if a request matches a cache entry, respond with that. Otherwise try to fetch the resource from the network. If the network request succeeds, update the cache. To learn more about caching strategies with Service Worker, read [Jake Archibald’s Offline Cookbook](https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/).

They define a precache for the initial bundles loaded by the application shell (webpack’s runtime, vendor and entryChunks) too.

As Pinterest is a site with a global presence, supporting multiple languages, they also generate a **per-locale Service Worker configuration** so they can precache locale bundles. Pinterest also use webpack’s named chunks to precache top-level async route bundles.

This work was rolled out in several smaller, iterative steps.

- 1st: Pinterest’s Service Worker only did **runtime caching of scripts lazy-loaded on demand**. This was to take advantage of [V8’s code caching](https://v8project.blogspot.com/2015/07/code-caching.html), helping skip some of the parse/compile cost on repeat views so they can load quicker. Scripts served from Cache Storage where a Service Worker is present can eagerly opt into code caching as there’s a good chance the browser knows the user will end up using these resources on repeat views.

![](https://cdn-images-1.medium.com/max/2000/1*W8AXvny4cVN3-dpH9T_HRg.png)

- After this, Pinterest progressed to **pre-caching their vendor and entry chunks**.
- Next, Pinterest started **precaching a few of the most used routes** (like the home page, pin page, search page etc).
- Finally, they started **generating a Service Worker for each locale** so that they could also cache the locale bundle. This was important for not just repeat load performance, but also enabling basic offline rendering for most of their audience:

<Gist id="8d716b8438c678dfa79123a586284c4b" />

#### **Application Shell challenges**

Pinterest found implementing their application shell a little tricky. Because of desktop-era assumptions about how much data could be sent down over a cable connection, initial payloads were large containing a lot of non-critical info, like user’s experiment groups, user info, contextual information etc.

They had to ask themselves: “do we cache this stuff in the application shell? or take the perf hit of making a blocking network request before rendering anything to fetch it at all”.

![](https://cdn-images-1.medium.com/max/2000/1*So_dHNZKmfrbPTkCwbng4g.png)

They decided to cache it in the application shell, which required some management of when to invalidate the app shell (logout, user information updates from settings etc). Each request response has an `appVersion` — if the app version changes, they unregister the Service Worker, register the new one then on the next route change they do a full page reload.

Adding this information to the application shell is a little trickier, but worth avoiding the render blocking request for.

#### **Auditing with Lighthouse**

Pinterest used [Lighthouse](https://github.com/GoogleChrome/lighthouse/) for one-off validations that their performance improvements were on the right track. It was useful for keeping an eye on metrics such as Time to Consistently Interactive.

![](https://cdn-images-1.medium.com/max/2000/1*LzeWXIvrLWT9bln2mcpecQ.png)

Next year they hope to use Lighthouse as a regression mechanism to verify that page loads remain fast.

#### **The Future**

Pinterest just deployed support for Web Push notifications and have also been working on the unauthenticated (logged-out) experience for their PWA.

![](https://cdn-images-1.medium.com/max/2000/1*05ab3hBhOfJdgs_DBMFbMg.png)

They are interested in exploring support for [resource prioritization](https://web.dev/articles/prioritize-resources) to preload critical bundles & reducing the amount of unused JavaScript delivered to users on first load. Stay tuned for more awesome perf work in the future!
]]></description>
            <link>https://hungvn.com/blog/cai-thien-toc-do-web-app-voi-pinterest</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cai-thien-toc-do-web-app-voi-pinterest</guid>
            <pubDate>Fri, 08 Dec 2017 13:57:03 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[22 React projects open source]]></title>
            <description><![CDATA[
This is a collection of open source apps built with React.JS library. In this observation, we compared nearly 1,000 popular React projects to pick the top 22\. (React Native: 11, React: 11)

> React is an open source JavaScript library built by Facebook, providing a view for data rendered as HTML.

To evaluate the quality, [Mybridge AI](https://www.mybridge.co/) considers a variety of factors to determine how useful the projects are for programmers. To give you an idea on the quality, **the average number of Github stars from the 22 projects was 3,584.**

Open source projects can be useful both for beginners to learn from reading the code and for advanced programmers to save time by using the existing code. The aim of this collection is to help you pick a great project right away without having to spend hours of searching.

> Note that React UI components, boilerplates, tools and frameworks are separated out to make this curation more specific to full-working apps built with React.

![](https://cdn-images-1.medium.com/max/2000/1*pQ2wBDU_8uUMEzJezF5mSg.png)

`<Recommended Courses>`

[No 1) Redux](https://click.linksynergy.com/deeplink?id=QZaBth/yPOQ&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Freact-2nd-edition%2F)

[![](https://cdn-images-1.medium.com/max/1200/1*QMUcUulA_-2VUkLme1Rr4A.png)](https://click.linksynergy.com/deeplink?id=QZaBth/yPOQ&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Freact-2nd-edition%2F)

[The Complete React Web Course (2nd Edition): Build apps using Redux, Webpack, React-Router](https://click.linksynergy.com/deeplink?id=QZaBth/yPOQ&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Freact-2nd-edition%2F)

[10,556 recommends, 4.8/5 stars]

[No 2) React Native](https://click.linksynergy.com/deeplink?id=QZaBth/yPOQ&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Fthe-complete-react-native-and-redux-course%2F)

[![](https://cdn-images-1.medium.com/max/1200/1*_t2AgPimrC931LYvMEMqsw.png)](https://click.linksynergy.com/deeplink?id=QZaBth/yPOQ&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Fthe-complete-react-native-and-redux-course%2F)

[The Complete React Native and Redux Course: Build iOS and Android App fast from scratch.](https://click.linksynergy.com/deeplink?id=QZaBth/yPOQ&mid=39197&murl=https%3A%2F%2Fwww.udemy.com%2Fthe-complete-react-native-and-redux-course%2F)

[46,695 recommends, 4.6/5 stars]

[No 3) Beginner](https://goo.gl/2yKV9E)

[![](https://cdn-images-1.medium.com/max/1200/1*-tXc7BFKeZgNta-iubHiEw.png)](https://goo.gl/2yKV9E)

[React for Beginners. By Wes Bos](https://goo.gl/2yKV9E)

[14,955 recommends]

![](https://cdn-images-1.medium.com/max/2000/1*pQ2wBDU_8uUMEzJezF5mSg.png)

### `<React Native>`

[React native iOS and Android apps that give attendees a schedule for the F8 conference.](https://github.com/fbsamples/f8app) Courtesy of [Alex Kotlyarskiy](https://medium.com/@frantic) **[11,081 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*bM-MLAmBamxjvKuptsPBYg.png)](https://github.com/fbsamples/f8app)

---

[Hacker News iOS and Android App: Made with React Native](https://github.com/iSimar/HackerNews-React-Native). Courtesy of [Simar Singh](https://medium.com/@simarmarok) **[3,224 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*b2AB4aJZprMD0OgSMBt4BA.png)](https://github.com/iSimar/HackerNews-React-Native)

---

[Dribbble app built with React Native](https://github.com/catalinmiron/react-native-dribbble-app). Courtesy of [Catalin MIRON](https://medium.com/@mironcatalin) **[1,778 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*4FFD8PN2sjsT785AAQIfhA.png)](https://github.com/catalinmiron/react-native-dribbble-app)

---

[Ready-to-use chat interface for iOS and Android React-Native apps](https://github.com/FaridSafi/react-native-gifted-messenger). Courtesy of [Farid from Safi](https://medium.com/@faridsafi) **[4,006 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*ru2hNgix-uKN2yj3uZYd-A.png)](https://github.com/FaridSafi/react-native-gifted-messenger)

---

[iOS’s Stocks App clone: Written in React Native available both iOS and Android](https://github.com/7kfpun/FinanceReactNative). Courtesy of [kf](https://medium.com/@.kf) **[1,352 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*J1Vvedaow-AGtqVHy7laFA.png)](https://github.com/7kfpun/FinanceReactNative)

---

[A Zhihu Daily App client implemented using React Native (Android and iOS)](https://github.com/race604/ZhiHuDaily-React-Native). Courtesy of [Race604](https://medium.com/@race604) **[3,521 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*H7G4p59A_NQSF9zgqHKxGw.png)](https://github.com/race604/ZhiHuDaily-React-Native)

---

[A Camera app for React Native (also supports barcode scanning)](https://github.com/lwansbrough/react-native-camera). Courtesy of [@CharlieHawker](https://twitter.com/CharlieHawker) **[4,248 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*LLTRnn-Q4Ro1JCVX2q04Kw.png)](https://github.com/lwansbrough/react-native-camera)

---

[Github client written with react-native.](https://github.com/xiekw2010/react-native-gitfeed) Courtesy of [David Tse](https://medium.com/@xiekw2010) **[1,635 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*Zf4pcg1WCftsyJhoKwXNAw.png)](https://github.com/xiekw2010/react-native-gitfeed)

---

[iOS and Android NBA App built with React Native](https://github.com/wwayne/react-native-nba-app). Courtesy of [WangZixiao](https://medium.com/@wwayne_me) **[1,715 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*ryrn5fg8OEFejjh8ovTyMg.png)](https://github.com/wwayne/react-native-nba-app)

---

[React Native Reddit Reader](https://github.com/akveo/react-native-reddit-reader). Courtesy of Andrei Hrabouski **[323 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*gkR8SK3r5N1eFUyCVENZhw.gif)](https://github.com/akveo/react-native-reddit-reader)

---

[FB Basketball game clone built in React.JS Native](https://github.com/faridsafi/react-native-basketball). Courtesy of [Farid from Safi](https://medium.com/@faridsafi) **[344 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*PrSmEqoTnZHDEU7hpf-gBg.gif)](https://github.com/faridsafi/react-native-basketball)![](https://cdn-images-1.medium.com/max/1600/1*PwDkJWBzoQElxEyoq_nzfg.png)

### `<React>`

[A Soundcloud client built with React / Redux](https://github.com/andrewngu/sound-redux). Courtesy of [Andrew Nguyen](https://medium.com/@andrewmnguyen) **[3,888 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*6_E_yFtZnla-2W9pMzyo2Q.png)](https://github.com/andrewngu/sound-redux)

---

[Calculator built with React (Website), Electron (Desktop), and React Native (iOS & Android).](https://github.com/benoitvallon/react-native-nw-react-calculator) Courtesy of [Benoit VALLON](https://medium.com/@benoitvallon) **[4,080 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*18M06EwSQ7RpiSjLaVC1xQ.png)](https://github.com/benoitvallon/react-native-nw-react-calculator)

---

[React-color: Color Pickers from Sketch, Photoshop, Chrome & more](https://github.com/casesandberg/react-color). Courtesy of [Case Sandberg](https://medium.com/@casesandberg) **[4,460 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*Nz-dIZ8FBnQ2MQPjlil5tQ.png)](https://github.com/casesandberg/react-color)

---

[Gatsby: Transform plain text into dynamic blogs and websites using React.js](https://github.com/gatsbyjs/gatsby). Courtesy of [kylemathews](https://medium.com/@kylemathews) **[15,427 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*nnHXMTKwXxCWJiY9yX2ZMA.gif)](https://github.com/gatsbyjs/gatsby)

---

[Sentry is cross-platform crash reporting built with React](https://github.com/getsentry/sentry/). Courtesy of [Armin Ronacher](https://medium.com/@mitsuhiko) **[14,749 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*BlqGo-URB6YJ5vO89Swa-A.png)](https://github.com/getsentry/sentry/)

---

[Isomorphic500: A web application featuring photos from 500px, built on express using React and Flux with yahoo/fluxible](https://github.com/gpbl/isomorphic500). Courtesy of [gp](https://medium.com/@gpblv) **[1,311 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*3ATOSUzoeg5ye-5IUzHmYQ.png)](https://github.com/gpbl/isomorphic500)

---

[A React & react-router-powered implementation of Hacker News using its Firebase API.](https://github.com/insin/react-hn) Courtesy of [Arthur Stolyar](https://medium.com/@nekrtemplar) **[1,765 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*pr4OcSdDsqMjn_87O7VbjQ.png)](https://github.com/insin/react-hn)

---

[A playground for in-browser interpreters. Built with React/Redux.](https://github.com/fatiherikli/fil) Courtesy of [Mican](https://medium.com/@fthrkl) **[659 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*XKunVbdIjmfhnRD8nrLKZQ.png)](https://github.com/fatiherikli/fil)

---

[Perseus: Khan Academy’s new exercise question editor and renderer built with React](https://github.com/khan/perseus) **[756 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*sD0ckKQiC_FNf7vrZEYyLg.png)](https://github.com/khan/perseus)

---

[React-based Imgur-like isomorphic demo app](https://github.com/BinaryMuse/imgsible). Courtesy of [Brandon Tilley](https://medium.com/@binarymuse) **[86 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*T2-uB71egFB_mdrBpOzl-g.png)](https://github.com/BinaryMuse/imgsible)

---

[Flatris: Tetris app for Cosmos, built with React](https://github.com/skidding/flatris). Courtesy of [Ovidiu Cherecheș](https://medium.com/@skidding) **[304 Stars]**

[![](https://cdn-images-1.medium.com/max/1600/1*hQeq8dP-ViarEyxl4YuEWQ.png)](https://github.com/skidding/flatris)![](https://cdn-images-1.medium.com/max/2000/1*pQ2wBDU_8uUMEzJezF5mSg.png)

That’s it for Amazing React Projects. If you like this curation, read best daily articles based on your programming skills on our [website](http://www.mybridge.co)

Recommend & share..
]]></description>
            <link>https://hungvn.com/blog/22-react-projects-open-source</link>
            <guid isPermaLink="true">https://hungvn.com/blog/22-react-projects-open-source</guid>
            <pubDate>Fri, 08 Dec 2017 13:37:30 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[React Component Patterns]]></title>
            <description><![CDATA[
## Stateful x Stateless, Container x P**resentational**, HOCs, Render Callbacks and more

It’s been a while since I’ve been working with [**React**](https://facebook.github.io/react/) — a Facebook library to build user interfaces using JavaScript — and there are a few concepts I wish I knew when I was just starting. This text is an attempt to summarize some patterns I learned during my experience so far — and also may be useful for developers who are just about to enter this awesome component-based world.

![](https://cdn-images-1.medium.com/max/2000/1*mPL5M-XhGpDuXLniVRCthw.png)

### Stateful x Stateless Components

Just as Stateful and Stateless web services, React components can also hold and manipulate state during application usage (**Stateful**) — or just be a simple component that takes the input props and returns what to display (**Stateless**).

A simple **Stateless** button component that depends on props only:

![](https://cdn-images-1.medium.com/max/1600/1*fgZOSwpdU7MMNxltRcXAcQ.png)

And a **Stateful** counter component example (using Button component):

![](https://cdn-images-1.medium.com/max/1600/1*TYPgsZUZMoo7lW7xv4gxYw.png)

As you can see, the last one’s constructor holds a component state, while the first one is a simple component that renders a text via props. This separation of concerns may look simple but makes Button component highly reusable.

### Container x Presentational Components

When working with external data, we can divide components into this two new categories. **Containers** are responsible to reach data that lives outside React scope, like connecting to _Redux_ or *Relay* — while **Presentational** components are free of dependencies from the rest of the app, depending only on its own state or props received. Let’s take a users list as a **Presentational** component example:

![](https://cdn-images-1.medium.com/max/1600/1*wbih6jbxJiIgNOXgRpcROA.png)

This list can be updated using our **Container** component:

![](https://cdn-images-1.medium.com/max/1600/1*TJxCVhawM2e99dZsxu11oA.png)

This approach divides data-fetching from rendering and also makes UserListreusable. If you want to learn more about this pattern, there’s an [awesome article from Dan Abramov](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) explaining it precisely.

### Higher-Order Components

Higher-Order Components — or just **_HOCs_**\_ — _are useful when you want to reuse a component logic. They are JavaScript functions that take a component as an argument and returns a new component.

Let’s say you need to build an expandable menu component that shows some children content when user clicks on it. So, instead of controlling the state on its parent component, you can simply create a generic **HOC** to handle it:

![](https://cdn-images-1.medium.com/max/1600/1*qchJXtrHlR46phKFDDJeeQ.png)

This approach allows us to apply our logic to our ToggleableMenu component using the JavaScript _decorator_ syntax:

![](https://cdn-images-1.medium.com/max/1600/1*RQuGzKKbT7R9OIDBzhO8gg.png)

Now we can pass any children to ToggleableMenu component:

![](https://cdn-images-1.medium.com/max/1600/1*rWCZQqL0Rbizbrw_yjgxgA.png)

If you’re familiar with [Redux’s](http://redux.js.org/) connect or [React Router’s](https://github.com/ReactTraining/react-router) withRouter functions, you’re already using **HOCs**!

### Render Callbacks

Another great way to make a component logic reusable is by turning your component children into a function — that’s why **Render Callbacks** are also called **Function as Child Components**. We can take an example of our expandable menu **HOC** and rewrite it using the **Render Callback** pattern:

![](https://cdn-images-1.medium.com/max/1600/1*Ul-ubPnaOFtY4mTeM5PW3A.png)

Now we can pass a function as our Toggleable component children:

![](https://cdn-images-1.medium.com/max/1600/1*cwoZiIT3Gcau5lDwyCQzQw.png)

The code above is already using a function as children, but, if we want to reuse it just as we did in our **HOC** example (multiple menus), we could simply create a new component that uses Toggleable logic:

![](https://cdn-images-1.medium.com/max/1600/1*DVfPDwHw_eH9dUeX9w5GEg.png)

Our brand new ToggleableMenu component is ready to be used:

![](https://cdn-images-1.medium.com/max/1600/1*hzpuJMAMTRQZK_vKCK_jhQ.png)

Our Menu component looks exactly the same as our **HOC** example!

This approach is really useful when we want to change the rendered content itself regardless of **state** manipulation: as you can see, we’ve moved our **render** logic to our ToggleableMenu children function, but kept the **state** logic to our Toggleablecomponent!
]]></description>
            <link>https://hungvn.com/blog/react-component-patterns</link>
            <guid isPermaLink="true">https://hungvn.com/blog/react-component-patterns</guid>
            <pubDate>Tue, 28 Nov 2017 10:53:16 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[The Front-End Checklist]]></title>
            <description><![CDATA[
## An Exhaustive List of all the Elements you need to have/test Before Launching your Website To Production.

![](https://cdn-images-1.medium.com/max/1600/1*2ofbexCS_7UAL4gByI37oA.png)

The [**Front-End Checklist**](https://github.com/thedaviddias/Front-End-Checklist) is an exhaustive list of all elements you need to have / to test before launching your site / HTML page to production.

It is based on Front-End developers’ years of experience, with additions coming from other open-source checklists. [**David Dias**](https://medium.com/@thedaviddias) is the main author/creator and posted the guide to [**GitHub**](https://github.com/thedaviddias/Front-End-Checklist) where it has taken off! The guide is also available below. Don’t forget to thank [David](https://medium.com/@thedaviddias) for an awesome guide!

### Table of Contents

1.  Head
2.  HTML
3.  Webfonts
4.  CSS
5.  Images
6.  JavaScript
7.  Security
8.  Performance
9.  Accessibility
10. SEO

### How To Use

All items in the Front-End Checklist are required for the majority of the projects, but some elements can be omitted or are not essential (in the case of an administration web app, you may not need RSS feed for example).

Some resources possess an emoticon to help you understand which type of content / help you may find on the checklist:

- 📖: documentation or article
- 🛠: online tool / testing tool
- 📹: media or video content

---

### Head

> _Notes: You can find_ [_a list of everything_](https://github.com/joshbuchea/HEAD) _that could be found in the_ _`<head>`_ _of an HTML document._

#### Meta tag

- Doctype: The Doctype is HTML5 and is at the top of all your HTML pages.

```html
<!-- Doctype HTML5 -->
<!doctype html>
```

> 📖 [Determining the character encoding — HTML5 W3C](https://www.w3.org/TR/html5/syntax.html#determining-the-character-encoding)

_The next 3 meta tags (Charset, X-UA Compatible and Viewport) need to come first in the head._

- Charset: The charset declared (UTF-8) is declared correctly.

```html
<!-- Set character encoding for the document -->
<meta charset="utf-8" />
```

- X-UA-Compatible: The X-UA-Compatible meta tag is present.

```html
<!-- Instruct Internet Explorer to use its latest rendering engine -->
<meta http-equiv="x-ua-compatible" content="ie=edge" />
```

> 📖 [Specifying legacy document modes (Internet Explorer)](https://msdn.microsoft.com/en-us/library/jj676915%28v=vs.85%29.aspx)

- Viewport: The viewport is declared correctly.

```html
<!-- Viewport for responsive web design -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
```

- Title: A title is used on all pages (SEO: Google calculate the pixel width of the characters used in the title, cut off between 472 and 482 pixels. Average character limit would be around 55-characters).

```javascript
<!-- Document Title -->
<title>Page Title less than 65 characters</title>
```

> 📖 [Title — HTML — MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title)

> 🛠 [SERP Snippet Generator](https://www.sistrix.com/serp-snippet-generator/)

- Description: A meta description is provided, it is unique and doesn’t possess more than 150 characters.

```html
<!-- Meta Description -->
<meta name="description" content="Description of the page less than 150 characters" />
```

> 📖[Meta Description — HTML — MDN](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#Adding_an_author_and_description)

- Favicons: Each favicon has been created and displays correctly. If you have only a favicon.ico, put it at the root of your site. Normally you won't need to use any markup. However, it's still good practice to link to it using the example below. Today, PNG format is recommended over .ico format (dimensions: 32x32px).

```html
<!-- Standard favicon -->
<link rel="icon" type="image/x-icon" href="https://example.com/favicon.ico" />
<!-- Recommended favicon format -->
<link rel="icon" type="image/png" href="https://example.com/favicon.png" />
```

> 🛠 [Favicon Generator](https://www.favicon-generator.org/)

> 🛠 [RealFaviconGenerator](https://realfavicongenerator.net/)

> 📖 [Favicon Cheat Sheet](https://github.com/audreyr/favicon-cheat-sheet)

> 📖 [Favicons, Touch Icons, Tile Icons, etc. Which Do You Need? — CSS Tricks](https://css-tricks.com/favicon-quiz/)

> 📖 [PNG favicons — caniuse](https://caniuse.com/#feat=link-icon-png)

- Apple Touch Icon: Apple touch favicon apple-mobile-web-app-capable are present. _(Create your Apple Icon file with at least 200x200px dimension to support all dimensions that you may need)_

```html
<!-- Apple Touch Icon -->
<link rel="apple-touch-icon" href="/custom-icon.png" />
```

> 📖 [Configuring Web Applications](https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html)

- Windows Tiles:
- Windows tiles are present and linked.

```html
<!-- Microsoft Tiles -->
<meta name="msapplication-config" content="browserconfig.xml" />
```

Minimum required xml markup for the browserconfig.xml file is as follows:

```xml
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
   <msapplication>
     <tile>
        <square70x70logo src="small.png"/>
        <square150x150logo src="medium.png"/>
        <wide310x150logo src="wide.png"/>
        <square310x310logo src="large.png"/>
     </tile>
   </msapplication>
</browserconfig>
```

> 📖 [Browser configuration schema reference](https://msdn.microsoft.com/en-us/library/dn320426%28v=vs.85%29.aspx)

- Canonical: Use rel="canonical" to avoid duplicate content.

```html
<!-- Helps prevent duplicate content issues -->
<link rel="canonical" href="http://example.com/2017/09/a-new-article-to-red.html" />
```

> 📖 [Use canonical URLs — Search Console Help — Google Support](https://support.google.com/webmasters/answer/139066?hl=en)

> 📖 [5 common mistakes with rel=canonical — Google Webmaster Blog](https://webmasters.googleblog.com/2013/04/5-common-mistakes-with-relcanonical.html)

#### HTML tags

- Language attribute: The lang attribute of your website is specified and related to the language of the current page.

```html
<html lang="en"></html>
```

- Direction attribute: The direction of lecture is specified on the html tag (It can be used on another HTML tag).

```html
<html dir="rtl"></html>
```

> 📖 [dir — HTML — MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir)

- Alternate language: The language tag of your website is specified and related to the language of the current page.

```html
<link rel="alternate" href="https://es.example.com/" hreflang="es" />
```

- Conditional comments: Conditional comments are present for IE if needed.

> 📖 [About conditional comments (Internet Explorer) — MSDN — Microsoft](https://msdn.microsoft.com/en-us/library/ms537512%28v=vs.85%29.aspx)

- RSS feed: If your project is a blog or has articles, an RSS link was provided.
- inline critical CSS: CSS which styles content that is immediately visible during pageload (“above the fold content”) is called “critical CSS”. It is embedded before your principal CSS call and between <style></style> in a single line (minified).

> 🛠 [Critical by Addy Osmani on Github](https://github.com/addyosmani/critical) automates this

- CSS order: All CSS files are loaded before any JavaScript files in the `<head>`. (Except the case where sometimes JS files are loaded asynchronously on top of your page).

#### Social meta

_Facebook OG_ and _Twitter Cards_ are, for any website, highly recommended. The other social media tags can be considered if you target a particular presence on those and want to ensure the display.

- Facebook Open Graph: All Facebook Open Graph (OG) are tested and no one is missing or with a false information. Images need to be at least 600 x 315 pixels, 1200 x 630 pixels recommended.

```html
<meta property="og:type" content="website" />
<meta property="og:url" content="https://example.com/page.html" />
<meta property="og:title" content="Content Title" />
<meta property="og:image" content="https://example.com/image.jpg" />
<meta property="og:description" content="Description Here" />
<meta property="og:site_name" content="Site Name" />
<meta property="og:locale" content="en_US" />
```

> 📖 [A Guide to Sharing for Webmasters](https://developers.facebook.com/docs/sharing/webmasters/)

> 🛠 Test your page with the [Facebook OG testing](https://developers.facebook.com/tools/debug/)

- Twitter Card:

```html
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@site_account" />
<meta name="twitter:creator" content="@individual_account" />
<meta name="twitter:url" content="https://example.com/page.html" />
<meta name="twitter:title" content="Content Title" />
<meta name="twitter:description" content="Content description less than 200 characters" />
<meta name="twitter:image" content="https://example.com/image.jpg" />
```

> 📖 [Getting started with cards — Twitter Developers](https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started)

> 🛠 Test your page with the [Twitter card validator](https://cards-dev.twitter.com/validator)

---

### HTML

#### Best practices

- HTML5 Semantic Elements: HTML5 Semantic Elements are used appropriately (header, section, footer, main…).

> 📖 [HTML Reference](http://htmlreference.io/)

- Error pages: Error 404 page and 5xx exist. Remember that the 5xx error pages need to have their CSS integrated (no external call on the current server).
- Noopener: In case you are using external links with target="\_blank", your link should have a rel="noopener" attribute to prevent tab nabbing. If you need to support older versions of Firefox, use rel="noopener noreferrer".

> 📖 [About rel=noopener](https://mathiasbynens.github.io/rel-noopener/)

- Clean up comments: Unnecessary code needs to be removed before sending the page to production.

#### HTML testing

- W3C compliant: All pages need to be tested with the W3C validator to identify possible issues in the HTML code.

> 🛠 [W3C validator](https://validator.w3.org/)

- HTML Lint: I use tools to help me analyze any issues I could have on my HTML code.

> 🛠 [Dirty markup](https://dirtymarkup.com/)

- Link checker: There are no broken links in my page, verify that you don’t have any 404 error.

> 🛠 [W3C Link Checker](https://validator.w3.org/checklink)

- Adblockers test: Your website shows your content correctly with adblockers enabled (You can provide a message encouraging people to disable their adblocker).

---

### Webfonts

- Webfont format: WOFF, WOFF2 and TTF are supported by all modern browsers.

> 📖 [WOFF — Web Open Font Format — Caniuse](https://caniuse.com/#feat=woff).

> 📖 [WOFF 2.0 — Web Open Font Format — Caniuse](https://caniuse.com/#feat=woff2).

> 📖 [TTF/OTF — TrueType and OpenType font support](https://caniuse.com/#feat=ttf)

> 📖 [Using @font-face — CSS-Tricks](https://css-tricks.com/snippets/css/using-font-face/)

- Webfont size: Webfont sizes don’t exceed 2 MB (all variants included).

---

### CSS

> _Notes: Take a look at_ [_CSS guidelines_](https://cssguidelin.es/) _and_ [_Sass Guidelines_](https://sass-guidelin.es/) _followed by most Front-End developers. If you have a doubt about CSS properties, you can visit_ [_CSS Reference_](http://cssreference.io/)_._

- Responsive Web Design: The website is using responsive web design.
- CSS Print: A print stylesheet is provided and is correct on each page.
- Preprocessors: Your page is using a CSS preprocessor ([Sass](http://sass-lang.com/) is preferred).
- Unique ID: If IDs are used, they are unique to a page.
- Reset CSS: A CSS reset (reset, normalize or reboot) is used and up to date. _(If you are using a CSS Framework like Bootstrap or Foundation, a Normalize is already included into it.)_

> 📖 [Reset.css](https://meyerweb.com/eric/tools/css/reset/)

> 📖 [Normalize.css](https://necolas.github.io/normalize.css/)

> 📖 [Reboot](https://getbootstrap.com/docs/4.0/content/reboot/)

- JS prefix: All classes (or id- used in JavaScript files) begin with js- and are not styled into the CSS files.

```html
<div id="js-slider" class="my-slider">
  <!-- Or -->
  <div id="id-used-by-cms" class="js-slider my-slider"></div>
</div>
```

- Embedded or inline CSS: Avoid at all cost embeding CSS in `<style>` tags or using inline CSS: only use for valid reasons (e.g. background-image for slider, critical CSS).
- Vendor prefixes: CSS vendor prefixes are used and are generated accordingly with your browser support compatibility.

> 🛠 [Autoprefixer CSS online](https://autoprefixer.github.io/)

#### Performance

- Concatenation: CSS files are concatenated in a single file. _(Not for HTTP/2)_
- Minification: All CSS files are minified.
- Non-blocking: CSS files need to be non-blocking to prevent the DOM from taking time to load.

> 📖 [loadCSS by filament group](https://github.com/filamentgroup/loadCSS)

> 📖 [Example of preload CSS using loadCSS](https://gist.github.com/thedaviddias/c24763b82b9991e53928e66a0bafc9bf)

- Unused CSS: Remove unused CSS.

> 🛠 [UnCSS Online](https://uncss-online.com/) 🛠

> 🛠 [PurifyCSS](https://github.com/purifycss/purifycss)

> 🛠 [Chrome DevTools Coverage](https://developers.google.com/web/updates/2017/04/devtools-release-notes#coverage)

#### CSS testing

- Stylelint: All CSS or SCSS files are without any errors.

> 🛠 [stylelint, a CSS linter](https://stylelint.io/)

> 📖 [Sass guidelines](https://sass-guidelin.es/)

- Responsive web design: All pages were tested at the following breakpoints: 320px, 768px, 1024px (can be more / different according to your analytics).
- CSS Validator: The CSS was tested and pertinent errors were corrected.

> 🛠 [CSS Validator](https://jigsaw.w3.org/css-validator/)

- Desktop Browsers: All pages were tested on all current desktop browsers (Safari, Firefox, Chrome, Internet Explorer, EDGE…).
- Mobile Browsers: All pages were tested on all current mobile browsers (Native browser, Chrome, Safari…).
- OS: All pages were tested on all current OS (Windows, Android, iOS, Mac…).
- Pixel perfect: Pages are close to pixel perfect. Depending on the quality of the creatives, you may not be 100% accurate, but your page needs to be close to your template.

> [_Pixel Perfect — Chrome Extension_](https://chrome.google.com/webstore/detail/perfectpixel-by-welldonec/dkaagdgjmgdmbnecmcefdhjekcoceebi?hl=en)

- Reading direction: All pages need to be tested for LTR and RTL languages if they need to be supported.

> 📖 [Building RTL-Aware Web Apps & Websites: Part 1 — Mozilla Hacks](https://hacks.mozilla.org/2015/09/building-rtl-aware-web-apps-and-websites-part-1/)

> 📖 [Building RTL-Aware Web Apps & Websites: Part 2 — Mozilla Hacks](https://hacks.mozilla.org/2015/10/building-rtl-aware-web-apps-websites-part-2/)

---

### Images

> _Notes: For a complete understanding of image optimization, check the free ebook_ [_Essential Image Optimization_](https://images.guide/)_from Addy Osmani._

#### Best practices

- Optimization: All images are optimized to be rendered in the browser. WebP format could be used for critical pages (like Homepage).

> 🛠 [Imagemin](https://github.com/imagemin/imagemin)

> 🛠 Use [ImageOptim](https://imageoptim.com/) to optimise your images for free.

- Picture/Srcset: You use picture/srcset to provide the most appropriate image for the current viewport of the user.

> 📖 [How to Build Responsive Images with srcset](https://www.sitepoint.com/how-to-build-responsive-images-with-srcset/)

- Retina: You provide layout images 2x or 3x, support retina display.
- Sprite: Small images are in a sprite file (in the case of icons, they can be in an SVG sprite image).
- Width and Height: Set width and height attributes on `<img>` if the final rendered image size is known (can be omitted for CSS sizing).
- Alternative text: All `<img>` have an alternative text which describe the image visually.

> 📖 [Alt-texts: The Ultimate Guide](https://axesslab.com/alt-texts/)

- Lazy loading: Images are lazyloaded (A noscript fallback is always provided).

---

### JavaScript

#### Best practices

- JavaScript Inline: You don’t have any JavaScript code inline (mixed with your HTML code).
- Concatenation: JavaScript files are concatenated.
- Minification: JavaScript files are minified (you can add the .min suffix).

> 📖 [Minify Resources (HTML, CSS, and JavaScript)](https://developers.google.com/speed/docs/insights/MinifyResources)

- JavaScript security:

> 📖 [Guidelines for Developing Secure Applications Utilizing JavaScript](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet#Guidelines_for_Developing_Secure_Applications_Utilizing_JavaScript)

- Non-blocking: JavaScript files are loaded asynchronously using async or deferred using defer attribute.

> 📖 [Remove Render-Blocking JavaScript](https://developers.google.com/speed/docs/insights/BlockingJS)

- Modernizr: If you need to target some specific features you can use a custom Modernizr to add classes in your `<html>` tag.

> 🛠 [Customize your Modernizr](https://modernizr.com/download?setclasses)

#### JavaScript testing

- ESLint: No errors are flagged by ESLint (based on your configuration or standards rules).

> 📖 [ESLint — The pluggable linting utility for JavaScript and JSX](https://eslint.org/)

---

### Security

#### Scan and check your web site

> [securityheaders.io](https://securityheaders.io/)

> [Observatory by Mozilla](https://observatory.mozilla.org/)

> [ASafaWeb — Automated Security Analyser for ASP.NET Websites](https://asafaweb.com/)

#### Best practices

- HTTPS: HTTPS is used on every pages and for all external content (plugins, images…).

> 🛠 [Let’s Encrypt — Free SSL/TLS Certificates](https://letsencrypt.org/)

> 🛠 [Free SSL Server Test](https://www.ssllabs.com/ssltest/index.html)

> 📖 [Strict Transport Security](http://caniuse.com/#feat=stricttransportsecurity)

- HTTP Strict Transport Security (HSTS):
- The HTTP header is set to ‘Strict-Transport-Security’.

> 🛠 [Check HSTS preload status and eligibility](https://hstspreload.org/)

> 📖 [HTTP Strict Transport Security Cheat Sheet — OWASP](https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet)

> 📖 [Transport Layer Protection Cheat Sheet — OWASP](https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet)

- Cross Site Request Forgery (CSRF): You ensure that requests made to your server-side are legitimate and originate from your website / app to prevent CSRF attacks.

> 📖 [Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet — OWASP](https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29_Prevention_Cheat_Sheet)

- Cross Site Scripting (XSS): Your page or website is free from XSS possible issues.

> 📖 [XSS (Cross Site Scripting) Prevention Cheat Sheet — OWASP](https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet)

> 📖 [DOM based XSS Prevention Cheat Sheet — OWASP](https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet)

- Content Type Options: Prevents Google Chrome and Internet Explorer from trying to mime-sniff the content-type of a response away from the one being declared by the server.

> 📖 [X-Content-Type-Options — Scott Helme](https://scotthelme.co.uk/hardening-your-http-response-headers/#x-content-type-options)

- X-Frame-Options (XFO): Protects your visitors against clickjacking attacks.

> 📖 [X-Frame-Options — Scott Helme](https://scotthelme.co.uk/hardening-your-http-response-headers/#x-frame-options)

> 📖 [RFC7034 — HTTP Header Field X-Frame-Options](https://tools.ietf.org/html/rfc7034)

---

### Performance

#### Best practices

- Weight page: The weight of each page is between 0 and 500 KB.

> 🛠 [Website Page Analysis](https://tools.pingdom.com/)

> 📖 [Size Limit: Make the Web lighter](https://evilmartians.com/chronicles/size-limit-make-the-web-lighter)

- Minified: Your HTML is minified.

> 🛠 [W3C Validator](https://validator.w3.org/)

- Lazy loading: Images, scripts and CSS need to be lazy loaded to improve the response time of the current page (See details in their respective sections).
- Cookie size: If you are using cookies be sure each cookie doesn’t exceed 4096 bytes and your domain name doesn’t have more than 20 cookies.

> 📖 [Cookie specification: RFC 6265](https://tools.ietf.org/html/rfc6265)

> 📖 [Cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies)

> 🛠 [Browser Cookie Limits](http://browsercookielimits.squawky.net/)

- Third party components: Third party iframes or components relying on external JS (like sharing buttons) are replaced by static components when possible, thus limiting calls to external APIs and keeping your users activity private.

> 🛠 [Simple sharing buttons generator](https://simplesharingbuttons.com/)

#### Preparing upcoming requests

> 📖 [Explanation of the following techniques](https://css-tricks.com/prefetching-preloading-prebrowsing/)

- DNS resolution: DNS of third-party services that may be needed are resolved in advance during idle time using dns-prefetch.

```javascript
<link rel="dns-prefetch" href="https://example.com">
```

- Preconnection: DNS lookup, TCP handshake and TLS negociation with services that will be needed soon is done in advance during idle time using preconnect.

```javascript
<link rel="preconnect" href="https://example.com">
```

- Prefetching: Resources that will be needed soon (e.g. lazy loaded images) are requested in advance during idle time using prefetch.

```javascript
<link rel="prefetch" href="image.png">
```

- Preloading: Resources needed in the current page (e.g. scripts placed at the end of `<body>`) in advance using preload.

```javascript
<link rel="preload" href="app.js">
```

> 📖 [Difference between prefetch and preload](https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf)

#### Performance testing

- Google PageSpeed: All your pages were tested (not only the homepage) and have a score of at least 90/100.

> 🛠 [Google PageSpeed](https://developers.google.com/speed/pagespeed/insights/)

> 🛠 [Test your mobile speed with Google](https://testmysite.withgoogle.com/)

> 🛠 [WebPagetest — Website Performance and Optimization Test](https://www.webpagetest.org/)

---

### Accessibility

> _Notes: You can watch the playlist_ [_A11ycasts with Rob Dodson_](https://www.youtube.com/playlist?list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g) _📹_

#### Best practices

- Progressive enhancement: Major functionality like main navigation and search should work without JavaScript enabled.

> 📖 [Enable / Disable JavaScript in Chrome Developer Tools](https://www.youtube.com/watch?v=kBmvq2cE0D8)

- Color contrast: Color contrast should at least pass WCAG AA (AAA for mobile).

> 🛠 [Contrast ratio](https://leaverou.github.io/contrast-ratio/)

#### Headings

- H1: All pages have an H1 which is not the title of the website.
- Headings: Headings should be used properly in the right order (H1 to H6).

> 📹 [Why headings and landmarks are so important — A11ycasts #18](https://www.youtube.com/watch?v=vAAzdi1xuUY&index=9&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g)

#### Landmarks

- Role coverImage: `<header>` has role="banner".
- Role navigation: `<nav>` has role="navigation".
- Role main: `<main>` has role="main".

> 📖 [Using ARIA landmarks to identify regions of a page](https://www.w3.org/WAI/GL/wiki/Using_ARIA_landmarks_to_identify_regions_of_a_page)

#### Semantics

- Specific HTML5 input types are used: This is especially important for mobile devices that show customized keypads and widgets for different types.

> 📖 [Mobile Input Types](http://mobileinputtypes.com/)

#### Form

- Label: A label is associated with each input form element. In case a label can’t be displayed, use aria-labelinstead.

> 📖 [Using the aria-label attribute — MDN](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute)

#### Accessibility testing

- Accessibility standards testing: Use the WAVE tool to test if your page respects the accessibility standards.

> 🛠 [Wave testing](http://wave.webaim.org/)

- Keyboard navigation: Test your website using only your keyboard in a previsible order. All interactive elements are reachable and usable.
- Screen-reader: All pages were tested in a screen-reader (VoiceOver, ChromeVox, NVDA or Lynx).
- Focus style: If the focus is disabled, it is replaced by visible state in CSS.

> 📹 [Managing Focus — A11ycasts #22](https://www.youtube.com/watch?v=srLRSQg6Jgg&index=5&list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g)

---

### SEO

- Google Analytics: Google Analytics is installed and correctly configured.
- Headings logic: Heading text helps to understand the content in the current page.
- sitemap.xml: A sitemap.xml exists and was submitted to Google Search Console (previously Google Webmaster Tools).
- robots.txt: The robots.txt is not blocking webpages.

> 🛠 Test your robots.txt with [Google Robots Testing Tool](https://www.google.com/webmasters/tools/robots-testing-tool)

- Structured Data: Pages using structured data are tested and are without errors. Structured data helps crawlers understand the content in the current page.

> 📖 [Introduction to Structured Data — Search — Google Developers](https://developers.google.com/search/docs/guides/intro-structured-data)

> 🛠 Test your page with the [Structured Data Testing Tool](https://developers.google.com/structured-data/testing-tool/)

> 🛠 Complete list of vocabularies that can be used as structured data. [Schema.org Full Heirarchy](http://schema.org/docs/full.html)

- Sitemap HTML: An HTML sitemap is provided and is accessible via a link in the footer of your website.

> 📖 [Sitemap guidelines — Google Support](https://support.google.com/webmasters/answer/183668?hl=en)

> 🛠 [Sitemap generator](https://websiteseochecker.com/html-sitemap-generator/)
]]></description>
            <link>https://hungvn.com/blog/the-front-end-checklist</link>
            <guid isPermaLink="true">https://hungvn.com/blog/the-front-end-checklist</guid>
            <pubDate>Tue, 28 Nov 2017 10:36:59 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nghiên cứu cải thiện tốc độ web app với React và Preact: Treebo]]></title>
            <description><![CDATA[
[Treebo](https://treebo.com) is India’s top rated budget hotel chain, operating in a segment of the travel industry worth $20 billion. They [recently](https://www.treebo.com/blog/google-io-2017-features-treebos-progressive-web-app/) shipped a new Progressive Web App as their default mobile experience, initially using [React](http://reactjs.com) and eventually switching to [Preact](http://preactjs.com) in production.

What they saw compared to their old mobile site was **a 70%+ improvement in time to first paint , 31% improvement in** [**time-to-interactive**](https://github.com/WPO-Foundation/webpagetest/blob/master/docs/Metrics/TimeToInteractive.md)**. and loaded in under 4 seconds over 3G** for many typical visitors and on their target hardware. It was interactive in under 5s using WebPageTest’s slower 3G emulation in India.

![](https://cdn-images-1.medium.com/max/2000/1*gVklUhiYIWw3LAKSL8wJjg.png)

**Switching from React to Preact was responsible for a 15% improvement in time-to-interactive alone**. You can check out [Treebo.com](https://treebo.com) for their full experience but today we would like to dive into some of the technical journey that made shipping this PWA possible.

![](https://cdn-images-1.medium.com/max/2000/1*QSIGKBY4t49YdOENePb2Jw.png)Treebo’s Progressive Web App

### A Performance Journey

#### The old mobile site

Treebo’s old mobile site was powered by a monolithic Django setup. Users had to wait for a server side request for every page transition on the website. This original setup had a first paint time of 1.5s, a first meaningful paint time of 5.9s and was first interactive in 6.5s.

![](https://cdn-images-1.medium.com/max/2000/1*zEQEtv1mzxBaE7lg4cpurg.png)

#### A basic single-page React app

For their first iteration of the rewrite Treebo started off with a **Single Page Application** built using React and a simple [webpack](https://webpack.js.org/) setup.

You can take a look at the actual code used below. This generates some simple (monolithic) JavaScript and CSS bundles.

<Gist id="d809f1d8fb7c5702b875435599d78d68" />

This experience had a first paint of 4.8s, was first interactive in about 5.6s and their meaningful header images painted in about 7.2s.

![](https://cdn-images-1.medium.com/max/2000/1*e623cjcetyonpGXys4yOLQ.png)

#### Server-side Rendering

Next, they went about optimizing their first paint a little so they tried out **Server-side Rendering**. **It’s important to note, server side rendering is not free. It optimizes one thing at the cost of another.**

> With [server-side rendering](https://css-tricks.com/server-side-react-rendering/), your server’s response to the browser is the HTML of your page that is ready to be rendered so the browser can start rendering without having to wait for all the JavaScript to be downloaded and executed.

Treebo used React’s [renderToString()](https://facebook.github.io/react/docs/react-dom-server.html#rendertostring) to render components to an HTML string and injecting state for the application on initial boot up.

<Gist id="f4d08e0391e015ee295a53ff3ccabafe" />

In Treebos’ case, using server side rendering dropped their first paint time to 1.1s and first meaningful paint time down to 2.4s — this improved how quickly users _perceived_ the page to be ready, they could read content earlier on and it performed slightly better at SEO in tests. But the downside was that it had a pretty negative impact on time to interactive.

![](https://cdn-images-1.medium.com/max/2000/1*SSKzzeSML-gTmWZQB9EqSQ.png)

Although users could _view_ content, the main thread got pegged while booting up their JavaScript and just hung there.

**With SSR, the browser had to fetch and process a much larger HTML payload than before and then still fetch, parse/compile and execute the JavaScript. It was effectively doing more work.**

This meant that first interactive happened about 6.6s, regressing.

SSR can also push TTI back by locking up the main thread on lower-end devices.

#### Code-splitting & route-based chunking

The next thing Treebo looked at was **route-based chunking** to help bring down their time-to-interactive numbers.

> [Route-based chunking](https://gist.github.com/addyosmani/44678d476b8843fd981ff8011d389724) aims to serve the minimal code needed to make a route interactive, by [code-splitting](https://webpack.js.org/guides/code-splitting/) the routes into “chunks” that can be loaded on demand. This encourages delivering resources closer to the granularity they were authored in.

What they did here was they split out their vendor dependencies, their Webpack runtime manifests and their routes — into separate chunks.

<Gist id="bc4a63c13173a1908c764c67e1fb8df2" />
<Gist id="563e6bda38f4f5b6293ceb32f38c85a2" />

This reduced the time to first interactive down to 4.8s. Awesome!

The only downside was that it started the current route’s JavaScript download only after their initial bundles were done executing, which was also not ideal.

But it did at least have some positive impact on the experience. For route-based code-splitting and this experience, they’re doing something a little bit more implicit. They’re using React Router’s declarative support for getComponent with a webpack import() call to asynchronously load in chunks.

![](https://cdn-images-1.medium.com/max/2000/1*YEJIN_D73FLy6bT-F2p1WA.png)

#### The PRPL Performance Pattern

Route-based chunking is a great first step in intelligently bundling code for more granular serving and caching. Treebo wanted to build on this and looked to the [**PRPL pattern**](https://developers.google.com/web/fundamentals/performance/prpl-pattern/)for inspiration.

> PRPL is a pattern for structuring and serving PWAs, with an emphasis on the performance of app delivery and launch.

PRPL stands for:

- **Push** critical resources for the initial URL route.
- **Render** initial route.
- **Pre-cache** remaining routes.
- **Lazy-load** and create remaining routes on demand.

![](https://cdn-images-1.medium.com/max/2000/1*wSy1jUPr08N8UKL_fHhXlw.png)A PRPL visualization by Jimmy Moon

The “Push” part encourages serving an unbundled build designed for server/browser combinations that support HTTP/2 to deliver the resources the browser needs for a fast first paint while optimizing caching. The delivery of these resources can be triggered efficiently using [link-rel-preload](https://developers.google.com/web/updates/2016/03/link-rel-preload) or [HTTP/2 Push](https://developers.google.com/web/fundamentals/performance/http2/#server-push).

Treebo opted to use `<link rel=”preload” />` to preload the current route’s chunk ahead of time. This had the impact of dropping their first interactive times since the current route’s chunk was already in the cache when webpack made a call to fetch it after their initial bundles finished executing. It shifted the time down a little bit and so the first interactive happened at the 4.6s mark.

![](https://cdn-images-1.medium.com/max/2000/1*Uhwf9VgUNDWtxV7Gp9NZkg.png)

The only con they had with preload is that it’s not implemented cross-browser. However, there’s an implementation of link rel preload in Safari Tech Preview. I’m hopeful that it’s going to land and stick this year. There’s also work underway to try landing it in Firefox.

#### HTML Streaming

> One difficulty with renderToString() is that it is synchronous, and it can become a performance bottleneck in server-side rendering of React sites. Servers won’t send out a response until the entire HTML is created. When web servers stream out their content instead, browsers can render pages for users before the entire response is finished. Projects like [react-dom-stream](https://github.com/aickin/react-dom-stream) can help here.

To improve perceived performance and introduce a sense of progressive rendering to their app, Treebo looked to **HTML Streaming**. They would stream the head tag with link rel preload tags set up to early preload in their CSS and their JavaScripts. They then perform their server side rendering and send the rest of the payload down to the browser.

The benefit of this was that resource downloads started earlier on, dropping their first paint to 0.9s and first interactive to 4.4s. The app was consistently interactive around the 4.9/5 second mark.

![](https://cdn-images-1.medium.com/max/2000/1*6PgaKR-HCQctzQVE7dIRqg.png)

The downside here was that it kept the connection open for a little bit longer between the client and server, which could have issues if you run into longer latency times. For HTML streaming, Treebo defined an early chunk with the `<head>` content, then they have the main content and the late chunks. All of these being injected into the page. This is what it looks like:

<Gist id="33142b2eae0806210ecead567dceab75" />

Effectively, the early chunk has got their rel=preload statements for all of their different script tags. The late chunk has got the server rendered html and anything that’s going to include state or actually use the JavaScript that’s being loaded in.

#### Inlining critical-path CSS

> CSS Stylesheets can block rendering. Until the browser has requested, received, downloaded and parsed your stylesheets, the page can remain blank. By reducing the amount of CSS the browser has to go through, and by inlining ([critical-path styles](https://jonassebastianohlsson.com/criticalpathcssgenerator/#what-is)) it on the page, thus removing a HTTP request, we can get the page to render faster.

Treebo added support for **Inlining their critical-path CSS** for the current route and asynchronously loading in the rest of their CSS using [loadCSS](https://github.com/filamentgroup/loadCSS) on DOMContentLoaded.

It had the effect of removing the critical-path render blocking link tag for stylesheets and inlining fewer lines of core CSS, improving first paint times to about 0.4s.

<Gist id="f7410178545720e260898de3b5054276" />

The downside was that time to first interactive went up a bit to 4.6s as the payload size was larger with inline styles and took time to parse before JavaScript could be executed.

![](https://cdn-images-1.medium.com/max/2000/1*pnXHVJYx4wnb5NogNcBcTg.png)

#### Offline-caching static assets

> A [Service Worker](https://developers.google.com/web/fundamentals/getting-started/primers/service-workers) is a programmable network proxy, allowing you to control how network requests from your page are handled.

Treebo added support for **Service Worker** caching of their static assets as well a custom offline page. Below we can see their Service Worker registration and how they used [sw-precache-webpack-plugin](https://www.npmjs.com/package/sw-precache-webpack-plugin) for resource caching”

<Gist id="fb2b569631a5c6d5585951ae516302ea" />
![](https://cdn-images-1.medium.com/max/2000/0*TwNbHKi9HH60PKa7.)

Caching static assets like their CSS and JavaScript bundles means pages load up (almost) instantly on repeat visits as they load from the disk cache rather than having to go back out to the network each time. Diligently defined caching headers can have this same effect with respect to disk cache hit-rates, but it’s Service Worker that gives us offline support.

![](https://cdn-images-1.medium.com/max/1600/0*ISP4LE8o1LO-DbFI.)

Serving JavaScript cached using Service Worker using the Cache API (as we covered in [JavaScript Start-up Performance](https://medium.com/reloading/javascript-start-up-performance-69200f43b201)) also has the nice property of early-opting Treebo into V8’s code cache so they save a little time on start-up during repeat visits.

Next, Treebo wanted to try getting their vendor bundle-size and JS execution time down, so they switched from React to **Preact** in production.

#### Switching from React to Preact

[Preact](http://preactjs.com) is a tiny 3KB alternative to React with the same ES2015 API. It aims to offer high performance rendering with an optional compatibility later (preact-compat) that works with the rest of the React ecosystem, like Redux.

Part of Preact’s smaller size comes from removing Synthetic Events and PropType validations. In addition it:

- Diffs Virtual DOM against the DOM
- Allows props like class and for
- Passes (props, state) to render
- Uses standard browser events
- Supports fully async rendering
- Subtree invalidation by default

In a number of PWAs, switching to Preact has led to smaller JS bundle sizes and lower initial JavaScript boot-up times for the application. Recent PWA launches like Lyft, Uber and Housing.com all use Preact in production.

**Note: Working with a React codebase and want to use Preact? Ideally, you should use preact and preact-compat for your dev, prod and test builds. This will enable you to discover any interop bugs early on. If you would prefer to only alias preact and preact-compat in Webpack for production builds (e.g if your preference is using Enzyme), make sure to thoroughly test everything works as expected before deploying to your servers.**

In Treebo’s case, this switch had the impact of dropping their vendor bundle sizes from 140kb all the way down to 100kb. This is all gzipped, by the way. It dropped first interactive times from **4.6s to 3.9s** on Treebo’s target mobile hardware which was a net win.

![](https://cdn-images-1.medium.com/max/2000/1*asckjwAnPWgEnH5UcAKd3w.png)

You can do this in your Webpack config by aliasing react to [preact-compat](https://github.com/developit/preact-compat), and react-dom to preact-compat as well.

<Gist id="3a435a65e8a78957c97a27e9589ef38a" />

The downside to this approach was that they did have to end up putting together a few workarounds in order to get Preact working exactly with all the different pieces of the React ecosystem that they wanted to use.

Preact tends to be a strong choice for the 95% of cases you would use React; for the other 5% you may end up needing to file bugs to work around edge-cases that are not yet factored in.

_Notes: As WebPageTest does not currently offer a way to test real Moto G4s directly from India, performance tests were run under the “Mumbai — EC2 — Chrome — Emulated Motorola G (gen 4) — 3GSlow — Mobile” setting. Should you wish to look at these traces they can be found_ [_here_](https://gist.github.com/addyosmani/d2fc259e1f1d19b64ae0fcbdfac025a2)_._

#### **Skeleton screens**

> “A skeleton screen is essentially a blank version of a page into which information is gradually loaded.”

> ~Luke Wroblewski

![](https://cdn-images-1.medium.com/max/2000/1*sahnJCMruB6mmvjMwzDkUQ.png)

Treebo like to implement their skeleton screens using preview enhanced components (a little like skeleton screens for each component). The approach is basically to enhance any atomic component (Text, Image etc) to have a preview version, such that if the source data that is required for the component is not present, it shows the preview version of the component instead.

For example, if you look at the hotel name, city name, price etc in the list items above, they’re implemented using Typography components like `<Text />` which take two extra props, preview and previewStyle which is used like so.

<Gist id="fb053d71edcf002ccb88a278a2fec306" />

Basically, if the hotel.name does not exist then the component changes the background to a greyish color with the width and other styles set according to the previewStyle passed down (width defaults to 100% if no previewStyle is passed).

<Gist id="41a92ed1059756aed91dfe4afe42d60a" />

Treebo likes this approach because the logic to switch to the preview mode is independent of the data actually being shown which makes it flexible. If you look at the “Incl. of all taxes” part, it’s just static text, which could have been shown right at the start but that would’ve looked very confusing to the user since the prices are still loading during the api call.

So to get the static text “Incl. of all prices” into a preview mode alongside the rest of the ui they just use the price itself as the logic for the preview mode.

<Gist id="65d5f5932241ba68473a55c09707a00e" />

This way while the prices are loading you get a preview UI and once the api succeeds you get to see the data in all its glory.

### **Webpack-bundle-analyzer**

At this point, Treebo wanted to perform some bundle analysis to look at what other low-hanging fruit they could optimize.

**Note: If you’re using a library like React on mobile, it’s important to be diligent about the other vendor libraries you are pulling in. Not doing so can negatively impact performance. Consider better chunking your vendor libraries so that routes only load those that are needed**

Treebo used [webpack-bundle-analyzer](https://www.npmjs.com/package/webpack-bundle-analyzer) to keep track of their bundle size changes and to monitor what modules are contained in each route chunk. They also use it to find areas where they can optimize to reduce bundle sizes such as stripping moment.js’ locales and reusing deep dependencies.

#### Optimizing moment.js with webpack

Treebo relies heavily on [moment.js](https://momentjs.com/) for their date manipulations. When you import moment.js and bundle it with Webpack, your bundle will include all of moment.js and it’s locales by default which is ~61.95kb gzipped. This seriously bloats your final vendor bundle size.

![](https://cdn-images-1.medium.com/max/2000/0*hCQTD69-U1v7tO8x.)

To optimize the size of moment.js, there are [two webpack plugins](https://github.com/jmblog/how-to-optimize-momentjs-with-webpack) available: [IgnorePlugin](https://webpack.js.org/plugins/ignore-plugin/), [ContextReplacementPlugin](https://webpack.js.org/plugins/context-replacement-plugin/)

Treebo opted to remove all locale files with the IgnorePlugin since they didn’t need any of the them.

**new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)**

With the locales stripped out, the moment.js’ bundled size dropped to ~16.48kb gzipped.

![](https://cdn-images-1.medium.com/max/1600/0*ZjW0M4b_xhN_GFaE.)

The biggest improvement as a side effect of stripping out moment.js’ locales was that the vendor bundle size dropped from ~179kb to ~119kb. That’s a massive 60kb drop from a critical bundle that has to be served on first load. All this translates to a considerable decrease in first interaction times. You can read more about optimizing moment.js [here](https://github.com/jmblog/how-to-optimize-momentjs-with-webpack).

#### Reusing existing deep dependencies

Treebo was initially using the “qs” module to perform query string operations. Using the webpack-bundle-analyzer output they found that “react-router” included the “history” module which in-turn included the “query-string” module.

![](https://cdn-images-1.medium.com/max/1600/0*8yOSbnWVyHeXltKM.)

Since there were two different modules both accomplishing the same operations, replacing “qs” with this version of “query-string” (by installing it explicitly) in their source code, dropped their bundle size by a further 2.72kb gzipped (size of the “qs” module).

Treebo have been good open source citizens. They’ve been using a lot of open source software. In return, they’ve actually open sourced most of their Webpack configuration, as well as a boilerplate that contains a lot of the set up they’re using in production. You can find that here: [https://github.com/lakshyaranganath/pwa](https://github.com/lakshyaranganath/pwa)

![](https://cdn-images-1.medium.com/max/1600/0*u6wzzX7XAxJFBQ0T.)

They’ve also committed to trying to keep that up to date. As they evolve you can take advantage of them as another PWA reference implementation.

### **Conclusions and the future**

Treebo knows that no application is perfect, they actively explore many methods to keep improving the experience they deliver to their users. Some of which are:

**Lazy Loading Images**
Some of you might have figured out from the network waterfall graphs before that the website image downloads are competing for bandwidth with the JS downloads.

![](https://cdn-images-1.medium.com/max/2000/0*a_0WeA_JrALu8-lV.)

Since image downloads are triggered as soon as the browser parses the img tags, they share the bandwidth during JS downloads. A simple solution would be lazy loading images only when they come into the user’s viewport, this will see a good improvement in our time to interactive.

Lighthouse highlights these problems well in the offscreen images audit:

![](https://cdn-images-1.medium.com/max/1600/1*fbZP4KSAzZdUD6_q1WnO1Q.png)

**Dual Importing**

Treebo also realise that while they are asynchronously loading the rest of the CSS for the app (after inlining the critical css), this approach is not viable for their users in the long run as their app grows. More features and routes means more CSS, and downloading all of that leads to bandwidth hogging and wastage.

Merging approaches followed by [loadCSS](https://github.com/filamentgroup/loadCSS) and [babel-plugin-dual-import](https://github.com/faceyspacey/babel-plugin-dual-import), Treebo changed their approach to loading CSS by using an explicit call to a custom implemented importCss(‘chunkname’) to download the CSS chunk in parallel to their import(‘chunkpath’) call for their respective JS chunk.

<Gist id="834e4e3efdba3766770849f688a275a8" />

With this new approach, a route transition results in two parallel asynchronous requests, one for JS and the other for CSS unlike the previous approach where all of the CSS was being downloaded on DOMContentLoaded. This is more viable since a user will only ever download the required CSS for the routes they are visiting.

**A/B Testing** Treebo are currently implementing an AB testing approach with server side rendering and code splitting so as to only push down the variant that user needs during both server and client side rendering. (Treebo will follow up with a blog post on how they tackled this).

**Eager Loading** Treebo ideally don’t want to always load all the split chunks of the app on load of the initial page since they want to avoid the bandwidth contention for critical resource downloads — this also wastes precious bandwidth for mobile users especially if you’re not caching it with service-worker for their future visits. If we look at how well Treebo is doing on metrics like consistently interactive, there’s still much room for improvement:

![](https://cdn-images-1.medium.com/max/2000/1*jSAh4rt_B2qhJsKfYMfuBA.png)

This is an area they’re experimenting with improving. One example is eager loading the next route’s chunk during the ripple animation of a button. onClick Treebo make a webpack [dynamic import()](https://webpack.js.org/guides/code-splitting/#dynamic-imports) call to the next route’s chunk entry and delay the route transition with a setTimeout. They also want to make sure that the next route’s chunk is small enough to be downloaded within the given 400ms timeout on a slow 3g network.

### That’s a wrap.

It’s been fun collaborating on this write-up. There’s obviously more work to be done, but we hope you found Treebo’s performance journey an interesting read :) You can find us over on twitter at [@addyosmani](https://medium.com/@addyosmani "Medium profile for @addyosmani") and [@\_\_lakshya](https://medium.com/@__lakshya "Medium profile for @__lakshya") (yep, double underscore xD) we would love to hear your thoughts.

_With thanks to_ [_@\_zouhir_](https://twitter.com/@_zouhir)_,_ [_@\_developit_](https://twitter.com/@_developit) _and_ [_@samcccone_](https://twitter.com/@samccone) _for their reviews and input._
]]></description>
            <link>https://hungvn.com/blog/nghien-cuu-cai-thien-toc-do-web-app-voi-react-va-preact-treebo</link>
            <guid isPermaLink="true">https://hungvn.com/blog/nghien-cuu-cai-thien-toc-do-web-app-voi-react-va-preact-treebo</guid>
            <pubDate>Wed, 15 Nov 2017 08:26:38 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách chính xác 100% để cấu trúc ứng dụng React]]></title>
            <description><![CDATA[
When it comes to structuring a React app, the ideal structure is the one that allows you to move around your code with the least amount of effort.

In this post, I'd like to tell you how _I_ structure my React apps, and what drove my decisions. Along the way I'll mention some options I don't use because they don't suit me, but that might serve you well.

I'd also like to hear how you do things and what you've found works well down in the comments.

### What works for you

Maybe this was always obvious to you, but it's only just clicked for me: the structure of an app has nothing to do with computers.

Imagine for a moment an app with only one file for all your components, reducers, the store, utilities, everything.

A terrible idea, of course. Now, have a think about _why_ the above would be a bad thing.

We both know you didn't really stop and ponder, so I'll just tell you what I think. The problem with this giant file is that it's going to be difficult to navigate. But what if you could have bookmarks for each area of the code, maybe one bookmark per function. Maybe the ability to have _nested_ bookmarks. How about a table of contents for all of these bookmarks?

This might seem like a daft thought experiment, but I think it's worth establishing that the _only_ thing you're trying to do when deciding on a file structure is to maximise how easily you can navigate through your code. Your ‘files' are nothing more than markers to parts of the code that will wind up being a single chunk of JS at the end of the day.

And this is why you can never get a straight answer to the question “what's the best way to structure my app” — it depends so much on your own navigation habits and preferences that it's not a question anyone else can answer for you.

---

To work out what the 100% correct application structure was _for me_, I set out to quantify my most common code-related activities:

- **Create a new component**. Usually this is a copy/paste of some existing component.
- **Import one module into another**. Here I mean the actual typing out of `import { SomeComponent } from '../blah/de/blah.js';`.
- **Jump to source**. This is when I'm looking at a file, and it has a reference to something external, say a `<HeaderNav>` component, and I jump to where that component is defined.
- **Open a known file**. Probably doesn't need a description, but I want my bullet points to look nice and uniform, so this is where I think in my head “I want to open the header nav”, so I use a keyboard shortcut and type the file name to open it. Dammit, now this is the bullet point with the longest description and it didn't even need one in the first place.
- **Browse for a file I don't know the name of**. Maybe I didn't work on the little widget that shows the drop down below the user profile photo and don't know what it's called. So I want to go browsing the directory structure for this component.
- **Change tab to another open file**. This is exactly what it sounds like. I currently have 7 files open, and I want to switch from one tab to another, by clicking on a tab name (or using the keyboard).

Next, I had a think about how often I do each of these things. I went back and counted the components I've created in the last year, the average number of imports per file, and took some wild guesses at the others, to come up with the following:

![](https://cdn-images-1.medium.com/max/2000/1*Pmm5N4hr9cANciDL5nbDpw.png)Sorted by the order that I thought of the things

With this data in my hot little hands, I was ready to objectively look at all the aspects of structuring a React app. Let us go through them one by one.

#### Directory structure

As a general rule, if a module (a utility, component, etc.) is only used within another module, then I want it nested in the directory structure like so:

![](https://cdn-images-1.medium.com/max/1600/1*dUdTcjW1krgImFrhZoPjkA.png)

`<HeaderNav>` will only be referenced from within the `<Header>` component, so it lives as a child. A `<Button>` could be referenced from anywhere, so it lives at the top level.

That rule is great, but I also know that following a super strict set of rules here can be annoying. Technically everything resides under App and under Page too. But I'm not going to represent that in my directory structure, because I don't want to.

This might sound flippant but it's quite fundamental. If following your own rules creates a structure that is _harder_ to navigate, you've taken your eyes off the prize.

Outside of components, I don't think directory structure is very important. You can agonise over whether your reducers and your action creators should be in the same directory as your services until you're a shade of blue. But if you ask me, any basic structure with sane folder names (actionCreators, reducers, data, etc.) is all you need.

This may be the first point where we differ in our needs and wants. I have established that I rarely open files by browsing through a directory structure, so naturally I apply a lower importance to directory structures. I've also never worked on a project with more than a few hundred components.

If you rely more heavily on navigating a directory structure, or you're Facebook with 30,000 components, then your needs will likely vary.

Another thing: I would suggest naming your components in a ‘fully qualified' (and globally unique) way. For example, HeaderNav is inside Header, so you could argue that it could just be named Nav. If that suits you, cool. But I open files by typing their names, and look at the text on tabs to switch files. In both these cases, having a fully qualified name is useful.

And of course if you're following BEM where the block matches the component name, you're going to need globally unique component names anyway.

#### What about container components?

Container components are a tricky one, because they're sort of components, but sort of not.

I see two broad approaches to fitting container components into your structure:

1.  Treat them exactly like presentational components
2.  Leave them out of the directory structure. They will live ‘in the background', just providing data to a component

In the **first case**, you would actually reference the container component in your markup. So, with the example of a header component that has its own container, it might be included like so:

<Gist id="https://medium.com/media/463238924efd0f86ee8d206d99fa1ce1?postId=3ede534ef1ed" />

So here I'm passing through some specific data to the `<Page>` and `<Footer>` components, while it's quite clear that the `<HeaderContainer>` is going to look after its own data needs.

If this is how you roll, the logical structure will be something like this:

![](https://cdn-images-1.medium.com/max/1600/1*wZl20Yi2C6ZLuJJ-Qrr2-Q.png)

The **second option** is to leave container components out of the structure; to think of them like implementation details of the component that they wrap.

So maybe your `<Header>` would wrap itself in a container component at the point of export. Something like this:

<Gist id="https://medium.com/media/ec9911836643c07a0b9642d1db1a2d86?postId=3ede534ef1ed" />

And then you reference it like this:

<Gist id="https://medium.com/media/d12d29a5607a3e07472e8e67af156841?postId=3ede534ef1ed" />

The downside is that it isn't immediately clear that `<Header />` will be provided data from somewhere else. The upside is one less step in the component hierarchy.

If this is how you want to do things, you can then just have the container as a function that lives in the same directory as the component it provides data to:

![](https://cdn-images-1.medium.com/max/1600/1*0WuTztg_evQbRcc3VP8OYQ.png)

(Also note that I exported the ‘raw' Header as well as the default export of the container-wrapped Header. The former is for unit tests, and your linter might tell you that you're being confusing by exporting a non-default constant with the same name as the file. I tend to agree with the linter.)

---

I have used the first approach in a medium sized project and it worked quite well. I recently tried out the second example in a new project (that only has 6 container components) and it didn't quite feel right, so I'll stick with the first option.

I see no problem with either approach.

Side note: I think there's a fine art to recognising the point at which it makes sense to say “you know what, it doesn't really matter” and moving on with your day. [This article nails it](http://blog.capwatkins.com/the-sliding-scale-of-giving-a-fuck) and is a nice short read. (Warning: there's a swear word in the title of that article, so don't click the link if you're offended by the word fuck.)

#### Self-contained components

My rule: if I have a project with more components than a Klein bottle has sides, I put each component in a directory along with a CSS file and a test. This rule is common for good reason, but even if you do have everything neatly tucked away in the same directory, you're still quite free to make one huge mistake…

Take a look at your nearest file that contains a component. At the top of that file you will probably see a list of all other files that the component relies on as a neat set of imports.

Unless, that is, you share CSS classes between components. Then you also have a bunch of dependencies that aren't listed.

Sure, you will save 7 seconds by using that .modal-wrapper class in your `<DropDown>` component because it already had the shadow you wanted, but oh boy do you even know the world of pain that you have just inflicted upon your future self...

[deleted scene: 14 paragraph rant about why this is a bad idea]

Trying to convince some people to not share CSS classes between components is like trying to convince people to “avoid using global variables in JavaScript” or “vaccinate your chickens” — some folks just aren't gonna listen.

CSS-module users are no doubt wiggling their butts feeling pretty darn pleased with themselves right now. And they have good reason to be — they have a setup that can enforce the explicit import of CSS classes. If you care about keeping your CSS tightly coupled with your components, you should be using CSS modules too.

#### File naming

One rule that I find immensely useful is this:

> name your file the same as the thing you're exporting from that file

To some this is not even worth typing out it's so obvious. But I've seen plenty of code where this isn't the case and boy does it make it slow to move around.

(Don't forget, _all of this is personal_. When I say “slow to move around”, it's totally OK for you to think “it wouldn't make it slow for me”, and therefore decide that there is no point in naming a file the same as its default export.)

Something I do very often is open a file by typing its name. If I have a utility function called toString then I fully expect that I will have a _file_ called toString that I can open by typing exactly that. Something else that I do very often is switch tabs to a file that I already have open. For this I'll expect that tab to have “toString.js” as it's name.

Structures like the below make me want to curl up in a ball in a fireplace that is in use:

![](https://cdn-images-1.medium.com/max/1600/1*EXRWu1imSsSJ_OJu2Udjew.png)

It staggers me that some people are happy to work like this.

![](https://cdn-images-1.medium.com/max/1600/1*FXqIEm2b8ZnLW0OC1AzXww.png)

Even if your IDE is clever and puts the directory in the tab name for non-unique filenames, you still have a bunch of redundancy there, and will run out of tab room sooner, and you still can't type the filename to open it. I don't even need to try this approach to know I won't like it. Like my cousin's new band, _Mass Spectrometer_ that “don't really fit into any known genre”. Get someone else to drive you to the gig.

Having said that, I understand that there is reasoning behind this — it means your import statement is this:

```javascript
**import** Link **from** '../Link';
```

Instead of this:

```javascript
**import** Link **from** '../Link/Link';
```

It's a clear trade-off. Shorter import statements vs file names that match exports.

Let's me just look this up… I import a module into another module, on average, 18 times a week. I open a file by typing its name roughly 840 times a week, and I look for a name on a tab roughly 1,892 times a week.

So I'll take one extra (auto-completed) word in my import path, thanks.

Savvy readers will be shouting at their screens: there are two solutions to this that allow you have the file name match the thing being exported, _and_ avoid having to type it twice in the import statement.

**The first** is to put an index.js file in every directory that exports a component, like so:

![](https://cdn-images-1.medium.com/max/1600/1*N1Urd1IUNrCUPrbFIoIlBA.png)

Since [Node will look for an](https://nodejs.org/api/modules.html#modules_all_together) [index.js](https://nodejs.org/api/modules.html#modules_all_together) [file](https://nodejs.org/api/modules.html#modules_all_together) when resolving an import path, a path to ../Link is really a path to ../Link/index.js which is a file that points to the actual component file.

If typing fewer characters in your imports is important, then maybe an extra file for every directory sounds like good value. I think it's a bad deal and I will repeat one more time that it's seriously OK to have a different opinion on the matter.

**The second** ‘solution' is this monstrosity:

![](https://cdn-images-1.medium.com/max/1600/1*jHV85E1ZAdR2VRP-BoGZCw.png)

By this point you will know that if Node doesn't find ../Link/index.js it's going to check to see if ../Link/package.json exists. If it does, it's going to resolve to the value of the main property.

I think you have to really really hate typing one extra word in your import statements to go as far as creating a package.json file for every component. It's just _weird_. And the more weird shit you put in your code, the weirder you become.

These two types of ‘redirecting' files both mean that your import statement no longer points to the file where the thing is defined.

In the olden days, this would break the ability to ‘jump to source' — something that is crucial to me being able to move throughout my code with ease and speed. WebStorm is clever and will resolve these hops (it will ‘know' that I don't want to jump into the index.js file, I want to jump all the way to the Link.js file), but if your text editor isn't so clever, this might leave you with a lot of index.js files open, or jumping to source might not work at all.

So before subscribing to an approach, try it out and see if it's going to be a hindrance to the way you work.

#### .js vs .jsx extensions

Until recently I'd always used .jsx extensions for any file that contained JSX, and used .js for anything that was vanilla JavaScript. This gave a clear distinction when opening/viewing files and as a bonus, you'll get proper JSX syntax highlighting in GitHub.

However Facebook suggests [_not_ using the .jsx extension](https://github.com/facebookincubator/create-react-app/issues/87#issuecomment-234627904), so I've recently been using just .js and I'm glad I didn't waste too much time weighing the pros and cons because it makes zero difference to me.

I recommend flipping a coin to decide.

#### Index files for utils

As a result of writing this article, and really thinking about what matters to me, I have actually made a change to one small aspect of my personal preference for app structure.

I used to create an index.js file for my utils, like so:

![](https://cdn-images-1.medium.com/max/1600/1*mjCnATVib2XNXvWUs8uMVw.png)

So that I could import multiple utilities in one go like this:

<Gist id="https://medium.com/media/317c2f29ff6fab2a5cfa28efdb758b65?postId=3ede534ef1ed" />

So neat!

Whenever I added a new util (0.8 times per week) I would simply add the util file and a new entry in the index file. Whenever I saw a PR that added a util and forgot to add it to index.js I would remind the developer to add that in. I would also occasionally discover utilities that weren't in index.js, so would have to add them myself. Such an elegant solution.

For some reason it took until September 2017 for me to realise that this only _added_ complexity. And that actually ditching the index.js and doing this was better:

<Gist id="https://medium.com/media/9867e01dd197336b4969702c5c48404f?postId=3ede534ef1ed" />

It's fewer lines, one less file, and one less thing to explain to new developers.

But those long import paths burn my eyes, so let's take a look at a couple of solutions. There are two of them, as is often the case with couples.

**Solution one** is to use [Webpack's alias resolving](https://webpack.js.org/configuration/resolve/#resolve-alias) to refer to my utils directory without a relative path. Here I've mapped Utils to src/app/utils; the result is pretty, and aligns nicely with the way I import other utilities.

![](https://cdn-images-1.medium.com/max/1600/1*5i9uDzXkAUFpJqvhEkULdA.png)Capital ‘U' by convention to differentiate it from npm packages

In the olden days this would confuse some text editors because they wouldn't know what or where Utils/formatDate was. My IDE is clever and reads my Webpack config (it actually [runs webpack under the hood](https://blog.jetbrains.com/webstorm/2017/06/webstorm-2017-2-eap-172-2827/)), and makes the connection to the correct file (so I can jump to source, get autocomplete, etc).

(The theme continues: the tools we use and the way we use them should most definitely be taken into account when thinking about how to structure our apps.)

So… it's a beautiful, neat, solution. But what's behind the scenes?

<Gist id="https://medium.com/media/a0e6459055c30a8a50454b151b70f201?postId=3ede534ef1ed" />

This is a nice solution but it has two negative impacts.

1.  It adds **complexity**. We now have more moving parts to achieve the exact same outcome.
2.  It reduces **clarity**. Someone unfamiliar with your Webpack config can't look at an import statement and know what it's referring to.

**The second** **solution** is to convince myself that I don't care about the dots and leave them as they are.

To convince myself, I thought about how often I type out an import path, and as it turns out it's exactly as often as I make coffee. Then I thought about how really, it's not so hard to type eight dots and five slashes, compared to the time it takes to put the little coffee pod in the machine, measure out a teaspoon of sugar into a cup, milk the cow just a little bit (shout out to Daisy) and press the picture of a cup.

The trade-offs between these two options are representative of many different decisions (in life, and in programming), so this feels like a good time to debut my clarity/obscurity-simplicity/complexity matrix.

![](https://cdn-images-1.medium.com/max/2000/1*1E4bcDylUocokBcbENXedQ.png)ClObSiCo for short

For me, the decision between these two is a close call. In the end though, I will favour clarity and simplicity wherever possible, so even though having ../../../../ in an import statement is an eyesore, it is the clear and simple winner.

#### Index files for components

It's not my cup of tea, but another thing you might like to do in the battle against the import dots is to create a library for your components.

Maybe this gets your motor running:

<Gist id="https://medium.com/media/bc9df168c97178118813f9cd68a18869?postId=3ede534ef1ed" />

You already know how to do this in your Webpack config:

<Gist id="https://medium.com/media/0cc44e665fe48539d6976a1e0ed1f8b0?postId=3ede534ef1ed" />

Then in your components directory add an index.js file with a row for each component like so:

![](https://cdn-images-1.medium.com/max/1600/1*rbFT4XPm9ljA_bAGcVcL_w.png)

Boom.

#### n exports per file

Having one export per file — where the thing being exported and the filename are the same — works _a lot_ of the time and I think is a good general rule for components and utility functions.

But I don't think this works for constants. I also like to start with a single file for all action creators, until it becomes a burden. Same for reducers. In my experience it doesn't make much difference whether you have eight, 10-line reducers in a single file or eight different files.

If you think it has a significant impact on how quickly you can locate a particular piece of code, then do what works for you. Heck, maybe [Redux ducks](https://medium.com/@scbarrus/the-ducks-file-structure-for-redux-d63c41b7035c) make your boat float. Sure, whatever.

### What works for the team

Now seems like a good time to explain the title of this post. If you're working on a project that is just you, then you might be able to find a React structure that is 100% correct, for you. In fact I think it's well worth aiming for this.

But the more people there are on a team, the less likely it is that you'll find something ‘optimal', and the more likely other factors will come into play.

The big one is compromise. Be aware of [distinction bias](https://en.m.wikipedia.org/wiki/Distinction_bias). You can probably tell from the above that for some items I would be happy to go another way if a team member expressed a strong preference. If someone _really_ wanted to use .jsx extensions or have a Utils alias, I'd be cool with that because although it's not my preference, it won't reduce my ability to work quickly. But if someone _really really_ wanted every damn file to be named index.js then it'd be on like Donkey Kong.

Another consideration: if you have, say, 30 developers on a team and you're starting a new project, you might want to structure it as closely to previous projects as possible, no use reinventing the wheel. Or maybe you'll want to learn from past mistakes and have a different structure, fix that badly-invented wheel.

Another little thing: as your team gets bigger, git conflicts will become a bigger part of your day, and erring on the side of smaller files will be a benefit.

If you have a mixture of skill levels on the team, that should encourage you to favour simplicity and clarity. On the flip side, if you have a team of seasoned front end engineers (mmm, seasoned), then go nuts and make it as complex as you like. As long as everyone is on the same wavelength, it doesn't matter how [weird it looks from the outside](https://i.imgur.com/4R6GyYC.gifv).

### Summary

I have a confession to make. I always struggle with summaries. It's like, I just wrote you a whole blog post, what more do you want from me!

So it's not a summary, but I think the most interesting aspect of all the different approaches to application structure is the way people deal with disagreements. There's a whole class of internet comments that can be summarised as “I disagree and that makes me ANGRY”. Which is a pity, because when two reasonable people disagree, there's very often something interesting going on, just waiting to be discovered.

And since I'm already doing a terrible job of wrapping this up, how about a movie recommendation? If you liked _District 9_, and haven't watched _Chappie_ yet, then watching _Chappie_ is something you should immediately go and do.

Thanks for reading. Bye!
]]></description>
            <link>https://hungvn.com/blog/cach-chinh-xac-100-de-cau-truc-ung-dung-react</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-chinh-xac-100-de-cau-truc-ung-dung-react</guid>
            <pubDate>Mon, 13 Nov 2017 23:51:55 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Làm thế nào để tổ chức tốt hơn những ứng dụng React]]></title>
            <description><![CDATA[
I’ve been working on very large web applications for the past few years, starting from ground zero and, with a dozen other developers, making them scale up to now be used by millions of people. And sometimes, if you didn’t start with a good architecture, it can become difficult to keep your code organized.

[Nathanael Beisiegel](http://engineering.kapost.com/author/nathanaelbeisiegel/) wrote an interesting article where he explains his strategy in the organization of large React applications, but I still wasn’t completely satisfied by his approach. So I decided to spend some time to figure out what could be the best way to organize my future React projects.

Note: I use Redux files in all the examples of this article. If you don’t know what Redux is, you can have a look to the [documentation here](http://redux.js.org/).

Note2: All examples are based on ReactJS, but you can use exactly the same structure for a React-Native application.

### What are the challenges when you build an application?

This has happened or will happen to pretty much all developers over the course of their career:

- You build an application for a client with a team of a few developers, everything works very well all together.
- Your client requires new features, fine, you add them.
- Your client asks you to remove some features and add new ones, it starts to get complicated, you didn’t think about that, but you make it work even though it’s not perfect.
- Your client now wants you to change another feature, remove some others and add another one that wasn’t expected. At that point, you grab the scotch tape and start patching some code. You are not really proud of it but it works.
- 6 months later, after some other iterations, the code of the application gets really complicated to read and understand, everything looks like some Italian spaghetti pasta.

Until the day your client decides to create a new version of the application, with some fresh new code and features. In some cases, you end-up keeping complicated legacy code that lives with the new code, and this becomes even harder to maintain. And all of this happened because your app wasn’t properly designed from the beginning.

---

When I started to learn React, I found a few very good articles explaining how to create Todo lists or very simple games. Those articles were very useful to understand the basics of React, but I quickly got to a point where I wasn’t able to find much about how I could use React to build actual applications, something with a few dozens pages and hundreds of components.

After some research, I learned that every React boilerplate project on Github results to similar structures, they organize all the files by type. This might look familiar to you:

```javascript
/src
  /actions
    /notifications.js

 /components
    /Header
    /Footer
    /Notifications
      /index.js
  /containers
    /Home
    /Login
    /Notifications
      /index.js

  /images
    /logo.png

  /reducers
    /login.js
    /notifications.js

  /styles
    /app.scss
    /header.scss
    /home.scss
    /footer.scss
    /notifications.scss

  /utils
  index.js
```

This architecture might be okay to build your website or application, but I believe that it is not the best architecture.

When you organize your files by type, as your application grows, it often becomes difficult to maintain. By the time you realize this, it’s too late and you will have to invest a lot of time and money to change everything, or to support what you have for the next few years.

The good thing with React is that you can structure your application in any way you like. You are not forced to follow a certain folder structure, React is simply a javascript library.

### What could be a better approach to organize your application?

For a couple of years I worked for a financial institution which used Ember as their main javascript framework to build all their new web applications. One interesting thing about Ember is the ability to structure your project by features, instead of by type. And this changes everything.

Pods in Ember are great but still limited, and I wanted something much more flexible. After a few experiments, trying to find what would be the best structure, I got to a point where I decided to group all related features together, and nest them as needed. This is what I use now:

```javascript
/src
  /components
    /Button
    /Notifications
      /components
        /ButtonDismiss
          /images
          /locales
          /specs
          /index.js
          /styles.scss
      /index.js
      /styles.scss
  /scenes
    /Home
      /components
        /ButtonLike
      /services
        /processData
      /index.js
      /styles.scss

    /Sign
      /components
        /FormField
      /scenes
        /Login
        /Register
          /locales
          /specs
          /index.js
          /styles.scss

  /services
    /api
    /geolocation
    /session
      /actions.js
      /index.js
      /reducer.js
    /users
      /actions.js
      /api.js
      /reducer.js
  index.js
  store.js
```

Each component, scene or service (a feature) has everything it needs to work on its own, such as its own styles, images, translations, set of actions as well as unit or integration tests. You can see a feature like an independent piece of code you will use in your app (a bit like _node modules_).

To work properly, they should follow these rules:

- A component can define nested components or services. It cannot use or define scenes.
- A scene can define nested components, scenes or services.
- A service can define nested services. It cannot use or define components or scenes.
- Nested features can only use from its parent.

_Note: By parent feature, I mean a parent, grandparent, great-grandparent etc… You cannot use a feature that is a “cousin”, this is not allowed. You will need to move it to a parent to use it._

Let’s break this down.

#### **Components**

You all already know what a component is, but one important thing in this organization is the ability to nest a component into another component.

Components defined at the root level of your project, in the _components_ folder, are global and can be used anywhere in your application. But if you decide to define a new component inside another component (nesting), this new component can only be used its direct parent.

**Why would you want to do that?**

When you develop a large application, it happens quite often that you need to create a component that you definitively know you won’t reuse anywhere else, but you need it. If you add it at the root level of your _components_ folder, it will get lost with hundreds of components. Sure, you could categorize them, but when it’s time to do some clean-up, you won’t remember what they are all for or if they are still being used somewhere.

Although, if you define at the root level only the main components of your application, such as buttons, form fields, thumbnails, but also more complicated one like listComments, formComposer with their own children components, it gets much easier to find what you need.

Example:

```javascript
/src
  /components
    /Button
      /index.js
    /Notifications
      /components
        /ButtonDismiss
          /index.js
      /actions.js
      /index.js
      /reducer.js
```

- _Button_ can be used anywhere in your application.
- _Notifications_ can also be used anywhere. This component defines a component _ButtonDismiss._ You cannot use _ButtonDismiss_ anywhere else than in the _Notifications_ component.
- _ButtonDismiss_ uses _Button_ internally, this is authorized because _Button_ is defined at the root level of _components_.

#### **Scenes**

A scene is a page of your application. You can see a scene just like any component, but I like to separate them into their own folder.

If you use [React-Router](https://github.com/reactjs/react-router) or [React Native Router](https://github.com/aksonov/react-native-router-flux), you can import all your scenes in your main index.js file and setup your routes.

With the same principle components can be nested, you can also nest a scene into a scene, and also define components or services into a scene. You have to remember that if you decide to define something into a scene, you can only use it within the scene folder itself.

Example:

```javascript
/src
  /scenes
    /Home
      /components
        /ButtonShare
          /index.js
      /index.js

    /Sign
      /components
        /ButtonHelp
          /index.js

      /scenes
        /Login
          /components
            /Form
              /index.js
            /ButtonFacebookLogin
              /index.js
          /index.js

        /Register
          /index.js
      /index.js
```

- _Home_ has a component _ButtonShare_, it can only be used by the Home scene.
- _Sign_ has a component _ButtonHelp_. This component can be used by _Login_ or _Register_ scenes, or by any components defined in those scenes.
- _Form_ component uses _ButtonHelp_ internally, this is authorized because _ButtonHelp_ is defined by a parent.
- The _Register_ scene cannot use any of the components defined in _Login_, but it can use the _ButtonHelp._

#### **Services**

Not everything can be a component, and you will need to create independent modules that can be used by your components or scenes.

You can see a service like a self-contained module where you will define the core business logic of your application. This can eventually be shared between several scenes or even applications, such as a web and native version of you app.

```javascript
/src
  /services
    /api
      /services
        /handleError
          /index.js
      /index.js    /geolocation
    /session
      /actions.js
      /index.js
      /reducer.js
```

I recommend you to create services to manage all api requests. You can see them as a bridge/an adapter between the server API and the view layer (scenes and components) of your application. It can take care of network calls your app will make, get and post content, and transform payloads as needed before being sent or saved in the store of your app (such as Redux). The scenes and components will only dispatch actions, read the store and update themselves based on the new changes.

---

### Wrapping up

I’ve been working with this architecture for the past few months on a personal project built with React-Native, and I can tell you this saved me a lot of time. It’s much more simpler to have all related entities grouped together, it makes things easier to work with.

This architecture is one of many other ways to organize your project, that’s the way I like it now and I hope this will help you improve yours!

If you are interested to see working projects, I have a few on my Github account that follows this architecture:

- [https://github.com/alexmngn/react-rock-paper-scissors](https://github.com/alexmngn/react-rock-paper-scissors) (ReactJS)
- [https://github.com/alexmngn/react-native-authentication](https://github.com/alexmngn/react-native-authentication) (React-Native)

Feel free to add a comment below or contact me directly if you have any question, I’ll be more than happy to help.

Have fun!
]]></description>
            <link>https://hungvn.com/blog/lam-the-nao-de-to-chuc-tot-hon-nhung-ung-dung-react</link>
            <guid isPermaLink="true">https://hungvn.com/blog/lam-the-nao-de-to-chuc-tot-hon-nhung-ung-dung-react</guid>
            <pubDate>Mon, 13 Nov 2017 23:48:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Làm thế nào để cấu trúc các components trong React? ]]></title>
            <description><![CDATA[
Programming is quite a complex task. Especially crafting clean code is hard. We need to take care of many elements — naming variables, scoping functions, handling errors, ensuring security, monitoring performance etc. Still to name single most difficult thing in programming I would go with **writing loosely coupled & highly cohesive components**. It doesn’t matter if we’re talking about object-oriented or functional programming. Structuring system is the hardest thing and it has a big impact on the overall project. It takes years to become proficient in designing software architecture (& probably one can never really master it — in such a fast moving industry mastery is always one step ahead, there is always a way to improve design).

I really enjoy working with React & I think its biggest advantage is how simple React is. There is a difference between simple & easy [https://www.infoq.com/presentations/Simple-Made-Easy](https://www.infoq.com/presentations/Simple-Made-Easy). And I really mean React is simple. Of course, you need to spend some time to get to know it. But after you understand core concepts, everything else is just a consequence. The hard part comes next.

#### Coupling & Cohesion

Those are the metrics that more or less describe how difficult it will be to change the behaviour of the code. Coupling & cohesion are used in object-oriented programming and refer to some form of classes. We’ll use them in reference to React components since the same rules apply.

Coupling is connection or dependency between elements. If changing one element _requires_ changing another element then we say there is _tight coupling_. If elements are _loosely coupled_, changing one element _does not imply_ changes in the other. For example, let’s take a look at displaying bank transfer amount. If displaying amount knows how rates are calculated, then anytime internal structure of transfer changes, displaying code also needs to be updated. If we design system to be loosely coupled, based on the interface of an element, then changes to transfer shouldn’t result in changes to the view layer. Loosely coupled components are easier to manage and maintain.

Cohesion tells if element’s responsibilities form one thing. That metric is connected with Single Responsibility Principle or Unix principle: Do one thing and do it well. If account balance formatter also calculates interest rates and checks the permission to display history, then it has many responsibilities and those are not related to each other. Probably, there should be different components for permission handling or interest rates. On the other hand, if there are multiple components one for integer part, one for floating and one for currency, then anytime programmer wants to display balance, they would need to find all elements. The challenge is to create highly cohesive components.

#### Structuring components

There are many ways we can structure components. We want components to be reusable, but only to the degree that is reasonable. We want to build small components that can be used to build bigger concepts. Ideally, we want to build loosely coupled & highly cohesive components, so our system is easier to maintain and grow. In React components props can be treated like function arguments and that’s exactly the case for functional stateless components. How we define props in a component, defines how a component can be reused.

We’ll use expense manager domain and we’ll analyze expense details formatter. Let’s suppose that expense model looks like this:

<Gist id="3e5c1110488dd166fbf96e671c9b0a31" />

There are several possibilities to model expense details formatter:

- no props at all
- passing expense object
- passing only required properties
- passing map of properties
- passing format as a child

We’ll discuss each of them to see what are benefits and flaws of using each and every. **Keep in mind that context is the king and everything depends on the system. That’s exactly what we’re paid for — building proper abstraction.**

#### No props at all

The simplest solution & the one that is often the starting point is building a component with hard-coded data.

<Gist id="b23018c9e6068f087f692c22be8b2311" />

Passing no props, of course, doesn’t give us any flexibility and component is suitable to be used only in single place. Of course, in the example of expense details, we can see from the beginning that component needs to accept some props. Nevertheless, there are cases that components without any props is good solution. Firstly, we can use components without props for “constant” content like badges, logos, company info etc.

<Gist id="f678bcb5d7b26f532af1fed53bd9b0ac" />

Building even small components makes a system more maintainable. Keeping information in one place allows making changes in one place. **Don’t repeat yourself.**

#### Passing expense object

In case of expense details definitely, we need to pass data to the component. First, we’ll take a look at passing expense object.

<Gist id="f1d9cae19a47a07dcb9831fcfa781535" />

Passing expense object to expense details component makes perfect sense. Expense details formatter is highly coherent -> it displays data of expense. Whenever we want to change formatting, this is the only place that’s going to change. Also changing expense details formatter does not introduce any side effects to expense object itself.

The component is tightly coupled to expense object. Is that a bad thing? Definitely not, but we must be aware how that influences our system. Passing expense object as props, results that expense details component relies on the internal structure of expense. Whenever we change the internal structure of expense, we’ll also need to change expense details. Of course, we’ll only need to make changes in one place.

How does that design affect future changes? If we want to add, change or remove a field, we’ll only need to change one component. What if we want to add different date formatters? We could add another prop for date formatting.

<Gist id="43581d012b0ba1ea70eff7fff8e71909" />

We start adding additional properties to make the component more flexible. As long as there are only a few options, everything is great. The problem starts after system grows and we have a lot of props for different use cases.

```javascript
const ExpenseDetails = ({ expense, dateFormat, withCurrency, currencyFormat, isOverdue, isPaid ... })
```

Adding props makes the component more reusable, but it can also be a sign that there are multiple responsibilities of the component. The same rule applies to the function. We can create a function with a number of parameters, but as soon as that number is greater than 3–4, it starts to do a lot of things. And probably that’s the time to split function into smaller one.

As number of component props grow, we can decide to split component into more defined ones like: OverdueExpenseDetails, PaidExpenseDetails etc.

#### Passing only required properties

To be less coupled with expense object itself, we can pass only required properties.

<Gist id="b3a6163659d5c003bb388950c06cbb70" />

We’re passing each and every property separately, so we’re moving the responsibility a bit to one who is using component. If internal structure of expense changes, it’s not affecting expense details formatter itself -> but probably it can affect every place that is using component because props need to be changed. When passing props as separate properties, a component is more abstract.

How passing only required fields affect future design? Adding/updating/removing fields is not easy now. Whenever we want to add a field, we not only need to change the implementation of expense details but also change every place where component is used :(

```javascript
const ExpenseDetails = ({ category, description, amount, date, account, comment, case ... }) => ( ... )
```

On the other hand, supporting multiple date formatting is done almost out-of-the-box. Since we’re passing date as a prop, we can pass formatted date.

<Gist id="b146710be07d2366e424b10397a38e43" />

Deciding how to display particular field is in the hands of the one who uses the component. That is no longer the case of expense details component implementation.

#### Passing map/array of properties

Going even more abstract, we could pass a map of properties.

<Gist id="b309a1196fa663f22f73ebf882993d2f" />

The one who uses component is in control over formatting expense details. The object passed to the component has to be properly formatted.

<Gist id="8604d3f2f1f5bbf2511f5c2b59d87e7d" />

That solution has many flaws. We have very little control over how the component will look. The order of reduce is not specified, so we’ll need to add some kind of order. Instead of a map, we could pass an array with objects to overcome that problem, but it still will have drawbacks.

Passing map/array as props is not coupled to expense at all but is also not coherent at all. Adding/removing new properties is only a matter of changing prop, but we have no control over the formatting of the component itself. If we want to change only the formatting of the category, it’s not possible it this solution. (_To be precise, there is always a way to tweak stuff. For example by passing another props with formatting config. Yet that solution is no longer clean and straightforward._)

#### Passing format as a child

We could also take as little responsibility as possible and pass data as a child.

<Gist id="59b77b957009e48e75dda4bb3b06309e" />

In that case, expense details is only a container to provide some structure and styling. To display details the one using component has to provide all information.

<Gist id="f3686dc82d016bc615695b7f7c267f3f" />

Probably in case of expense details, it’s not a good solution, since we’ll need to repeat a lot. Still, flexibility is huge and there are a lot of different formatting possibilities. Adding/removing/updating fields is only a matter of changing the use of the component. The same goes with date formatting. We lose coherence, but that’s the price we had to pay.

#### Context is the king

As you can see, we’re exchanging different advantages and possibilities. Which one is the best? It depends on:

- on project itself
- on stage of project
- on the component — do we want more specific components or few with options
- on one’s preferences
- on requirements — is that component supposed to change frequently & used frequently

**There is no single good solution. One size doesn’t fit all.** How we structure our components has a great impact on how we’ll maintain a system and how expandable it will be. It all depends on the context. Thankfully we have plenty of options and we can pick and choose. Components are a great abstraction to build both small and big systems. It’s _only_ a case of picking right solution.
]]></description>
            <link>https://hungvn.com/blog/lam-the-nao-de-cau-truc-cac-components-trong-react</link>
            <guid isPermaLink="true">https://hungvn.com/blog/lam-the-nao-de-cau-truc-cac-components-trong-react</guid>
            <pubDate>Mon, 13 Nov 2017 23:41:33 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách hoạt động của JavaScript: Quản lý bộ nhớ + 4 cách xử lý memory leaks thông dụng]]></title>
            <description><![CDATA[
A few weeks ago we started a series aimed at digging deeper into JavaScript and how it actually works: we thought that by knowing the building blocks of JavaScript and how they come to play together you'll be able to write better code and apps.

The first post of the series focused on providing [an overview of the engine, the runtime, and the call stack](https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf). Thе [second post examined closely the internal parts of Google's V8 JavaScript engine](https://blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e) and also provided a few tips on how to write better JavaScript code.

In this third post, we'll discuss another critical topic that's getting ever more neglected by developers due to the increasing maturity and complexity of programming languages that are being used on a daily basis — memory management. We'll also provide a few tips on how to handle memory leaks in JavaScript that we at [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=Post-3-v8-intro) follow as we need to make sure SessionStack causes no memory leaks or doesn't increase the memory consumption of the web app in which we are integrated.

#### Overview

Languages, like C, have low-level memory management primitives such as malloc() and free(). These primitives are used by the developer to explicitly allocate and free memory from and to the operating system.

At the same time, JavaScript allocates memory when things (objects, strings, etc.) are created and “automatically” frees it up when they are not used anymore, a process called _garbage collection_. This seemingly “automatical” nature of freeing up resources is a source of confusion and gives JavaScript (and other high-level-language) developers the false impression they can choose not to care about memory management. **This is a big mistake.**

Even when working with high-level languages, developers should have an understanding of memory management (or at least the basics). Sometimes there are issues with the automatic memory management (such as bugs or implementation limitations in the garbage collectors, etc.) which developers have to understand in order to handle them properly (or to find a proper workaround, with a minimum trade off and code debt).

#### Memory life cycle

No matter what programming language you're using, memory life cycle is pretty much always the same:

![](https://cdn-images-1.medium.com/max/1600/1*slxXgq_TO38TgtoKpWa_jQ.png)

Here is an overview of what happens at each step of the cycle:

- **Allocate memory **— memory is allocated by the operating system which allows your program to use it. In low-level languages (e.g. C) this is an explicit operation that you as a developer should handle. In high-level languages, however, this is taken care of for you.
- **Use memory — **this is the time when your program actually makes use of the previously allocated memory. **Read** and **write** operations are taking place as you're using the allocated variables in your code.
- **Release memory** — now is the time to release the entire memory that you don't need so that it can become free and available again. As with the **Allocate memory** operation, this one is explicit in low-level languages.

For a quick overview of the concepts of the call stack and the memory heap, you can read our [first post on the topic](https://blog.sessionstack.com/how-does-javascript-actually-work-part-1-b0bacc073cf).

#### What is memory?

Before jumping straight to memory in JavaScript, we'll briefly discuss what memory is in general and how it works in a nutshell.

On a hardware level, computer memory consists of a large number of
[flip flops](https://en.wikipedia.org/wiki/Flip-flop_%28electronics%29). Each flip flop contains a few transistors and is capable of storing one bit. Individual flip flops are addressable by a **unique identifier**, so we can read and overwrite them. Thus, conceptually, we can think of our entire computer memory as a just one giant array of bits that we can read and write.

Since as humans, we are not that good at doing all of our thinking and arithmetic in bits, we organize them into larger groups, which together can be used to represent numbers. 8 bits are called 1 byte. Beyond bytes, there are words (which are sometimes 16, sometimes 32 bits).

A lot of things are stored in this memory:

1.  All variables and other data used by all programs.
2.  The programs' code, including the operating system's.

The compiler and the operating system work together to take care of most of the memory management for you, but we recommend that you take a look at what's going on under the hood.

When you compile your code, the compiler can examine primitive data types and calculate ahead of time how much memory they will need. The required amount is then allocated to the program in the call **stack space**. The space in which these variables are allocated is called the stack space because as functions get called, their memory gets added on top of the existing memory. As they terminate, they are removed in a LIFO (last-in, first-out) order. For example, consider the following declarations:

```javascript
int n; // 4 bytes
int x[4]; // array of 4 elements, each 4 bytes
double m; // 8 bytes
```

The compiler can immediately see that the code requires
4 + 4 × 4 + 8 = 28 bytes.

> That's how it works with the current sizes for integers and doubles. About 20 years ago, integers were typically 2 bytes, and double 4 bytes. Your code should never have to depend on what is at this moment the size of the basic data types.

The compiler will insert code that will interact with the operating system to request the necessary number of bytes on the stack for your variables to be stored.

In the example above, the compiler knows the exact memory address of each variable. In fact, whenever we write to the variable n, this gets translated into something like “memory address 4127963” internally.

Notice that if we attempted to access x[4] here, we would have accessed the data associated with m . That's because we're accessing an element in the array that doesn't exist — it's 4 bytes further than the last actual allocated element in the array which is x[3], and may end up reading (or overwriting) some of m's bits. This would almost certainly have very undesired consequences for the rest of the program.

![](https://cdn-images-1.medium.com/max/1600/1*5aBou4onl1B8xlgwoGTDOg.png)

When functions call other functions, each gets its own chunk of the stack when it is called. It keeps all its local variables there, but also a program counter that remembers where in its execution it was. When the function finishes, its memory block is once again made available for other purposes.

#### Dynamic allocation

Unfortunately, things aren't quite as easy when we don't know at compile time how much memory a variable will need. Suppose we want to do something like the following:

```javascript
int n = readInput(); // reads input from the user
...
// create an array with "n" elements
```

Here, at compile time, the compiler does not know how much memory the array will need because it is determined by the value provided by the user.

It, therefore, cannot allocate room for a variable on the stack. Instead, our program needs to explicitly ask the operating system for the right amount of space at run-time. This memory is assigned from the **heap space**. The difference between static and dynamic memory allocation is summarized in the following table:

![](https://cdn-images-1.medium.com/max/1600/1*qY-yRQWGI-DLS3zRHYHm9A.png)Differences between statically and dynamically allocated memory

To fully understand how dynamic memory allocation works, we need to spend more time on **pointers,** which might be a bit too much of a deviation from the topic of this post. If you're interested in learning more, just let me know in the comments and we can go into more details about pointers in a future post.

#### Allocation in JavaScript

Now we'll explain how the first step (allocate memory**)** works in JavaScript.

JavaScript relieves developers from the responsibility to handle memory allocations — JavaScript does it by itself, alongside declaring values.

```javascript
var n = 374; // allocates memory for a number
var s = "sessionstack"; // allocates memory for a string
var o = {
  a: 1,
  b: null,
}; // allocates memory for an object and its contained values

var a = [1, null, "str"]; // (like object) allocates memory for the
// array and its contained values

function f(a) {
  return a + 3;
} // allocates a function (which is a callable object)
// function expressions also allocate an object
someElement.addEventListener(
  "click",
  function () {
    someElement.style.backgroundColor = "blue";
  },
  false
);
```

Some function calls result in object allocation as well:

```javascript
var d = new Date(); // allocates a Date object
var e = document.createElement("div"); // allocates a DOM element
```

Methods can allocate new values or objects:

```javascript
var s1 = "sessionstack";
var s2 = s1.substr(0, 3); // s2 is a new string
// Since strings are immutable,
// JavaScript may decide to not allocate memory,
// but just store the [0, 3] range.var a1 = ['str1', 'str2'];
var a2 = ["str3", "str4"];
var a3 = a1.concat(a2);
// new array with 4 elements being
// the concatenation of a1 and a2 elements
```

#### Using memory in JavaScript

Using the allocated memory in JavaScript basically, means reading and writing in it.

This can be done by reading or writing the value of a variable or an object property or even passing an argument to a function.

#### Release when the memory is not needed anymore

Most of the memory management issues come at this stage.

The hardest task here is to figure out when the allocated memory is not needed any longer. It often requires the developer to determine where in the program such piece of memory is not needed anymore and free it.

High-level languages embed a piece of software called **garbage collector** which job is to track memory allocation and use in order to find when a piece of allocated memory is not needed any longer in which case, it will automatically free it.

Unfortunately, this process is an approximation since the general problem of knowing whether some piece of memory is needed is [undecidable](http://en.wikipedia.org/wiki/Decidability_%28logic%29) (can't be solved by an algorithm).

Most garbage collectors work by collecting memory which can no longer be accessed, e.g. all variables pointing to it went out of scope. That's, however, an under-approximation of the set of memory spaces that can be collected, because at any point a memory location may still have a variable pointing to it in scope, yet it will never be accessed again.

#### Garbage collection

Due to the fact that finding whether some memory is “not needed anymore” is undecidable, garbage collections implement a restriction of a solution to the general problem. This section will explain the necessary notions to understand the main garbage collection algorithms and their limitations.

#### Memory references

The main concept garbage collection algorithms rely on is the one of **reference**.

Within the context of memory management, an object is said to reference another object if the former has an access to the latter (can be implicit or explicit). For instance, a JavaScript object has a reference to its [prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain) (**implicit reference**) and to its properties' values (**explicit reference**).

In this context, the idea of an “object” is extended to something broader than regular JavaScript objects and also contains function scopes (or the global **lexical scope**).

> Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.

#### Reference-counting garbage collection

This is the simplest garbage collection algorithm. An object is considered “garbage collectible” if there are **zero** references pointing to it.

Take a look at the following code:

```javascript
var o1 = {
  o2: {
    x: 1,
  },
};
// 2 objects are created.
// 'o2' is referenced by 'o1' object as one of its properties.
// None can be garbage-collected

var o3 = o1; // the 'o3' variable is the second thing that
// has a reference to the object pointed by 'o1'.
o1 = 1; // now, the object that was originally in 'o1' has a
// single reference, embodied by the 'o3' variable

var o4 = o3.o2; // reference to 'o2' property of the object.
// This object has now 2 references: one as
// a property.
// The other as the 'o4' variable

o3 = "374"; // The object that was originally in 'o1' has now zero
// references to it.
// It can be garbage-collected.
// However, what was its 'o2' property is still
// referenced by the 'o4' variable, so it cannot be
// freed.

o4 = null; // what was the 'o2' property of the object originally in
// 'o1' has zero references to it.
// It can be garbage collected.
```

#### Cycles are creating problems

There is a limitation when it comes to cycles. In the following example, two objects are created and reference one another, thus creating a cycle. They will go out of scope after the function call, so they are effectively useless and could be freed. However, the reference-counting algorithm considers that since each of the two objects is referenced at least once, neither can be garbage-collected.

```javascript
function f() {
  var o1 = {};
  var o2 = {};
  o1.p = o2; // o1 references o2
  o2.p = o1; // o2 references o1\. This creates a cycle.
}

f();
```

![](https://cdn-images-1.medium.com/max/1600/1*GF3p99CQPZkX3UkgyVKSHw.png)

#### Mark-and-sweep algorithm

In order to decide whether an object is needed, this algorithm determines whether the object is reachable.

The Mark-and-sweep algorithm goes through these 3 steps:

1.  Roots: In general, roots are global variables which get referenced in the code. In JavaScript for example, a global variable that can act as a root is the “window” object. The identical object in Node.js is called “global”. A complete list of all roots gets built by the garbage collector.
2.  The algorithm then inspects all roots and their children and marks them as active (meaning, they are not garbage). Anything that a root cannot reach will be marked as garbage.
3.  Finally, the garbage collector frees all memory pieces that are not marked as active and returns that memory to the OS.

![](https://cdn-images-1.medium.com/max/1600/1*WVtok3BV0NgU95mpxk9CNg.gif)A visualization of the mark and sweep algorithm in action

This algorithm is better than the previous one since “an object has zero reference” leads to this object being unreachable. The opposite is not true as we have seen with cycles.

As of 2012, all modern browsers ship a mark-and-sweep garbage-collector. All improvements made in the field of JavaScript garbage collection (generational/incremental/concurrent/parallel garbage collection) over the last years are implementation improvements of this algorithm (mark-and-sweep), but not improvements over the garbage collection algorithm itself, nor its goal of deciding whether an object is reachable or not.

[In this article](https://en.wikipedia.org/wiki/Tracing_garbage_collection), you can read in a greater detail about tracing garbage collection that also covers mark-and-sweep along with its optimizations.

#### Cycles are not a problem anymore

In the first example above, after the function call returns, the two objects are not referenced anymore by something reachable from the global object. Consequently, they will be found unreachable by the garbage collector.

![](https://cdn-images-1.medium.com/max/1600/1*FbbOG9mcqWZtNajjDO6SaA.png)

Even though there are references between the objects, they're not reachable from the root.

#### Counter intuitive behavior of Garbage Collectors

Although Garbage Collectors are convenient they come with their own set of trade-offs. One of them is _non-determinism_. In other words, GCs are unpredictable. You can't really tell when a collection will be performed. This means that in some cases programs use more memory that it's actually required. In other cases, short-pauses may be noticeable in particularly sensitive applications. Although non-determinism means one cannot be certain when a collection will be performed, most GC implementations share the common pattern of doing collection passes during allocation. If no allocations are performed, most GCs stay idle. Consider the following scenario:

1.  A sizable set of allocations is performed.
2.  Most of these elements (or all of them) are marked as unreachable (suppose we null a reference pointing to a cache we no longer need).
3.  No further allocations are performed.

In this scenario, most GCs will not run any further collection passes. In other words, even though there are unreachable references available for collection, these are not claimed by the collector. These are not strictly leaks but still, result in higher-than-usual memory usage.

#### What are memory leaks?

Just like the memory suggests, memory leaks are pieces of memory that the application have used in the past but is not needed any longer but has not yet been return back to the OS or the pool of free memory.

![](https://cdn-images-1.medium.com/max/1600/1*0B-dAUOH7NrcCDP6GhKHQw.jpeg)

Programming languages favor different ways of managing memory. However, whether a certain piece of memory is used or not is actually an [undecidable problem](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#Release_when_the_memory_is_not_needed_anymore). In other words, only developers can make it clear whether a piece of memory can be returned to the operating system or not.

Certain programming languages provide features that help developers do this. Others expect developers to be completely explicit about when a piece of memory is unused. Wikipedia has good articles on [manual](https://en.wikipedia.org/wiki/Manual_memory_management) and [automatic](https://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29) memory management.

#### The four types of common JavaScript leaks

#### 1: Global variables

JavaScript handles undeclared variables in an interesting way: when a undeclared variable is referenced, a new variable gets created in the _global_ object. In a browser, the global object would be window, which means that

```javascript
function foo(arg) {
  bar = "some text";
}
```

is the equivalent of:

```javascript
function foo(arg) {
  window.bar = "some text";
}
```

Let's say the purpose of bar is to only reference a variable in the foo function. A redundant global variable will be created, however, if you don't use var to declare it. In the above case, this won't cause much harm. You can surely imagine a more damaging scenario though.

You can also accidentally create a global variable using this:

```javascript
function foo() {
  this.var1 = "potential accidental global";
} // Foo called on its own, this points to the global object (window)
// rather than being undefined.
foo();
```

> You can avoid all this by adding ‘use strict'; at the beginning of your JavaScript file which would switch on a much stricter mode of parsing JavaScript which prevents the unexpected creation of global variables.

Unexpected globals is certainly an issue, however, more often than not your code would be infested with explicit global variables which by definition cannot be collected by the garbage collector. Special attention needs to be given to global variables used to temporarily store and process large bits of information. Use global variables to store data if you must but when you do, make sure to **assign it as null or reassign it** once you are done with it.

#### 2: Timers or callbacks that are forgotten

Let's take setInterval for example as it's often used in JavaScript.

Libraries which provide observers and other instruments that accept callbacks usually make sure all references to the callbacks become unreachable once their instances are unreachable too. Still, the code below is not a rare find:

```javascript
var serverData = loadData();
setInterval(function () {
  var renderer = document.getElementById("renderer");
  if (renderer) {
    renderer.innerHTML = JSON.stringify(serverData);
  }
}, 5000); //This will be executed every ~5 seconds.
```

The snippet above shows the consequences of using timers that reference nodes or data that's no longer needed.

The renderer object may be replaced or removed at some point which would make the block encapsulated by the interval handler redundant. If this happens, neither the handler, nor its dependencies would be collected as the interval would need to be stopped first (remember, it's still active). It all boils down to the fact that serverData which surely stores and processes loads of data will not be collected either.

When using observers, you need to make sure you make an explicit call to remove them once you are done with them (either the observer is not needed anymore, or the object will become unreachable).

Luckily, most modern browsers would do the job for you: they'll automatically collect the the observer handlers once the observed object becomes unreachable even if you forgot to remove the listener. In the past some browsers were unable to handle these cases (good old IE6).

Still, though, it's in line with best practices to remove the observers once the object becomes obsolete. See the following example:

```javascript
var element = document.getElementById("launch-button");
var counter = 0;
function onClick(event) {
  counter++;
  element.innerHtml = "text " + counter;
}

element.addEventListener("click", onClick);

// Do stuff

element.removeEventListener("click", onClick);
element.parentNode.removeChild(element);
// Now when element goes out of scope,
// both element and onClick will be collected even in old browsers // that don't handle cycles well.
```

You no longer need to call removeEventListener before making a node unreachable as modern browsers support garbage collectors that can detect these cycles and handle them appropriately.

If you leverage the jQuery APIs (other libraries and frameworks support this too) you can also have the listeners removed before a node is made obsolete. The library would also make sure there are no memory leaks even when the application is running under older browser versions.

3: Closures

A key aspect of JavaScript development are closures: an inner function that has access to the outer (enclosing) function's variables. Due to the implementation details of the JavaScript runtime, it is possible to leak memory in the following way:

```javascript
var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing)
      // a reference to 'originalThing'
      console.log("hi");
  };

  theThing = {
    longStr: new Array(1000000).join("*"),
    someMethod: function () {
      console.log("message");
    },
  };
};
setInterval(replaceThing, 1000);
```

Once replaceThing is called, theThing gets a new object which consists of a big array and a new closure (someMethod). Yet, originalThing is referenced by a closure that's held by the unused variable (which is theThing variable from the previous call to replaceThing). The thing to remember is that **once a scope for closures is created for closures in the same parent scope, the scope is shared.**

In this case, the scope created for the closure someMethod is shared with unused. unused has a reference to originalThing. Even though unused is never used, someMethod can be used through theThing outside of the scope of replaceThing (e.g. somewhere globally). And as someMethod shares the closure scope with unused, the reference unused has to originalThing forces it to stay active (the whole shared scope between the two closures). This prevents its collection.

In the above example, the scope created for the closure someMethod is shared with unused, while unused references originalThing. someMethod can be used through theThing outside of the replaceThing scope, despite the fact that unused is never used. The fact that unused references originalThing requires that it remains active since someMethod shares the closure scope with unused.

All this can result in a considerable memory leak. You can expect to see a spike in memory usage when the above snippet is run over and over again. Its size won't shrink when the garbage collector runs. A linked list of closures is created (its root is theThing variable in this case), and each the closure scopes carries forward an indirect reference to the big array.

This issue was found by the Meteor team and [they have a great article](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156) that describes the issue in great detail.

#### 4: Out of DOM references

There are cases in which developers store DOM nodes inside data structures. Suppose you want to rapidly update the contents of several rows in a table. If you store a reference to each DOM row in a dictionary or an array, there will be two references to the same DOM element: one in the DOM tree and another in the dictionary. If you decide to get rid of these rows, you need to remember to make both references unreachable.

```javascript
var elements = {
  button: document.getElementById("button"),
  image: document.getElementById("image"),
};
function doStuff() {
  elements.image.src = "http://example.com/image_name.png";
}

function removeImage() {
  // The image is a direct child of the body element.
  document.body.removeChild(document.getElementById("image"));
  // At this point, we still have a reference to #button in the
  //global elements object. In other words, the button element is
  //still in memory and cannot be collected by the GC.
}
```

There's an additional consideration that has to be taken into account when it comes to references to inner or leaf nodes inside a DOM tree. If you keep a reference to a table cell (a `<td>` tag) in your code and decide to remove the table from the DOM yet keep the reference to that particular cell, you can expect a major memory leak to follow. You might think that the garbage collector would free up everything but that cell. This will not be the case, however. Since the cell is a child node of the table and children keep references to their parents, **this single reference to the table cell would keep the whole table in memory**.

We at [SessionStack](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=Post-3-v8-outro) try to follow these best practices in writing code that handles memory allocation properly, and here's why:

Once you integrate SessionStack into your production web app, it starts recording everything: all DOM changes, user interactions, JavaScript exceptions, stack traces, failed network requests, debug messages, etc.
With SessionStack, you replay issues in your web apps as videos and see everything that happened to your user. And all of this has to take place with no performance impact for your web app.
Since the user can reload the page or navigate your app, all observers, interceptors, variable allocations, etc. have to be handled properly, so they don't cause any memory leaks or don't increase the memory consumption of the web app in which we are integrated.

There is a free plan so you can [give it a try now](https://www.sessionstack.com/?utm_source=medium&utm_medium=blog&utm_content=Post-3-v8-getStarted).

![](https://cdn-images-1.medium.com/max/1600/1*kEQmoMuNBDfZKNSBh0tvRA.png)

#### Resources

- [http://www-bcf.usc.edu/~dkempe/CS104/08-29.pdf](http://www-bcf.usc.edu/~dkempe/CS104/08-29.pdf)
- [https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156](https://blog.meteor.com/an-interesting-kind-of-javascript-memory-leak-8b47d2e7f156)
- [http://www.nodesimplified.com/2017/08/javascript-memory-management-and.html](http://www.nodesimplified.com/2017/08/javascript-memory-management-and.html)
- [https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/](https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/)
]]></description>
            <link>https://hungvn.com/blog/cach-hoat-dong-cua-javascript-quan-ly-bo-nho-4-cach-xu-ly-memory-leaks-thong-dung</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-hoat-dong-cua-javascript-quan-ly-bo-nho-4-cach-xu-ly-memory-leaks-thong-dung</guid>
            <pubDate>Mon, 13 Nov 2017 23:26:26 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giải thích React Lifecycle - componentDidMakeSense]]></title>
            <description><![CDATA[
## Learn the React lifecycle methods and when/how to use them

![](https://cdn-images-1.medium.com/max/1600/1*u8hTumGAPQMYZIvfgQMfPA.jpeg)

React is incredible because it allows you to build your UI using a declarative API. You tell React what you want the interface to look like, and it handles the rest.

As users interact with the application, the state changes which causes updates to the DOM. React provides a set of methods to seamlessly intercept the changes at any point during the updates and take control of the UI. The component lifecycle is typically one of the final pieces to truly mastering React, and this article will ensure that you have a firm grasp.

The lifecycle of a component can be defined as the time from when the component is first being inserted into the DOM, the entire time the component is in the DOM, and the point when the component is being removed from the DOM. There is a unique lifecycle for every React component in your code.

### [Check out gitconnected >](https://gitconnected.com)

_The community and network for developers and software engineers._

#### Overview of the lifecycle

The lifecycle methods are hooks to allow you to read state changes and control UI updates. The lifecycle can be broken down into 3 categories:

1.  **Mounting:** The component is being added to the DOM.
2.  **Updates:** The component receives changes props or state and is called when the component is being re-rendered.
3.  **Unmounting:** The component is being removed from the DOM.

The lifecycle methods provide entry points to take over any of these steps. Any method that begins with componentWill means you access it before the event occurs and any method prepended with componentDid means you capture it after the event occurs.

![](https://cdn-images-1.medium.com/max/1600/1*EjHABzqbwHBPBP_xPRP_4A.png)

#### Mounting

- constructor()
- componentWillMount()
- render()
- componentDidMount()

#### Updating

- componentWillReceiveProps()
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()

#### Unmounting

- componentWillUnmount()

### constructor

This method is called when your component is being created and before mounting (being added to the DOM). Its primary use is to initialize state and .bind(this) for the component’s methods. If you do neither of these, then there is no need for a constructor.

<Gist id="e6877a12b3da2c62116d78816b680eaf" />

### componentWillMount

This method is executed right before a component is added to the DOM / render(). It is generally recommended that you use the constructor, but this method is still included in the API mostly for backwards compatibility.

You should avoid calling any functions that cause side effects in this method as setState won’t trigger a change and there is no DOM to interact with.

_Note that this is also the only lifecycle method called on the server._

### componentDidMount

Your component has now been rendered and exists in the DOM. This is the point when you should initiate AJAX requests, add event listeners, and perform any set up that requires a DOM. Calling setState during this method or any time after will cause a re-render.

<Gist id="a85dc866528ba30dbec1becfd9d8fa0f" />

### componentWillReceiveProps

When your component receives new props from its parent, componentWillReceiveProps(nextProps) is triggered. This is a great time to check if there are changes in the incoming props when compared to your current props and trigger a state change based on the new values. A common use-case for this is resetting state based on a change.

<Gist id="7a6e5de3b54d65b89d5ce0a51fbdd8eb" />

### shouldComponentUpdate

This method exists purely for performance improvements. Renders and [reconciliations](https://reactjs.org/docs/reconciliation.html) are expensive in React. shouldComponentUpdate(nextProps, nextState) provides the developer the ability to return a boolean true/false from this method which controls whether React should perform the reconciliation operations and DOM updates.

The default behavior is for React to render every update, which works in most cases. If shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and componentDidUpdate() will not be invoked.

<Gist id="13688d13d0cf500438011780c76901eb" />

### componentWillUpdate

React invokes this method immediately before rendering when new props or state are being received. There is not much use for componentWillUpdate(nextProps, nextState) and should probably be avoided (similar to componentWillMount). You should not do anything that would change the state at this point — use componentWillReceiveProps if you need to do anything before a render.

_Note that this method is not called on the initial render._

### componentDidUpdate

Immediately after React builds you a shiny new UI, componentDidUpdate(prevProps, prevState) is invoked. This is a great time to interact with the DOM or instantiate a new network request based on what the new interface should look like.

### componentWillUnmount

Your component had a great life and now it’s time for it to leave the UI. This is the moment to clean up everything that was associated with adding and maintaining your component while it was living on the UI.

<Gist id="c3fdd539a7d1abe0d695c7a25cd51af7" />

### BONUS: componentDidCatch

componentDidCatch(error, info) is a new lifecycle that was added in React 16\. React was notorious for crashing the an entire application if a JavaScript error was thrown inside the React app. It corrupted React’s internal state which blew up the app and yielded cryptic error messages. componentDidCatch solves this by catching any JavaScript error occurring in a component’s tree for the children of the component that implements the method. It is able to capture the error and display a fallback UI.

<Gist id="8728583fd2985bd0cab1dfa403ba49ec" />
]]></description>
            <link>https://hungvn.com/blog/giai-thich-react-lifecycle-componentdidmakesense</link>
            <guid isPermaLink="true">https://hungvn.com/blog/giai-thich-react-lifecycle-componentdidmakesense</guid>
            <pubDate>Sat, 04 Nov 2017 23:42:53 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Hướng dẫn xây dựng ứng dụng React Redux CRUD]]></title>
            <description><![CDATA[
Building a single-page CRUD app using [React](https://facebook.github.io/react/) and [Redux](https://github.com/reactjs/) can be challenging because you’ll have to deal w/ new techniques and terms like “Reducers”, “Actions”, “Middlewares”, “Stores” and so on.

_Perhaps the trickiest part is making async requests and handling responses._ While there are many examples, _there is no well established pattern for making async requests and handling responses in Redux apps(just yet)_.

**_In this blog I’ll provide a general approach on how to build a Blog app that has 3 pages and show navigate b/w them._**

**_Further, I’ll also establish a pattern for making async requests and handling four async states: “loading”, “success”, “error” and “success-and-navigate”._**

> **Source code:** [https://github.com/rajaraodv/react-redux-blog](https://github.com/rajaraodv/react-redux-blog)

Let’s get started.

### STEP 1 — Write Detailed Mocks For Each Page And Phases.

In our app we have 3 pages: An **Index** page that shows a list of Posts, a **Post details** page and a **New Post** page.

Each page has “Success”, “Loading” and “Error” **phases** because they all make AJAX calls to load/delete posts, so we need to mock those things as well.

#### 1.1 Success Phase — Detailed Mocks when things are working

> Note: You can click on the pictures to Zoom and read

![](https://cdn-images-1.medium.com/max/1600/1*W9EVx20lNtyHafutHeG7ig.png)

#### 1.2 Loading Phase — Detailed Mocks when they are loading

![](https://cdn-images-1.medium.com/max/1600/1*yI0Hfav100ILspf99x_9Eg.png)

#### 1.3 Error Phase — Detailed Mocks when there is an Error

![](https://cdn-images-1.medium.com/max/1600/1*dcubqLNT9nGN3an82P4k7w.png)

### STEP 2 — Divide Each Page Into Components

Look at all the phases of each page and _roughly_ divide each page into components based on “**purpose**” and based on **physical** location.

This helps you identify reusable components across different pages and also any additional ones in a specific phase. For example, you may need a “Spinner” or an “Error” component for different phases.

> Note: this doesn’t need to be perfect. You can make changes later on.

![](https://cdn-images-1.medium.com/max/1600/1*NI2eOJmFrA9WTphppbTUgQ.png)

#### 2.1 — Success Phase: Divide Each Page Into Components

1.  **Index page:** 1\. Shows list of posts, 2\. Allows navigating to Post form page to create new post. So we end up w/ **PostsList** and **Header** components.
2.  **Post details page:** 1\. Shows details of the post, 2\. Allows navigating back to Index page 3\. Index page. So we end up with **PostDetails** and **Header** components.

3\. **New Post page:** 1\. Allows creating posts and 2\. allows navigating back to Index. Again we end up with **PostForm** and **Header** component.

Notice that we can reuse **Header** across all 3 pages because of the **physical** location. So we end up with four components (instead of 6): **1\. PostsList, 2\. PostDetails 3\. PostForm and 4\. Header components.**

#### 2.2 — Loading Phase: Divide Each Page Into Components

If you look at the mock, we are simply displaying “loading..” text in each page and not using some fancy spinner or “toast”. So we don’t have any more components.

#### 2.3 — Error Phase: Divide Each Page Into Components

If you look at the mock, we are simply throwing an alert popup and not using any custom modals. So we don’t have any more components.

So net-net, we have 4 components (**1\. PostsList, 2\. PostDetails 3\. PostForm and 4\. Header)**

### Redux Terms:

#### Redux Terms — “Actions” And “States”

**_Every component does two things:_** 1\. Listen to the user and server events and send them to JS functions. In Redux, events are represented as a JSON object called “Actions”.

```javascript
{"type": "FETCH_POST", "id": 1234} // <-- Action
```

2\. Render DOM based on some data. This data is called a“**state**”, which is also a JSON object.

```javascript
{"post": {"id": 1234, "title": "My Redux Post"}} // <-- state
```

#### Redux Terms — “Action Creators”

These are functions that listen to DOM or server events and return formal JSON “Action” object.

```javascript
function fetchPost(id) {
  return {
    type: FETCH_POST,
    result: makeServerRequest("http://postsServer.com/api/id"),
  };
}
```

> See [Action Creators](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/actions/) for our app.

#### Redux Terms — “Dispatching an Action”

Redux provides a function called “**dispatch**” which allows us to pass the “Action” JSON object to all other components. Dispatching an Action means simply calling the dispatch function w/ the action JSON object.

```javascript
//Call the "Action Creator" w/ post's id and then use it's return //value (Action JSON object) to finally dispatch it to "reducers"dispatch(fetchPost(id)) or dispatch({type:"FETCH_POST", id:1234})
```

> The components calls Action creators to receive Actions and then dispatches the actions. Redux then send the actions to “Reducers”

#### Redux Terms — “Reducers”

**Reducers are functions that take an Action and the current state that was sent to them via “dispatch”, apply action to the current state and return a new state**. And Redux re-renders all components whenever there is a new state.

```javascript
//If the action is FETCH_POST_SUCCESS, return a new "activePost" //state w/ new post)
case FETCH_POST_SUCCESS:
 return {activePost: {post: action.payload.data, error:null, loading: false}};
```

> See Reducers “[reducer_posts.js](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/reducers/reducer_posts.js)” and main “[index.js](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/reducers/index.js)” (this combines multiple reducers into one)

> **OK, before we go ahead to step 3, let’s understand how to deal with Async Actions because every page makes AJAX calls.**

### **PATTERN: Dealing With Async Actions**

If component is loading an object(e.g. list of Posts) via AJAX call to the server, that object’s state should keep track of all the potential states. Initial state for such objects should look like: `{**_objName: {obj:null, loading: false, error:null}}._**`

Further, such components should dispatch up to 4 actions such as “**FETCH_OBJ**”(for loading), “**FETCH_OBJ_SUCCESS**”, “**FETCH_OBJ_FAILURE**” and “**OBJ_RESET**”(to cleanup dirty previous state).

For example, if we are loading list of posts..

> Note: You can click on the pictures to zoom and read

![](https://cdn-images-1.medium.com/max/1600/1*BvyBVTs4GmOf2zULvnGaTg.png)

**Initial State:** Initial state should look like,

```javascript
{postsList:{posts:[], loading:false, error:null}}
```

**Actions:**

1.  **FETCH_OBJ** — Dispatch this to make the server request and also let other components know we are **loading**. This helps current/other components show “loading” or hide or do something.

```javascript
dispatch({“type”: “FETCH_POSTS”, loading: true})
```

Once Redux gets this and passes it through reducers, the new state will look something like:

```javascript
{postList: {posts:null, error: null, loading: true}}
```

2\. **FETCH_OBJ_SUCCESS**: Dispatch this when you get successful response. This is to show the actual data and also to cancel “loading”

```javascript
dispatch({"type": "FETCH_POSTS_SUCCESS", "posts":[post1, post2])
```

Once Redux gets this and passes it through reducers, the new state will look something like:

```javascript
{postsList:{posts:[post1, post2], error:null, loading: false}}
```

3.**FETCH_OBJ_FAILURE**: Dispatch this when you get a failed response. This is to show some error message and also to cancel “loading”.

```javascript
dispatch({ type: "FETCH_POSTS_FAILURE", error: "Error message" });
```

Once Redux gets this and passes it through reducers, the new state will look something like:

```javascript
{postList:{posts:null, error:{msg: "Error msg"}, loading: false}}
```

4.**RESET_OBJ**: Dispatch this to reset the component’s state after success/failure. **This is optional but can be useful when you want to reuse a “dirty” component from previous AJAX request.**

```javascript
dispatch({
  type: "RESET_POST",
  loading: false,
  post: null,
  error: "Error message",
});
```

Once Redux gets this and passes it through reducers, the new state will look something like:

```javascript
{postList:{post:null, error:null, loading: false}}
```

### STEP 3 — List State and Actions For Each Component (AND For Each Phase)

Take a look at each component one by one and each phase and list of state and actions.

We have 4 components: **1\. PostsList, 2\. PostDetails 3\. PostForm and 4\. Header components.**

#### 3.1 PostList Component — List State And Actions

![](https://cdn-images-1.medium.com/max/1600/1*SSoWLNAOzBkxK-4T2HuzPQ.png)

**States:**

List out various data that may change the display of the component in all phases of the component.

1.  Shows list of Posts. Let’s call the state as “**posts**” (an array).
2.  Shows “Loading..”, if it’s in the processing fetching the posts. Let’s call this state “**loading**”(boolean)
3.  Shows “Error” if there is an error. Let’s call this state as “**error**”(null or error info).

Since all the above are related to PostList, let’s put them in a single state object called **postList.**

```javascript
{ postsList: {posts: [], error:null, loading: false} //initial state
```

**Actions:**

This component makes a “AJAX” call to load posts, so we’ll use the above mentioned pattern and create 4 actions.

1.Asks server for list of posts. Let’s call this action as: “FETCH_POSTS”.

```javascript
export function fetchPosts() {
  const request = axios.get(`${ROOT_URL}/posts`);
  return {
    type: FETCH_POSTS,
    payload: request,
  };
}
```

2.Tells every component that it received posts (success case). Let’s call this “FETCH_POSTS_SUCCESS”

```javascript
export function fetchPostsSuccess(posts) {
  return {
    type: FETCH_POSTS_SUCCESS,
    payload: posts,
  };
}
```

3.Tells every component that there was an error(failure case). Let’s call this “FETCH_POSTS_FAILURE”

```javascript
export function fetchPostsFailure(error) {
  return {
    type: FETCH_POSTS_FAILURE,
    payload: error,
  };
}
```

4\. Resetting data is not required because this is the 1st page (you’ll see how this is useful in other 2 pages)

#### 3.2 PostDetails Component — List State And Actions

> Note: You can click on the pictures to zoom and read

![](https://cdn-images-1.medium.com/max/1600/1*qHMPcz-dVKe7ai1z3Koecg.png)

#### 3.3 PostForm Component — State And Actions

![](https://cdn-images-1.medium.com/max/1600/1*0jws-QutuczHQDwxTwAM7g.png)

#### 3.4 Header Component — List State And Actions

![](https://cdn-images-1.medium.com/max/1600/1*tzojxjqL59C7Urs9wwPmDw.png)

### STEP 4 — Create Action Creators For Each Action

We have a total of **12 actions(4 actions x 3 pages)**, create action creators for each one. Please see the [source code here](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/actions/index.js).

```javascript
//Example Action creators...
export function fetchPosts() {
 const request = axios.get(`${ROOT_URL}/posts`);

return {
 type: FETCH_POSTS,
 payload: request
 };
}
export function fetchPostsSuccess(posts) {
 return {
 type: FETCH_POSTS_SUCCESS,
 payload: posts
 };
}
...
```

### Redux Term: “Reducers”

Reducers are functions that take “state” from Redux and “action” JSON object and returns a new “state” to be stored back in Redux.

1\. Reducer functions are called by the “Container” containers when there is a user or server action.
2\. If the reducer changes the state, Redux passes the new state to each component and React re-renders each component

The below function takes the current "postsList" inside "...state" and merges new "postList" and creates a **new** state(json), if the action is "FECTH_POSTS_SUCCESS"

```javascript
case FETCH_POSTS_SUCCESS:
 return { …state, postsList: {posts: action.payload, error:null, loading: false} };
```

### STEP 5 — Write Reducers For Each Action

We have 12 actions, we need to write reducers for each one of them.

Please look at the [source code for details here](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/reducers/reducer_posts.js).

### Redux Term: “Presentational” and “Container” Components

Keeping React and Redux logic inside each component can make it messy, so Redux recommends creating a dummy presentation only component called “Presentational” component and a parent wrapper component called “Container” component that deals w/ Redux, dispatch “Actions” and more.

The parent Container then passes the data to the presentational component, handle events, deal with React on behalf of Presentational component.

![](https://cdn-images-1.medium.com/max/1600/1*8naKQS5q3GXlqzHQLMNJ-Q.png)

> **_Legend_**: Yellow dotted lines = “Presentational” components. Black dotted lines = “Container” components.

### STEP 6 — Implement Every Presentational Component

We have 4 components: **PostsList, PostDetails, PostForm and Header**. Let’s create presentational components for each one.

#### 6.1 Implement Presentational Component — PostsList

> Note: You can click on the pictures to zoom and read

![](https://cdn-images-1.medium.com/max/1600/1*wgv9ZrBoTL9ujxUnrnIvlQ.png)

#### 6.2 Implement Presentational Component — PostDetails

![](https://cdn-images-1.medium.com/max/1600/1*7hwsBN_-1KqNv7xR-hC9YQ.png)

#### 6.3 Implement Presentational Component — PostForm

![](https://cdn-images-1.medium.com/max/1600/1*2w9eQMK__FuESaDWlziyaQ.png)

> Note: In the actual code, I am using the awesome [redux-form](https://github.com/erikras/redux-form) library for form-validation. I’ll blog about it in a different post.

#### 6.4 Implement Presentational Component — Header

![](https://cdn-images-1.medium.com/max/1600/1*Zpw_soSAlhN_4POpyPor6w.png)

> Note: You can click on the pictures to zoom and read

### STEP 7 — Create Container Component For Some/All Presentational Component

We have 4 components: PostList, PostDetails, PostForm and Header. Let’s create container components for each one.

#### 7.1 Create Container Component — PostsListContainer

![](https://cdn-images-1.medium.com/max/1600/1*paowu40xgHA8l4zHJyG7aQ.png)

#### 7.2 Create Container Component — PostDetailsContainer

![](https://cdn-images-1.medium.com/max/1600/1*mxsh2xZYnVbFJvY7hG73eg.png)

#### 7.3 Create Container Component — PostFormContainer

![](https://cdn-images-1.medium.com/max/1600/1*KrPV7Ssxu1dPuwAQ4ilTyQ.png)

#### 7.4 Create Container Component — HeaderContainer

![](https://cdn-images-1.medium.com/max/1600/1*_NkFxHOJHQEOy_yuf04aXQ.png)

### STEP 8 — Finally Bring Them All Together

Below code is a simplified version of wiring everything together. Please see source code of the main [index.js](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/index.js) and [reducers.js](https://github.com/rajaraodv/react-redux-blog/blob/master/public/src/reducers.js) to get started.

```javascript
import React from 'react'; <-- Main React lib
import ReactDOM from 'react-dom'; <-- Main React DOM lib
import { Provider } from 'react-redux';<-- Injects Redux to comps
import { createStore, applyMiddleware } from 'redux';<- Redux
import { Router, browserHistory } from 'react-router';<- Navigation
import reducers from './reducers'; <- Import reducers
import promise from 'redux-promise';
//Configure middleware w/ redux-promise for AJAX requests
const createStoreWithMiddleware = applyMiddleware(
  promise
)(createStore);

const store = createStoreWithMiddleware(reducers);
ReactDOM.render(
  <Provider store={store}> <- Inject global redux state to comps
    <Router history={browserHistory}>
       <Route path=”/” component={App}> <- Wrapper for all pages
         <IndexRoute component={PostsIndex} /> <-wrapper Index page
         <Route path=”posts/new” component={PostsNew} /> <- New page
         <Route path=”posts/:id” component={PostsShow} /> <-Details
       </Route>
    </Router>
</Provider>
  , document.getElementById('body'));
```

That’s it for now!
]]></description>
            <link>https://hungvn.com/blog/huong-dan-xay-dung-ung-dung-react-redux-crud</link>
            <guid isPermaLink="true">https://hungvn.com/blog/huong-dan-xay-dung-ung-dung-react-redux-crud</guid>
            <pubDate>Sat, 04 Nov 2017 23:38:19 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Làm thế nào để kết hợp NodeJS Back End với ReactJS Front End]]></title>
            <description><![CDATA[
---

In this post, I want to show how you can build the front and back end of a website using NodeJS for the back end. We’ll use node to create endpoints, and set up a database in JSON format. Then, we’ll create a front end application using React that will post to the database, and also fetch data from it.

For this example, I’ll be making a guestbook, where users can submit their names and leave messages. Because users won’t need to log in, or retrieve any data, I won’t need to store anything in a session. Here’s the way this will likely work:

![](https://cdn-images-1.medium.com/max/1600/1*1jc_PHELP7D04nUsZb3zmQ.png)

Basically, we will have this all one one page, with a form for submitting a message, alongside the actual guestbook. To make this work we’’ll start by creating the endpoints for our POST and GET requests. We’ll set up our database, deploy it, so that we can create a React app, and pull data from the online API.

Here’s the order in which I like to do things. You may prefer to work differently. This process makes sense to me, because each step builds on the step before it. During this tutorial, I’ll go through each step in more detail.

![](https://cdn-images-1.medium.com/max/1600/1*AzwpcG8i0GA3mxmHMenLeQ.png)

To see how the finished project could work, here’s a link to my project:

[http://ethan.jarrell.webdeveloper.surge.sh/GuestBook](http://ethan.jarrell.webdeveloper.surge.sh/GuestBook)

### STEP 1 -

Our database collection will contain 2 items:

1.  The name of the user
2.  The message the user writes

If you haven’t already done so, go ahead and install MongoDB, and get it running on port 27017\. Then, on the command line, we’ll create the database.

We’ll call our database signatures. And the collection, guest_signatures.

```javascript
> Show dbs
> Use signatures
switched to db signatures
> show collections
> db.createCollection(guest_signatures)
```

Now that we have that set up, we can switch to the text editor, and create the models for the database.

### STEP 2 -

Use the command line to start a new express app. Make the new directory, and then use npm init to create the app. This will automatically create your pkg.JSON file.

Since this will be a very basic app, we’ll only need 2 other files in our express app. One for our routes. I like to include all my dependencies in this file as well. Then our second fill will be for our models/schema. We’ll tackle the model file first. It should look something like this:

```javascript
const mongoose = require("mongoose");
let Schema = mongoose.Schema;

const signatureSchema = new Schema({
  guestSignature: {
    type: mongoose.Schema.Types.Mixed,
    required: true,
  },
  message: {
    type: mongoose.Schema.Types.Mixed,
    required: true,
  },
});

const Signature = mongoose.model("Signature", signatureSchema);
module.exports = Signature;
```

### STEP 3 -

Before we create our endpoints here, let’s go ahead an list our dependencies at the top of our file. We don’t need too many.

```javascript
//====LIST DEPENDENCIES===//
const express = require("express");
const parseurl = require("parseurl");
const bodyParser = require("body-parser");
const path = require("path");
const expressValidator = require("express-validator");
const mongoose = require("mongoose");
const Signature = require("./models/signature.js");
const app = express();
const url = "mongodb://localhost:27017/signatures";
//=========================//
```

You don’t necessarily need to connect with mongoose, so feel free to use MongoClient, if you prefer that. We’re also using the Signature schema that we just created in the previous step.

Now, let’s create our endpoints. We only have one model, and we’re only going to read and write to it for now, so we’re only going to have 2 endpoints.

1.  Our root directory “/”, where we’ll redirect to our API
2.  Our api, we’ll call “/api/signatures, where we’ll read and write to.

At our API endpoint, we’ll have a GET and a POST. We’ll reference our models, using the find() and create() methods for GET and POST respectively. And our response will need to be in JSON format, so that we can easily access the data there from React later on. Here’s how those endpoints might look:

```javascript
//====ROOT DIRECTORY===//
app.get("/", function (req, res) {
  res.json("you did it");
});

//==========================//

//====GET ALL SIGNATURES===//

app.get("/api/signatures", function (req, res) {
  Signature.find({}).then(eachOne => {
    res.json(eachOne);
  });
});

//==========================//

//====POST NEW SIGNATURE===//

app.post("/api/signatures", function (req, res) {
  Signature.create({
    guestSignature: req.body.SignatureOfGuest,
    message: req.body.MessageofGuest,
  }).then(signature => {
    res.json(signature);
  });
});
//==========================//
```

The only thing I didn’t really mention was the req.body.SignatureOfGuest and req.body.MessageofGuest. Everything else in this section refers to something we’ve already created, like our database, collections and models. This refers to the name of the field that we’ll use in our React App, Our input will have to use the names SignatureOfGuest and MessageofGuest, so we’ll need to remember that.

### STEP 4 -

Now, we’ll want to connect to our local database from out text editor. If you remember, we had this constant in our list:

```javascript
const url = "mongodb://localhost:27017/signatures";
```

We’ll write a function using this constant to connect to our local database.

```javascript
//====MONGOOSE CONNECT===//
mongoose.connect(url, function (err, db) {
  if (err) {
    console.log("Unable to connect to the mongoDB server. Error:", err);
  } else {
    console.log("Connection established to", url);
  }
});
//==========================//
```

In order to make sure everything is working properly, we’ll also need to add an app.listen at the end of our file.

At this point, it’s a good idea to pause, and make sure the endpoints and local connection works. You can do that by using Postman to make GET and POST requests. If the endpoints or connections don’t work, you should be able to diagnose the problem here based on the error messages you receive. If everything is working, it should allow you to appropriately read and write to the database.

Once everything is working, it’s time to set up our account on Heroku and Mlab.

### STEP 5-

Sign up for a Heroku account [here](https://signup.heroku.com/). And create an mLab account [here](https://mlab.com/signup/).

### STEP 6 -

1.  After creating your mLab account, click on the Create New button and select a Single node sandbox. There are paid options as well, but the sandbox has plenty of space for getting started. Give your database a name. Since my local database is signatures, I’m using the same name for my mLab database.
2.  Now that you have your database created, you can start a new collection from here.
3.  You will also need to add a User or Users who can access your database. Without doing this step, and adding yourself as a User with access, authentication will always fail when you try to deploy it.

Now your database is running on mLab. When you click on the database, you should see some information at the top, telling you how to integrate the connection. It should look something like this:

```javascript
mongodb://<dbuser>:<dbpassword>[@ds7](http://twitter.com/ds129024 "Twitter profile for @ds129024")9234.mlab.com:9234/signatures
```

The actual url of the database will just have the username and password replaced with your username and password.

Now let’s head back to our text editor. We currently have the database running locally at this location:

```javascript
const url = "mongodb://localhost:27017/signatures";
```

To change it, so that we are connected to mLab, simply update the url variable with the information from mLab. It should look something like this:

```javascript
const url = "mongodb://username:password@ds79234.mlab.com:9234/signatures";
```

However, you’ll likely be putting this on github, or another public place. You don’t want your mlab username and password in a public sphere where anyone can see it. To fix that, we’ll set an environment variable on the command line, and then update our url variable one more time in the text editor. On the command line, use this command:

```javascript
export MONGOLAB_URI="mongodb://username:password@ds79234.mlab.com:9234/signatures';
```

Of course, replacing it with your own username, password, numbers and database name. Now, back in our text editor, we will change our url variable to the following:

```javascript
const url = process.env.MONGOLAB_URI;
```

We’ll also want to change our app.listen to reflect the new port. It could look like this:

```javascript
app.listen(process.env.PORT || 3000);
console.log("starting applicaiton.  Good job!");
```

This way, it will try to run from mongolab, but if it can’t make the connection, it will still listen on port 3000 by default. This will also allow you to run the app locally or from mlab, in case you want to test changes on the local version.

The final step in making the connection is deploying your code to your Heroku App. to do this, you can use the following code from the command line:

```javascript
heroku config:set MONGOLAB_URI=mongodb://username:password@ds79234.mlab.com:9234/signatures
```

Your app should be successfully deployed on heroku, and you can open it from there now. If you are getting errors, double check to make sure it’s running locally. If so, then it’s probably an error along the way in the connection.

In these last two steps, there’s quite a bit of repetitive code. I’m going to outline the high level code here.

### STEP 7 -

Use ‘create-react-app’ from the command line to create a new react app.

### STEP 8 -

Now, we’ll want to create a form, to allow for user input. Here’s how we do that.

1.  In a new component, we’ll create a new class.

```javascript
class GuestBook extends Component
```

2\. We’ll use a constructor and super method to pass props down.

```javascript
constructor(props) {
    super(props);
```

3\. Use the this keyword to handle the name and message of guest, and bind it to (this).

```javascript
this.handleSignatureOfGuest = this.handleSignatureOfGuest.bind(this);
this.handleMessageofGuest = this.handleMessageofGuest.bind(this);
```

4\. Set the state of the name and message of guest to an empty string.

```javascript
this.state = {
  SignatureOfGuest: "",
  MessageofGuest: "",
};
```

5\. Listen for an event on the state of both the name and message input.

```javascript
handleSignatureOfGuest(event) {
    this.setState({ SignatureOfGuest: event.target.value });
  }
  handleMessageofGuest(event) {
      this.setState({ MessageofGuest: event.target.value });
    }
```

6\. Create a function that changes the name and message to the value of the target input.

```javascript
addToGuestBook = event => {
    event.preventDefault();
    this.setState({
      SignatureOfGuest: event.target.value,
      MessageofGuest: event.target.value,
});
```

7\. I’m now using axios to post the input data to our database, which is on heroku.

```javascript
axios.post('<[your-heroku-url here>'](https://ancient-sea-87841.herokuapp.com/api/signatures%27), {
        SignatureOfGuest: this.state.SignatureOfGuest,
        MessageofGuest: this.state.MessageofGuest,
      })
    .then(response => {
      console.log(response, 'Signature added!');
    })
    .catch(err => {
      console.log(err, 'Signature not added, try again');
    });
```

8\. Then I’m resetting the state of the input to an empty string.

```javascript
this.setState({
      SignatureOfGuest: "",
      MessageofGuest: "",
    });
};
```

9\. Finally, we’ll make a render method, and return our page with the input fields. Inside the input of each field, we’ll give it an onChange, name, and value. the onChange will be set to the.handlemessage or this.handlename, for each field. The name of each field will be set to what we called it in our node app. The value will use state, and we’ll set that to this.state.message, and this.state.name.

```javascript
<input
           onChange={this.handleSignatureOfGuest}
           name="SignatureOfGuest"
           className="NameinputForm"
           value={this.state.SignatureOfGuest}
           placeholder="Enter your name"
            />
  <textarea
              onChange={this.handleMessageofGuest}
              name="MessageofGuest"
              className="MessageinputForm"
              value={this.state.MessageofGuest}
              placeholder="Type a message"
               />
```

10\. Then we’ll add a submit button, where we call the function from earlier.

```javascript
<button className="submitbuttonguestbook" type="submit" onClick={this.addToGuestBook}>
  Submit to Guestbook
  <i className="GuestBookButton2" aria-hidden="true" />
</button>
```

### STEP 9-

Now we’ll make another component where we’ll render the data that’s being stored in our database. Then we can export that component, and put it on our guestbook page.

Inside this component we’ll do the following:

1.  In a new component, we’ll create a new class.

```javascript
class GuestNames extends Component {
```

2\. We’ll use a constructor and super method to pass props down.

```javascript
constructor(props) {
    super(props);
```

3\. Use this.state to set the state of our guestbook messages to an empty string.

```javascript
this.state = {
  messages: "",
};
```

4\. Use a componentDidMount lifecycle method

```javascript
componentDidMount() {
```

5\. Inside that method we’ll use fetch and the url of our heroku api to fetch the information from the database.

```javascript
fetch('<your-heroku-url-goes-here>['](https://ancient-sea-87841.herokuapp.com/api/signatures%27))
    .then(results => {
      return results.json();
```

6\. We’ll map over the data, and return the data we want.

```javascript
data.map((msg) => {
        return(
          <div key={msg.results}>
            <h3 className="h3msg">{msg.message}</h3><h2 className="h2sig">-{msg.guestSignature}</h2>
          </div>
```

7\. Now we’ll use this.setState to set the state of the messages to the new state using the data we just fetched.

```javascript
this.setState({ messages: messages });
```

8\. Now we’ll create render mehod.

```javascript
render() {
```

9\. Inside the render method, we’ll create JSX elements to render our data inside the component. I’m using this.state.messages inside an `<h6>` tag.

```javascript
return (<div className="guestdataContainer">
          <h6>Guestbook Messages</h6>
          {this.state.messages}
        </div>
```

10\. Finally, we’ll export the component, so we can use it on other pages.

```javascript
export default GuestNames;
```

Again, if you have any questions feel free to reach out. Thanks!
]]></description>
            <link>https://hungvn.com/blog/lam-the-nao-de-ket-hop-nodejs-back-end-voi-reactjs-front-end</link>
            <guid isPermaLink="true">https://hungvn.com/blog/lam-the-nao-de-ket-hop-nodejs-back-end-voi-reactjs-front-end</guid>
            <pubDate>Sat, 04 Nov 2017 23:34:28 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Đi ăn và hiểu những điều cơ bản của Express.js]]></title>
            <description><![CDATA[
If you have ever visited a sit-down restaurant, then you can understand the basics of Express. But if you are just starting to build your first Node.js back end…you might be in for a bumpy ride.

Yes — it is certainly easier to learn Node if you have past experience with JavaScript. But the challenges you will face while building a back end are completely different than the ones you face while using JavaScript on the front end.

When I learned Node, I chose the hard way. I studied eBooks, written tutorials, and videos over and over until I finally understood **why** I was doing what I was doing.

There is an easier way. I am going to use a restaurant analogy to explain four key parts of your first Express app. [Express.js](https://expressjs.com/) is a popular framework for organizing your code, and I would recommend it for any beginner. I’ll explain further in a moment.

Here are the four key parts we will cover:

1.  The require statements
2.  Middleware
3.  Routing
4.  App.listen()/ Starting the server

In this analogy, you are a restaurant owner looking to hire a general manager — the person who creates all the processes and manages the place so that it runs smoothly and customers leave happy.

Here is a preview of what is next:

![](https://cdn-images-1.medium.com/max/2000/1*gWVqib20b1NNzB6vrM-U6w.png)

By the end, you will understand the functionality of every part of a basic Express app.

### Step 1: hiring the manager (require statements)

In this example, you are the restaurant owner. And you need to hire an expert to run the day-to-day operations of your new restaurant. You certainly aren’t an expert, and you can’t leave it to the waitstaff and kitchen to figure out.

If you want to run an efficient and safe restaurant, you need someone to keep your staff working at maximum efficiency. Express is the new manager.

The first part is pretty straightforward. Like with any other NPM package, you need to npm install the express module and then use a **require** statement to load the module.

![](https://cdn-images-1.medium.com/max/2000/1*VjyG-yoVn9aUYJ_cdN6RYA.png)

Unlike many other NPM packages, you also need to use this line:

```javascript
const app = express();
```

This is because you need a variable to hold your new Express application. Express is not a default part of Node.

### Step 2: making decisions at the restaurant (middleware)

Let’s take a step back here. What are some common routines that happen at restaurants? There are three that immediately jump into my head:

1.  Seating new customers
2.  Taking food orders
3.  Presenting the check at the end of the meal

For each one, there are a series of checks that you need to run before you can execute the action. For example, before you seat customers you need to know:

1.  Are they wearing a shirt and shoes (and pants)? Otherwise, they cannot be seated.
2.  If they want to sit at the bar, are they 21 years old (if you are in the United States)?

This ain’t a beach bar! Similarly, in your code, you will need to validate that requests have certain criteria before they can continue. For example, if a person tries to log in to your site:

1.  Do they have an account?
2.  Did they enter the correct password?

This is where the concept of **middleware** comes in. Middleware functions allow you to take action on any incoming request and modify it before sending back a response.

![](https://cdn-images-1.medium.com/max/1600/0*8HIzvtX-DA3C26uv.png)

In your restaurant, you need a series of rules to decide if you should seat incoming people or not. Let’s say a couple walks through your door. You have one rule before giving them a table: are they wearing a shirt and shoes?

![](https://cdn-images-1.medium.com/max/2000/1*Gqix0p7PBNJ5htTY3sT7OQ.png)

First, you start with [app.use()](http://expressjs.com/en/api.html#app.use). This means that these are simply rules that need to be applied for the routes coming up next. They are not a GET, POST, PUT or DELETE.

In line 4, you have an anonymous function with the parameters req, res and next. For the purposes of this code block, you are just inspecting the request (req) to see if it has shirt and shoes.

You also need to use the next() function at the end because you are simply validating clothing here. Later, in the routes, you will allow the guests to get an actual table.

In lines 5 and 6, you check if they have a shirt and shoes.

And in lines 7–9, you only proceed if they have both.

The code block above is missing one important thing: A **path**. This is the specific string included with the request. And since it is missing a path, it will run on every single request.

Can you imagine? When customers entered the restaurant… ordered food… asked for the check… employees would be forced to look up and down at them to make sure they were clothed! That is a quick way to go out of business.

![](https://cdn-images-1.medium.com/max/2000/1*fjZKIJYmTIxQmVMURYTW9g.png)

So, we change line 4 in the example above. Now, we will only run this code when a user requests along the ‘/table’ route.

The full explanation:

![](https://cdn-images-1.medium.com/max/2000/1*d1OPYjAlr6mUWtjtMRbk6g.png)

### Step 3: executing common routines (routing)

Let’s continue with the seating example. So far, we only know how to validate whether someone should be seated or not. But we do not actually know how to lead them to a table and sit them down.

This is where **routes** come in. Routes allow us to script specific actions based on the **path**. The options are GET, POST, PUT and DELETE, but we will focus on GET and POST for now.

In the context of a restaurant, we need to create a GET request in order to choose a specific table and seat the guests. GETs do not modify or add to your database. They just retrieve information based on specific parameters.

In this case, let’s say that you need to create a procedure to seat a party of two. The number 2 came from the customer **request.**

![](https://cdn-images-1.medium.com/max/2000/1*pGvgMABGA1xzrSL9EFGQmQ.png)

Okay, before I explain: Yes, this is only sending a message at the end. It has not actually found a specific table to seat the customer yet. I would need to search an array for an open table, have more of a back story…that is outside of the scope of this tutorial.

In line 12, we define the procedure for finding a table when a guest **requests** along the ‘/table’ **route**. Just like the middleware example above, we have request and response parameters available. It also has a **parameter**, amount. This is two, in this example.

In fact, everything after the function declaration in line 12 is technically **middleware** since it modifies a user request. You will see in the diagram at the end.

In line 13, we access the number of people in the party from the **parameters** of the request object. That is not declared anywhere since the request came from the user, and we do not have any front-end code. So here is what the request might look like if this was a real app:

```javascript
req = {
  params: {
    amount: 2;
  }
}
```

In line 13, our party variable accesses the amount **property** of the params **object** within the **request**.

Finally in line 14, we send a **response** back to the customer: we are looking for the appropriately sized table.

That is a lot at once. Here is a diagram:

![](https://cdn-images-1.medium.com/max/2000/1*k7DkIw1cheKYBwu_AC4SAA.png)

### Step 3.5: making your restaurant efficient (router)

Now you can trace the full path from request to response. But as your app grows in size, you will not want to code the rules for each route individually. You will find that some routes share the same rules, so you need to find a way to apply one set of rules to multiple routes.

In terms of seating, you can either seat your customers at the bar or at a table. Those have rules in common like shirt + shoes, but seating at the bar requires every member of the party to be 21.

And, in terms of serving customers, you will need to use a slightly different procedure for serving the appetizer, main course, and dinner. But, those three routes have plenty in common as well.

This is where the **router** comes in. The router lets you group your routes so that you can create common rules.

![](https://cdn-images-1.medium.com/max/2000/1*6Irrxz4EmHaPgVm0JRgVLg.png)

We need to create middleware to cover each of these cases. I will just cover the seating cases for now since it will overwrite the code above.

Here is the full code snippet:

![](https://cdn-images-1.medium.com/max/1600/1*Pih87WdfXU_PEXkcbsaAIw.png)

I am going to cover each part individually.

In line 4, we declare our router.

In lines 6 and 14, we now have seatingRouter.use() in place of app.use() to indicate that this **middleware** is only related to seatingRouter routes.

Finally, in line 21, we add more middleware to show that every seatingRouter route begins with ‘/seating’. So, if someone requested a seat at the bar, the full path would be ‘/seating/bar.’ This may feel a little out of order, since you might expect the path to be defined when you create the router in line 4\. That is normal!

Here is that in diagram form:

![](https://cdn-images-1.medium.com/max/1600/1*-1x9T6VvBCQihyzwqgnGIA.png)

And, when you add a GET route, it goes above the last statement where you assign routes to the router.

![](https://cdn-images-1.medium.com/max/2000/1*EPEUF9z94mMlCYXMB6HENA.png)

### Step 4: opening for business (ports)

Okay, last part. So far, you have hired a manager, defined what to do before accepting customer requests, and determined what to do with specific customer requests once they come in. Now, you just need to determine the address for the location where all this will happen.

Your server has **ports** that are kind of like the address for the restaurant itself.Since your server can handle many types of restaurants (or server-side scripts) at once, you need to tell it where each script should run.

![](https://cdn-images-1.medium.com/max/2000/1*xGoTkrNMLnwyh7zR2wbbVA.png)

In the example above, the port is 3000 and it is located on your computer. So if you type:

```javascript
[https://localhost:3000/](https://localhost:3000/)
```

into your browser, and you are running your Node app, the server knows to run the specific script. In this case, as soon as you enter the URL, you will log the message in the console and be able to use any of your **routes**. If the restaurant itself is your entire app, then it is now open for business at the address 3000.

![](https://cdn-images-1.medium.com/max/2000/1*kl9doAbsvsaQNJdFWhc2-Q.png)
]]></description>
            <link>https://hungvn.com/blog/di-an-va-hieu-nhung-dieu-co-ban-cua-express-js</link>
            <guid isPermaLink="true">https://hungvn.com/blog/di-an-va-hieu-nhung-dieu-co-ban-cua-express-js</guid>
            <pubDate>Sat, 04 Nov 2017 23:25:21 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Các nguyên tắc cơ bản của Redux]]></title>
            <description><![CDATA[
## Redux là gì và tại sao phải cần nó trong React/React Native

Tóm tắt React:

> Nguyên tắc một app React là dựa vào component. Mỗi component có state và props. Nếu state của một component thay đổi thì nó sẽ được render lại. Props để truyền data từ component cha sang component con

Vấn đề là khi ta muốn truyền props từ **2 component không phải cha-con** thì sẽ xảy ra vấn đề

Ví dụ sau, một app nhỏ chỉ có Main -> Parent -> Child như sau thì truyền props đơn giản

![](https://i2.wp.com/niviki.com/wp-content/uploads/2017/07/Screen-Shot-2017-07-03-at-13.59.05.png?resize=424%2C630)

Nhưng với app phức tạp hơn một tý, khi muốn truyền props giữa 2 component không phải cha-con thì rất phức tạp:

![](https://i0.wp.com/niviki.com/wp-content/uploads/2017/07/tai-sao-can-redux.png?resize=800%2C589)

Đó là lý do tại sao nên dùng Redux:

![](redux-article-3-03.svg)

Tóm lại cần một cơ chế để **quản lý state trong React/React Native.**

_Không phải cứ React/React Native là phải dùng Redux. Cũng không phải Redux chỉ được dùng trong React/React Native_

## Ngoài Redux ra thì còn cái nào để quản lý state nữa không?

Thực ra Redux dựa theo ý tưởng của Flux. Ngoài Redux ra bạn có thể dùng:

Mobx ( Cài này phổ biến chỉ sau Redux )

[Jumpsuit](https://github.com/jumpsuit/jumpsuit) ( đặt tên ngáo thật )

Nhưng [lập trình React Native](http://niviki.com/2017/02/tu-mo-react-native-khong-chi-la-hello-world/) thì nên dùng Redux với Mobx.

## 3 Nguyên tắc của Redux

Đáng lẽ ra mình sẽ viết bài “Tại sao cần Redux và cách dùng”. Nhưng để hiểu được tại sao và cách dùng thì nên hiểu nguyên tắc chính của nó, từ đó khi học chúng ta sẽ để ý những nguyên tắc này mà học theo. Nơron thần kinh trong não mới bắt đầu liên kết lại.

Cũng giống như bạn [học lập trình hướng đối tượng](http://niviki.com/khoa-hoc-lap-trinh-huong-doi-tuong-c-co-ban-den-nang-cao/) sẽ có 4 nguyên tắc: trừu tượng, đóng gói, kế thừa, đa hình vậy. Từ đó mới học class , object, properties, method, access modifier, khởi tạo, kế thừa, interface, vv

**Nguyên tắc này từ đâu? **Đương nhiên từ nhóm tạo ra nó rồi, một trong đó là [Dan Abramov](https://github.com/gaearon)

### Nguyên tắc 1: Store (Single Source of Truth)

Chỉ có một cây object trong một ứng dụng, và người ta đặt nó là store.
Ví dụ mình có viết một ứng dụng tìm việc làm đơn giản:

<YouTube id="9jzEULoVrn4" />

Thì sẽ được một store như sau:

- auth: dùng để quản lý đăng nhập
- jobs: danh sách job tải từ web service
- likedJobs: danh sách job đã thích

![3 nguyên tắc redux ](https://i2.wp.com/niviki.com/wp-content/uploads/2017/07/Screen-Shot-2017-07-03-at-10.37.33.png?resize=732%2C629)

### Nguyên tắc 2: Action (State is Read-Only)

Không update store trực tiếp được, muốn thay đổi cái store thì phải truyền action vào. Mà action nghe cao siêu vậy thôi, chứ nó [**chỉ là một object trong Javascript**](http://niviki.com/2017/06/hoc-javascript-2-name-value-pair-va-object/). Quy định duy nhất của của object này là **phải có type**. ( type thường là chuỗi string )
Ví dụ action đăng nhập Facebook thành công:

![](https://i1.wp.com/niviki.com/wp-content/uploads/2017/07/Screen-Shot-2017-07-03-at-10.43.23.png?resize=513%2C68)
Ví dụ action thích một công việc nào đó:

![](https://i0.wp.com/niviki.com/wp-content/uploads/2017/07/Screen-Shot-2017-07-03-at-10.44.51.png?resize=407%2C61)

### Nguyên tắc 3: Reducer (Changes are made with Pure Functions)

Sẽ có một cái hàm nhận cái action ở trên, rồi trả về state mới. Mà hàm này phải là **pure function.** Mà pure function là sao?

Cái pure function này viết cả bài cũng được. Nhưng đại ý chính là **pure function không gây side effects** như: thay đổi giá trị tham số, không gọi web service hay database trong hàm này.

![](https://i0.wp.com/niviki.com/wp-content/uploads/2017/07/reducer-la-gi.png?resize=500%2C400)

### Tóm tắt cách hoạt động:

Khi người dùng nhấn like một job  ( nhấn button like )  -> tạo action:

![](https://i0.wp.com/niviki.com/wp-content/uploads/2017/07/Screen-Shot-2017-07-03-at-10.44.51.png?resize=407%2C61)

Sau đó **Reducer là một cái hàm**, nó trả về state mới

![reducer là gì](https://i2.wp.com/niviki.com/wp-content/uploads/2017/07/Screen-Shot-2017-07-03-at-13.22.50.png?resize=593%2C381)

Sau đó ở _component_ nào muốn xài thì _liên hệ store_ để truy cập dữ liệu trong store.

### Bức tranh tổng quát của Redux

Hình này mới mô tả một chiều của dữ liệu: giữa action, reducer và store

![](https://i2.wp.com/niviki.com/wp-content/uploads/2017/07/redux-la-gi-2.png?resize=670%2C327)

Đây mới là hình đầy đủ:

![](https://i1.wp.com/niviki.com/wp-content/uploads/2017/07/redux-workflow.png?resize=541%2C295)

## Cách học Redux

Đương nhiên còn có nhiều phần chi tiết bên trong mình chưa đề cập đến như:

- **Action Creator**: dùng để tạo action, thao tác logic. Chúng cũng là những hàm bình thường nhưng sẽ trả về là action thôi chứ không có gì gê gớm.
- **createStore**: tạo store
- **applyMiddleware**: thành phần trung gian như lưu store offline ( local storage ), async action như tải data trên web service, vv
- **connect**, **mapStateToProps**: kết nối store với component, để component có thể xài được state trong store.

### Chia sẻ cách học Redux:

1.  Xem video hướng dẫn từ chính anh tạo ra Redux:
    [https://egghead.io/courses/getting-started-with-redux](https://egghead.io/courses/getting-started-with-redux)
2.  Lên youtube xem cách dùng redux trong một ứng dụng React/React Native để hiểu được những phần còn thiếu ở trên cũng như cách tổ chức code trong ứng dụng.
3.  [Đọc document của Redux](http://niviki.com/2017/06/doc-document-di/) từ đầu đến cuối, trong này có hướng dẫn code app To Do List:
    [http://redux.js.org/docs/introduction/](http://redux.js.org/docs/introduction/)
4.  Muốn master thì viết lại các hàm, các middleware như connect, applyMiddleware. Mà muốn làm được thì cũng phải master React tại phải dùng Higher-Order Components

### Một số resources hay

[The Complete React Native and Redux Course](https://www.udemy.com/the-complete-react-native-and-redux-course/learn/v4/overview)

[Advanced React and Redux](https://www.udemy.com/react-redux-tutorial/)

Hình chôm từ:

[https://www.udemy.com/full-stack-universal-react-with-redux-express-and-mongodb/](https://www.udemy.com/full-stack-universal-react-with-redux-express-and-mongodb/)

[https://www.theodo.fr/blog/2016/03/getting-started-with-react-redux-and-immutable-a-test-driven-tutorial-part-2/](https://www.theodo.fr/blog/2016/03/getting-started-with-react-redux-and-immutable-a-test-driven-tutorial-part-2/)
]]></description>
            <link>https://hungvn.com/blog/cac-nguyen-tac-co-ban-cua-redux</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cac-nguyen-tac-co-ban-cua-redux</guid>
            <pubDate>Tue, 10 Oct 2017 22:41:15 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Kiến trúc tổng quan của Angular 2/4 - P2]]></title>
            <description><![CDATA[
## Data binding

Hãy tưởng tượng rằng, bạn đang phải code 1 ứng dụng web mà việc tương tác, thay đổi giá trị trên DOM diễn ra liên tục. Sẽ thực sự là 1 cơn ác mộng nếu bạn phải tự tay thực hiện toàn bộ các thao tác update, create value trên các HTML DOM khi có hành động của người dùng mà không sử dụng 1 framework nào khác ngoài mấy thư viện kiểu jQuery :-s

Với Angular, chúng ta có 1 thuật ngữ là **data binding**, một cơ chế phối hợp nhịp nhàng các thành phần của **template** với **component**. Việc này rất đơn giản, chúng ta chỉ cần thêm _binding markup_ vào HTML là Angular tự hiểu và connect chúng tới Component.

Như diagram bên dưới, có 4 kiểu _data binding syntax_. Mỗi kiểu đều có chiều dữ liệu từ DOM tới COMPONENT, từ COMPONENT tới DOM, và có cả kiểu có 2 chiều dữ liệu.

![](https://viblo.asia/uploads/dfbd5235-6342-4a1d-9672-f78c941338c1.png)

Ở ví dụ HeroListComponent, template có 3 kiểu:

**`app/hero-list.component.html` (binding)**

```html
<li>{{hero.name}}</li>
<hero-detail [hero]="selectedHero"></hero-detail>
<li (click)="selectHero(hero)"></li>
```

- Markup 1 có chức năng hiển thị giá trị của component's _hero.name_ property với thẻ `<li>`.
- Markup [hero] property binding truyền giá trị của selectedHero từ parent HeroListComponent tới các hero property của HeroDetailComponent.
- (click) event binding gọi phương thức selectHero khi user **click** vào hero's name.

Kiểu quan trọng thứ 4, được gọi là **Two-way data binding**. Chỉ với 1 markup notation đơn giản sử dụng ngModel directive, ta có thể kết hợp việc binding _event_ và _property_.

**app/hero-detail.component.html (ngModel)**

```html
<input [(ngModel)]="hero.name" />
```

![](https://viblo.asia/uploads/a1434531-d952-4bf9-9999-58d835eaf7db.png)

Angular xử lý **toàn bộ** data bindings trên mỗi JavaScript _event_, xuất phát từ gốc của cây application component duyệt tới toàn bộ components lá.

**Data binding** đóng một vai trò quan trọng trong việc giao tiếp giữa **template** và **component**.

**Data binding** còn là công cụ giao tiếp giữa **parent** và **child components**.

## Directives

_Angular templates_ là dynamic. Khi ứng dụng Angular thực hiện render template, chúng transforms DOM theo các lệnh nhận được từ **directives**.

![](https://viblo.asia/uploads/a88f5717-647f-4806-b90b-fe90c558929f.png)

Một **directive** là một class bắt đầu với @Directive _decorator_. Có thể coi một component là một directive-với-một-template; @Component _decorator_ thực chất là một @Directive _decorator_ kế thừa từ **template-oriented** features.

> While a component is technically a directive, components are so distinctive and central to Angular applications that this architectural overview separates components from directives.

Câu trích dẫn trên cho chúng ta lý do tại sao chúng ta lại tách **Component** ra khỏi **Directive** trong kiến trúc Angular.

Có 2 loại **directives**: _structural_ và _attribute_ **directives**.

Chúng xuất hiện giữa element tag như 1 thuộc tính (attributes).

_Structural_ **directives** tùy chỉnh layout bằng cách thêm mới, xóa bỏ và thay thế elements trong DOM.

Ví dụ dưới đây sử dụng 2 loại built-in _structural_ **directives**:

**app/hero-list.component.html (structural)**

```html
<li *ngFor="let hero of heroes"></li>
<hero-detail *ngIf="selectedHero"></hero-detail>
```

1.  \*ngFor giúp liệt kê các hero từ mảng heroes trong mỗi thẻ `<li>`
2.  \*ngIf include HeroDetail component nếu có một hero được select.

**Attribute** directives thay thế appearance hoặc behavior của các element. Bên trong templates, chúng chẳng có gì khác các HTML attributes thông thường, ngoại trừ tên :))

**ngModel** directive, implements **two-way data binding**, là một ví dụ của attribute directive. **ngModel** thay đổi behavior của element (Ví dụ tiêu biểu là các `<input>`) bằng cách thiết lập value property hiển thị ra cũng như thay đổi chúng theo events.

**app/hero-detail.component.html (ngModel)**

```html
<input [(ngModel)]="hero.name" />
```

Ngoài ra, chúng ta còn nhiều **directives** có thể chỉnh sửa cấu trúc layout (ngSwitch) hoặc thay đổi DOM elements và components (ngStyle và ngClass).

Dĩ nhiên, bạn cũng có thể tự viết một **directives**. **Components** như HeroListComponent chính là một loại **custom directive**.

## Services

![](https://viblo.asia/uploads/091a88e9-6a22-462f-9a5c-0f6844ff7d06.png)

**Service** có thể là bấy kỳ giá trị, hàm, class,... tính năng nào cần thiết cho ứng dụng của bạn hoạt động.

Hầu hết mọi thứ đề có thể trở thành **service** (lol). Một **service** điển hình là một class được thu hẹp lại trong một mục đích rõ ràng.

Ví dụ:

- logging service
- data service
- message bus
- tax calculator
- application configuration

Không có một chút đặc trưng của **Angular** về **services**. **Angular** cũng không có bất kỳ định nghĩa nào về **service**.

> No service base class, and no place to register a service.

Tuy nhiên **services** lại là nền tảng của bất kỳ ứng dụng Angular nào. **Components** cũng là một services.

Dưới đây là một service class có nhiệm vụ logs lên browser console:

**app/logger.service.ts (class)**

```typescript
export class Logger {
  log(msg: any) {
    console.log(msg);
  }
  error(msg: any) {
    console.error(msg);
  }
  warn(msg: any) {
    console.warn(msg);
  }
}
```

Còn đây là HeroService có nhiệm vụ lấy về mảng các heroes và trả về chúng cùng với resolved Promise. HeroService phụ thuộc vào Logger service và BackendService khác nắm giữ việc communication với server.

**app/hero.service.ts (class)**

```typescript
export class HeroService {
  private heroes: Hero[] = [];

  constructor(
    private backend: BackendService,
    private logger: Logger) { }
  )

  getHeroes() {
    this.backend.getAll(Hero).then( (heroes: Hero[]) => {
      this.logger.log(`Fetched ${heroes.length} heroes.`);
      this.heroes.push(...heroes); // fill cache
    });
    return this.heroes;
  }
}
```

> Services are everywhere.

**Component classes** như một miếng thịt nạc không có mỡ =)) . Không có bất kì đoạn code nào fetch data từ server, validate user input, hoặc log lên console. Tất các các tasks đó được giao cho **services**.

Công việc của một **component** lúc này không hơn việc cho phép người sử dụng trải nghiệm dịch vụ. Đứng giữa view (rendered bởi template) và tầng application logic.

Khi code **Angular**, không ai ép bạn làm theo parttern này, cũng không quy định nguyên tắc gì về **service**, tuy nhiên chắc hẳn mọi người sẽ không phàn nàn nếu bạn hoàn thành 1 component với hơn 3000 lines code =))

**Angular** giúp ta thực hiện các nguyên tác này dễ dàng hơn bằng cách support **Dependency injection**.

## Dependency injection

![](https://viblo.asia/uploads/4df0dd41-68bf-4bc9-a6ce-9fcb5c2bfd3c.png)

**Dependency injection** là một cách cung cấp các new instance của một class cùng với các dependencies phụ thuộc mà nó cần. Hầu hết các **dependencies** là **services**. Angular sử dụng **dependency injection** để chuẩn bị một _new component_ cùng với các services mà nó cần.
@
Việc khai báo các **services** cần thiết cho một **component** cũng với kiểu dữ liệu của nó được thực hiện trong chính constructor parameters. Ví dụ về constructor của HeroListComponent và HeroService ở đây chính là một dependency :

**app/hero-list.component.ts (constructor)**

```typescript
constructor(private service: HeroService) { }
```

Khi Angular khởi tạo một component, nó sẽ hỏi **injector** về các services mà component cần.

Một **injector** lưu giữ container các service instances đã được tạo trước đó. Nếu có một yêu cầu về service instance không có trong container, **injector** sẽ tạo và thêm mới nó rồi add nó vào container trước khi trả lại service cho Angular. Khi tất cả các request services được giải quyết (resolved) và được hoàn thành (returned), Angular có thể gọi các component's constructor cùng với các tham số là các services. Đó chính là **dependency injection**.

Quá trình injection của HeroService có thể trông giống sơ đồ sau:

![](https://viblo.asia/uploads/188ec1e4-b3a9-47c6-a228-83d72a1d645a.png)

Nếu injector không có HeroService, Vậy làm thể nào để Angular biết nơi cần lấy và tạo ra nó

Như đã mô tả trước đó, bạn cần phải đăng ký (registered) HeroService với **provider** của HeroComponent cùng **injector**. Một provider có thể create và return một service.

Bạn có thể **register providers** trong **modules** hoặc trong **components**.

Thông thường, chúng ta add providers vào root module, ez, ta có instance của service tồn tại ở mọi nơi (ngon).

**app/app.module.ts (module providers)**

```typescript
providers: [
  BackendService,
  HeroService,
  Logger
],
```

Một cách khác, ta có thể register ở level component trong providers property của @Component **metadata**:

**app/hero-list.component.ts (component providers)**

```typescript
@Component({
  moduleId: module.id,
  selector:    'hero-list',
  templateUrl: 'hero-list.component.html',
  providers:  [ HeroService ]
})
```

Registering ở level component nghĩa là bạn có thể lấy ra các new instance của service với mỗi một new instance của component đó.

Các điểm cần nhớ về **dependency injection**:

- Dependency injection được móc vào Angular framework và có thể sử dụng ở mọi nơi.
- Injector có 2 cơ chế chính.
  - Injector duy trì một container các service instances mà chúng đã tạo ra.
  - Injector có thể tạo mới service instance từ provider.
- Provider là nơi khai báo cách tạo ra service.
- Register providers với injectors.

### _THE END_

## Tham khảo

[https://angular.io/docs/ts/latest/guide/architecture.html](https://angular.io/docs/ts/latest/guide/architecture.html)
]]></description>
            <link>https://hungvn.com/blog/kien-truc-tong-quan-cua-angular-2-4-p2</link>
            <guid isPermaLink="true">https://hungvn.com/blog/kien-truc-tong-quan-cua-angular-2-4-p2</guid>
            <pubDate>Sun, 01 Oct 2017 16:02:02 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Kiến trúc tổng quan của Angular 2/4  - P1]]></title>
            <description><![CDATA[
## Đôi điều về Angular 2

- Hiểu đơn giản là một framework để giúp lập trình viên xây dựng các ứng dụng client với HTML và JavaScript/Typescript ...
- Việc render HTML templates sẽ được thực hiện bởi Angularized-markup, việc cần làm của một developer là viết các component để quản lý template, thêm mới các xử lý logic bên trong các service, đóng gói component và service thành một module.
- Một ứng dụng Angular2 được chạy dựa trên việc bootstrapping root module vào Angular's bootstrapper.
  ![](https://viblo.asia/uploads/a1b02db2-8d40-425f-91e8-6a6193547b5d.png)

  Dựa vào sơ đồ kiến trúc trên ta có thể liệt kê ra 8 thành phần chính tạo ra một ứng dụng Angular 2:

- Module
- Component
- Template
- Metadata
- Data Binding
- Service
- Directive
- Dependency Injection

## Modules

![](https://viblo.asia/uploads/523f82f0-b104-431e-a5af-acb7bcc8e83c.png)
Angular apps sử dụng hệ thống module, hay còn gọi là _Angular modules_ hoặc _NgModules_.
Trong bài viết này chủ yếu là giới thiệu các modules; Để tìm hiểu sâu hơn xin vui lòng tham khảo [Angular modules](https://angular.io/docs/ts/latest/guide/ngmodule.html).
Mỗi ứng dụng Angular đều phải có ít nhất một Angular module class, là _root module_, hay còn được đặt tên theo quy ước là _AppModule_.

Trong các ứng dụng nhỏ, đôi khi chỉ có duy nhất 1 module chính là _root module_ , tuy nhiên ở hầu hết các ứng dụng, còn có thêm nhiều feature modules.
Dù là _root_ hay là _feature_ module, thì mỗi class đều có @NgModule decorator.

> Decorators là design pattern thường được dùng để thay đổi hành vi, chức năng của JavaScript classes. Angular cung cấp sẵn nhiều decorators gắn các metadata vào các classes để dễ dàng biết được ý nghĩa và cách thức hoạt động.

_NgModule_ là một decorator function (single metadata object) có các thuộc tính mô tả các module. Các thuộc tính quan trọng là:

- _declarations_ - Khai báo các View classes thuộc về module. Angular có 3 loại view classes: components, directives, pipes.
- _exports_ - Một tập con của _declarations_ khả dụng trong component templates của các module khác.
- _imports_ - Các module khác được exported các classes cần thiết bởi component templates được _declarations_ bên trong module này.
- _providers_ - Tạo ra các global collection of services có thể truy cập ở mọi ngõ ngách của ứng dụng.
- _bootstrap_ - Main application view, hay còn được gọi là _root component_, chứa tất cả các app views. Duy nhất _root module_ có thuộc tính bootstrap.

Dưới đây là một _ root module_ đơn giản:

**app/app.module.ts**

```typescript
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";

@NgModule({
  imports: [BrowserModule],
  providers: [Logger],
  declarations: [AppComponent],
  exports: [AppComponent],
  bootstrap: [AppComponent],
})
export class AppModule {}
```

> Trong trường hợp này, thuộc tính export của AppComponent chỉ đơn giản mô tả cách export; nó thì không cần thiết trong thực tế. Một _root module_ không có lý do gì để export bất cứ điều gì, đơn giản là các component khác ko cần thiết phải import _root module_.

Khởi chạy ứng dụng bằng cách bootstrapping _root module_. Trong quá trình development, chúng ta sẽ bootstrap AppModule trong file **main.ts**.

**app/main.ts**

```typescript
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app.module";

platformBrowserDynamic().bootstrapModule(AppModule);
```

### Angular modules vs. JavaScript modules

**Angular Module**: Class decorator với @NgModule — đây là 1 một tính tăng cơ bản Angular.

**Javascript Module**: JavaScript cũng có một hệ thống module để quản lý các JavaScript objects. Nó hoàn toàn khác biệt và không liên quan tới Angular module system.

> Trong JavaScript mỗi file là một module và tất cả các đối tượng được định nghĩa trong file đều thuộc về module đó. Các module khai báo đối tượng public bằng cách sử dụng từ khóa export. Các module JavaScript khác sử dụng từ khóa import để truy cập vào đối tượng public từ các module khác.

```typescript
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
```

```typescript
export class AppModule {}
```

Tìm hiểu thêm về [Javascript Module](http://exploringjs.com/es6/ch_modules.html).

### Angular libraries

![](https://viblo.asia/uploads/998f1c91-dc05-4e19-9d1c-2195c10886ca.png)

Angular được ví như 1 con tàu chuyên chở các JavaScript modules. Cũng có thể ví là các library modules.

Mỗi Angular library name đều bắt đầu với tiền tố @angular.
Bạn cài đặt chúng với npm package manager và import các phần lại bằng câu lệnh JavaScript import.

Lấy ví dụ, import Angular's Component decorator từ **@angular/core** library như sau:

```typescript
import { Component } from "@angular/core";
```

Bạn cũng có thể import _Angular modules_ từ _Angular libraries_ sử dụng câu lệnh JavaScript import:

```typescript
import { BrowserModule } from "@angular/platform-browser";
```

Trong ví dụ về _root module_ bên trên, application module cần _BrowserModule_. Để truy cập tới _BrowserModule_, ta thêm vào @NgModule metadata imports:

```typescript
imports:      [ BrowserModule ],
```

Theo cách này, ta đang sử dụng cả Angular and JavaScript module systems cùng nhau.

## Components

![](https://viblo.asia/uploads/3735f092-68b6-4cb4-ac1e-0c28e5f6d85c.png)
Một component điều khiển từng chức năng trên màn hình view.
Ví dụ, view sau được điều khiển bởi các components:

- The app root với navigation links.
- The list of heroes.
- The hero editor.

Chúng ta cần định nghĩa component's application logic—những gì sẽ support trên view—bên trong một class. Class sẽ tương tác với view thông qua API của các properties và methods.

Ví dụ, **HeroListComponent** có một heroes property trả về 1 mảng các heroes lấy từ service. **HeroListComponent** cũng có sẵn phương thức selectHero() để get các thuộc tính của selectedHero khi người dùng chọn user từ danh sách.

**app/hero-list.component.ts (class)**

```typescript
export class HeroListComponent implements OnInit {
  heroes: Hero[];
  selectedHero: Hero;

  constructor(private service: HeroService) {}

  ngOnInit() {
    this.heroes = this.service.getHeroes();
  }

  selectHero(hero: Hero) {
    this.selectedHero = hero;
  }
}
```

Angular creates, updates, và destroys components cùng với user di chuyển xuyên suốt trong application. App có thể lấy các action ở từng thời điểm tron lifecycle thông qua lifecycle hooks, như ngOnInit() được khai báo bên trên.

## Templates

![](https://viblo.asia/uploads/c4425a98-9a0e-4635-a25f-3dd5103b8b23.png)
Chúng ta định nghĩa component's view với template của nó. Một template là mã code HTML giúp Angular render component.

Một template có thể có đôi chút khác biệt với HTML thông thường, đây là 1 ví dụ cho template của HeroListComponent:

**app/hero-list.component.html**

```html
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
  <li *ngFor="let hero of heroes" (click)="selectHero(hero)">{{hero.name}}</li>
</ul>
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>
```

Mặc dù template này sử dụng các thành phần cơ bản HTML như `<h2>` và `<p>`, nhưng cũng có đôi chút khác biệt như `*ngFor`, `{{hero.name}}`, `(click)`, `[hero]`, và `<hero-detail>` sử dụng _Angular's template syntax_.

Trên dòng cuối cùng của template, `<hero-detail>` tag là custom element thể hiện cho new component, HeroDetailComponent.

HeroDetailComponent là một component khác với HeroListComponent chúng ta đang xem. HeroDetailComponent mô tả chi tiết từng hero, mà người dùng đã **select** từ HeroListComponent. HeroDetailComponent là con (_child_) của HeroListComponent.
![](https://viblo.asia/uploads/d0f19d36-3916-4721-9e7f-1b872b74f3c4.png)

> Element `<hero-detail`> có thể được code thoải mái giữa native HTML elements

## Metadata

![](https://viblo.asia/uploads/9bdc0dbb-5bfc-43ec-a307-26fd72eda43e.png)
**Metadata** giúp Angular biết cách xử lý các class.

Quay trở lại code HeroListComponent bên trên, ta thấy rằng đó chỉ đơn giản là 1 class, ko có dấu ấn gì của 1 framework cả, no "Angular" omg

Thực tế, HeroListComponent thực chất chỉ là 1 class. Nó không phải là 1 component cho tới khi ta khai báo nó với Angular.

Để khai báo với Angular rằng HeroListComponent là 1 component, ta sẽ gắn thẻ **metadata** vào class này.

Trong TypeScript, việc gắn thẻ **metadata** sử dụng decorator. Dưới đây là metadata cho HeroListComponent:

**`app/hero-list.component.ts` (metadata)**

```typescript
@Component({
  moduleId: module.id,
  selector: "hero-list",
  templateUrl: "hero-list.component.html",
  providers: [HeroService],
})
export class HeroListComponent implements OnInit {
  /* . . . */
}
```

_Decorator_ ở đây chính là @Component, định nghĩa class ngay bên dưới như một _component class_.

@Component decorator khởi tạo một object với các thông tin mà _Angular_ cần thể tạo và biểu diễn một component & view.

Dưới đây là một số option cấu hình cho @Component:

- moduleId: Tập hợp các source dựa trên address (module.id) với module-relative URLs như templateUrl.
- selector: CSS selector ra lệnh cho Angular create và insert một thể hiện component khi nó tìm thấy `<hero-list>` tag trong parent HTML. Ví dụ, nếu một app's HTML có chứa <hero-list></hero-list>, thì Angular sẽ inserts một instance của HeroListComponent view giữa các tags.
- templateUrl: module-relative address của component's HTML template.
- providers: Mảng các dependency injection providers cho services cần thiết để component hoạt động. Đây là 1 cách khai báo với Angular rằng, component's constructo yêu cầu 1 HeroService để nó có thể thu được danh sách các heroes phục vụ việc hiển thị lên màn hình.

![](https://viblo.asia/uploads/8e49084e-55a7-4f71-98e6-d3a12c5729ff.png)

**Metadata** trong @Component giúp Angular biết cách lấy những thành phần chính tạo nên component.
**Template**, **Metadata**, và **Component** được sử dụng cùng với nhau với mục đích tạo nên **View**.
Ngoài @Component, chúng ta còn có @Injectable, @Input, và @Output là những _decorators_ rất hay được sử dụng.

## Tham khảo

[https://angular.io/docs/ts/latest/guide/architecture.html](https://angular.io/docs/ts/latest/guide/architecture.html)
]]></description>
            <link>https://hungvn.com/blog/kien-truc-tong-quan-cua-angular-2-4-p1</link>
            <guid isPermaLink="true">https://hungvn.com/blog/kien-truc-tong-quan-cua-angular-2-4-p1</guid>
            <pubDate>Sun, 01 Oct 2017 15:43:49 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Các kỹ thuật SEO tối thiểu mà developer cần nắm vững trong lập trình web]]></title>
            <description><![CDATA[
Trong khi đang làm việc tại công ty Basic (1 công ty của Nhật hoạt động trong lĩnh vực Web & Media Marketing, vận hành 2 website [ferret](https://ferret-plus.com) và [ferretOne](https://ferret-one.com)), tôi được giao nhiệm vụ tối ưu hoá công cụ tìm kiếm cho website [phocase](https://phocase.jp) (1 website bán phụ kiện điện thoại), để hoàn thành công việc này tôi đã phải tìm hiểu và học thêm các kiến thức, tiện đây xin được tổng hợp lại và chia sẻ với các bạn những điều cần nhớ về SEO với vai trò là 1 kỹ sư.

**TLDR**; Bài viết này dành cho nhiều đối tượng nên tương đối dài, hãy chọn lọc các kiến thức cần thiết cho mình thôi nhé :v

### ★ Bạn có thể nhận được gì khi đọc bài viết này ?

- Sự tương tác giữa các Marketer và Director trở nên dễ dàng hơn
- Nhận biết các đoạn code mà vô tình làm giảm thứ hạng của website trên bộ máy tìm kiếm
- Đề xuất các giải pháp SEO có thể thực hiện được ở phía Developer
- Nắm bắt được bức tranh/bối cảnh SEO năm 2017

## Nắm bắt chính xác tài liệu được Google chính thức công khai

Có thể tìm kiếm rất nhiều thông tin trên các trang web, nhưng tối thiểu thì hãy thực hiện những chính sách được Google đưa ra về rule của 1 website.

[Search Engine Optimization Starter Guide](https://static.googleusercontent.com/media/www.google.com/en//webmasters/docs/search-engine-optimization-starter-guide.pdf)

Ngoài ra bạn cũng có thể tìm hiểu thêm các thông tin tại website chính thức của Google: [Official news on crawling and indexing sites for the Google index](https://webmasters.googleblog.com)

### ★ Kiểm tra lại các biện pháp SEO trước đó để nắm được các thông tin hữu ích

Hãy tìm kiếm trong **Search Console Help** các từ khoá liên quan tới các công việc đã thực hiện từ trước, rất có thể bạn sẽ phát hiện ra những kỹ thuật bị bỏ sót mà mình không hề nghĩ tới.

Chẳng hạn nếu như bạn có sử dụng thẻ alt với ảnh trên website, thì tôi khuyên bạn nên thử tìm kiếm trong **Search Console Help** các ảnh đã được đánh tag trước đó.
Việc nhồi nhét quá nhiều keyword trong thẻ alt có thể khiến search engineer đưa vào danh sách spam, đây cũng có thể là cách để bạn phòng tránh việc đó.
[Search Console Help](http://support.google.com/webmasters/)

# Chính sách của Google đối với Mobile Site

## Mobile First Index (MFI)

Ngày 5/11/2016, Google chính thức công bố chính sách của mình đối với Mobile site: [Mobile-first Indexing](https://webmasters.googleblog.com/2016/11/mobile-first-indexing.html)

Về cơ bản, cho tới thời điểm hiện tại ngoài rank được đánh cho các website hướng PC Desktop, Google còn bổ sung thêm rank cho các website chú trọng nội dung và thiết kế tới SP (Smart phone)

Ngày 5/4/2017, Tại hội nghị [Next10x Conference](https://www.stonetemple.com/next10x-conference/), Các kỹ sư của Google đã chính thức công bố mục tiêu áp dụng vào trong năm nay, tuy nhiên chưa công bố chính thức khoảng thời gian.

- Trước khi áp dụng MFI (Hiện tại)
  - PC Search: Hiển thị theo trình tự của rank cho nội dung PC site
  - SP Search: Hiển thị theo trình tự của rank cho nội dung PC site

- Sau khi áp dụng MFI (Chưa xác định thời gian)
  - PC Search: Hiển thị theo trình tự chú trọng vào rank cho nội dung SP site (Không có nghĩa là không tính đến rank của PC site)
  - SP Search: Hiển thị theo trình tự của rank cho nội dung SP site

### ★ Các site có khả năng chịu ảnh hưởng

- Có sự khác biện lớn giữa phiên bản **PC và SP**
- Còn nhiều thông tin tồn tại trên phiên bản cho PC nhưng lại ko có trên phiên bản SP
- Đã hỗ trợ và có chiến lược SEO cho PC site nhưng lại chưa có cho SP site
- Ngoài header vs footer ra, các nội dung chính là khác nhau
- Cấu trúc HTML khác nhau
- Tốc độ hiển thị cho SP site quá chậm

## Mobile Friendly

Ngày 21/4/2015, Google công bố : thứ tự xuất hiện trên kết quả tìm kiếm có liên quan tới UI, UX trong trường hợp truy cập trang web trên Smart Phone Device
[Rolling out the mobile-friendly update](https://webmasters.googleblog.com/2015/04/rolling-out-mobile-friendly-update.html)

> Chỉ ảnh hưởng tới thứ tự xuất hiện kết quả tìm kiếm trên Mobile Device
> Ảnh hưởng trong phạm vi toàn bộ các ngôn ngữ trên thế giới
> Áp dụng cho các page riêng rẽ, chứ không phải toàn bộ trang web

Nếu như website đó không được coi là Mobile Friendly sẽ có thứ tự thấp và không được ưu tiên xuất hiện trên kết quả tìm kiếm. Điều này có tác động trực tiếp tới doanh thu của các website thương mại điện tử (EC site)

Sử dụng website sau, có thể kiểm tra tính thân thiện với thiết bị mobile của 1 trang web
[Mobile Friendly Check](https://www.google.com/webmasters/tools/mobile-friendly/)

### ★ Các hạng mục cần kiểm tra

- Font size có thích hợp (>= 16px) không?
- Có sử dụng thẻ meta và chỉ định viewport cho mobile không?
- Khoảng cách của các liên kết có bị quá hẹp không? (phòng ngừa lỗi)
- Nội dung trang web có bị tràn ra ngoài màn hình không?
- Website có được hiển thị trong vòng 3s không? (Nếu việc hiển thị tốn quá > 3s, thì 40% người dùng sẽ thoát trang web đó)

Đối với các website không thoả mãn tối thiểu các điều kiện trên sẽ có thể có có thứ hạng thấp trong kết quả tìm kiếm.

### ★ Mobile Friendly Support & Yêu cầu craw lại website

Bằng cách sử dụng **GoogleSearchConsole**, bạn có thể nắm rõ được chi tiết các thành phần trên website mình không thoả mãn các hạng mục kiểm tra phía trên.
[Google Webmaster Home](https://www.google.com/webmasters/tools/home)

Sau khi giải quyết các vấn đề trên, hãy gửi yêu cầu cho Google crawl lại các URL đó.
Chi tiết các bạn có thể tham khảo link sau về việc [Yêu cầu Google crawl lại các URL](https://support.google.com/webmasters/answer/6065812?hl=vi)

### ★ Các hạng mục để đánh giá về UX

- First view của trang web sẽ được hiển thị trong vòng 1 giây (Google recommended)
- Chuẩn bị riêng biệt kích thước hình ảnh với PC Site, để giảm dung lượng của một trang web
- Sử dụng công cụ YUI Compressor và JSMin để rút ngắn đoạn code dài như thư viện
- Thiết lập các nội dung có thể tab được lớn hơn 48px

Để xác nhận tốc độ hiển thị của web site, bạn có thể dụng công cụ: [PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/)

### ★ Chuyển tiếp quảng cáo

Đối với các quảng cáo chuyển tiếp thì đến khi hiển thị target page, thì hiển thị quảng cáo với link [**Skip this page**] giống như ảnh bên dưới, từ tháng 11 năm 2016 sẽ vi phạm điều luật của Google.

![](https://viblo.asia/uploads/87d34608-62a4-4e35-a038-f2b0e1c33321.png)

Quote: [https://london3.jp/2014/12/skip/](https://london3.jp/2014/12/skip/)

### ★ Các tác động dẫn tới việc giảm thứ hạng rank

- Nội dung chính nằm trong Popup (kể cả Modal)
- Trước khi dẫn tới main content (nội dung chính) của website thì hiển thị quảng cáo giống trong ảnh trên
- First view có chưa quảng cáo với kích thước lớn, nếu không scroll thì không thấy được nội dung chính

### ★ Các tác động không ảnh hưởng tới thứ hạng rank

- Pop-up cấp quyền sử dụng Cookie
- Các hiển thị như xác minh độ tuổi với cơ sở dựa vào pháp luật
- Các page mà chỉ một bộ phận cụ thể người dùng được hiển thị, chẳng hạn như một trang đăng nhập.
- Banner quảng cáo Pop-up mà không chiếm nhiều diện tích màn hình

Hơn nữa, trong cuộc đối thoại giữa Google với người sử dụng có câu hỏi:

> Về nội dung Pop-up (Quảng cáo) thì, liệu có khả năng nội dung ẩn bên trong nó lại được Googlebot ưu tiên ko ?

Về phía Google đã trả lời là:「Chính xác là có khả năng đó」, như vậy thì việc hiển thị quảng cáo dù là = Pop-up hay Modal cũng là không nên.

# Cài đặt XML Sitemap & Đăng ký RSS Feed

Công việc này đã được Google hướng dẫn rất chi tiết tại link sau:
[Best practices for XML sitemaps & RSS/Atom feeds](https://webmasters.googleblog.com/2014/10/best-practices-for-xml-sitemaps-rssatom.html)

## RSS, Atom Register và PubSubHubbub(PuSH)

Được sử dụng như Sitemap, có format tương tự RSS và Atom trong RSS Reader.。

### ★ Lợi ích khi đăng ký Feed

- Chỉ URL được cập nhật gần đây nhất được đăng ký.
- Tần suất Crawl cao hơn Sitemap thông thường

Việc thông báo cho Google các Page được create/update gần đây nhất là một phương pháp sử dụng Feed có tần suất Crawl cao hơn một cách hiệu quả.

### ★ Thực hiện index theo thời gian thực dựa vào PubSubHubbub (PuSH)

Một cách để thực hiện index realtime khác đó là: Sử dụng phương thức PubSubHubbub (hay còn gọi là PuSH) giúp thông báo tới Google các thay đổi tại thời điểm mà các trang được update.

[Danh sách các repository thực hiện việc implement **PuSH** được viết trên nhiều ngôn ngữ lập trình](https://github.com/pubsubhubbub)

Trường hợp code bằng PHP, có thể sử dụng file được Download từ thư viện sau đây:
pubsubhubbub-php-master/library/publisher.php

```php
require_once './publisher.php' ;
$publisher = new Publisher('http://pubsubhubbub.appspot.com/');
$publisher->publish_update('http://example.com/article/1');
```

## Đăng ký Sitemap

### ★ HTML Sitemap

- Sitemap cho người sử dụng truy cập trang web
- Thường xuyên quản lý để tránh các liên kết lỗi
- Việc phân loại sẵn các Category giúp cải thiện khả năng sử dụng

### ★ XML Sitemap

Việc tạo sẵn một Sitemap có định dạng XML chính là công cụ đắc lực, trợ giúp Search Engine index website của bạn
Dưới đây là các loại Sitemap:

| Loại File XML | Vai trò                                           |
| ------------- | ------------------------------------------------- |
| sitemap.xml   | Mô tả cấu trúc website, bao gồm cả mobile sitemap |
| movie.xml     | Hiển thị các nội dung video trong tìm kiếm        |
| image.xml     | Hiển thị các nội dung ảnh trong tìm kiếm          |
| news.xml      | Khai báo các tệp tin được gửi tới Google News     |

- Với mỗi file XML được cài đặt chính xác, góp phần xúc tiến việc index website của bạn
- Tuy nhiên nếu crawler không visit, chúng ta cần thực hiện cải thiện lại Sitemap đã tạo trước đó
- Trên SP site việc giới hạn quyền truy cập webiste mobile trên device = .htaccess có thể khiến Search Engine Bot không vô được, vì vậy hãy cho phép Googlebot-Mobile có quyền truy cập.

Trong thực tế, đối với việc create/submit Sitemap chúng ta có thể tham khảo thêm tại link [Build and submit a sitemap](https://support.google.com/webmasters/answer/183668?hl=vi) , có hướng dẫn chi tiết các loại tool giúp tạo và test sitemap, rất tiện lợi.

### ★ Video, Image Sitemap

Việc Crawler thu thập thông tin tìm kiếm liên quan tới Video và Ảnh là tương đối khó khăn, do đó chúng ta cần sử dụng Sitemap chuyên dụng có chứa thông tin cho Video và Image.
Về cách create thì bạn có thể tạo file XML chỉ chứa các video và ảnh mới tạo hoặc bổ sung chúng vào 1 file XML đã tồn tại đều ok, tuy nhiên hãy thiết lập một sitemap chứa nhiều thông tin.
[Sitemap Protocol](https://www.sitemaps.org/index.html) : Video extension, Title, Duration, Description

Hơn nữa, bằng cách sử dụng Video Sitemap, khi tiến hành tìm kiếm Video lẫn Image trong Search Engine, Video có thể được tìm thấy trong kết quả.
Ví dụ file movie.xml như sau:

```
xmlns:video="http://www.google.com/schemas/sitemap-video/1.1"
```

Khi vận hành 1 EC site (Website thương mại điện tử) sử dụng Image Sitemap, doanh nghiệp có thể thu hút và tiếp cận được đối tượng người dùng tìm kiếm sản phẩm muốn mua bằng ảnh trên máy tìm kiếm.

# Những điều cần lưu ý khi sử dụng tag HTML

## 【Title】

Trong SEO, thẻ **Title** là một trong số những thẻ tag có tầm ảnh hưởng nhất, Trong 1 page chỉ được có 1 thẻ **title** trong **head** tag.
index.html

```
<head>
    <title>Page title</title>
</head>
```

- Nếu trong thẻ title có từ khóa tìm kiếm của user sẽ được bôi đậm trên kết quả tìm kiếm
- Mỗi Page nên có 1 thẻ title với nội dung khác nhau
- Trên kết quả tìm kiếm của Search Engine sẽ chỉ hiển thị tối đa ~32 ký tự trong nội dung của thẻ **title**
- Nếu trong thẻ **title** có chứa các từ khóa không cần thiết sẽ làm giảm trọng số của từ khóa mong muốn được tìm kiếm
- Nên lựa chọn nội dung của thẻ **title** sao cho dựa vào đó có thể đoán được phần nào nội dung của web page

Cần lưu ý rằng trên Search Engine sẽ chỉ hiển thị khoảng **32** ký tự cho tiêu đề (title) của 1 website, và thậm chí là **24** ký tự khi người dùng tìm kiếm trên thiết bị di dộng.
Nếu đặt tiêu đề cho page không liên quan tới nội dung của page sẽ làm giảm lượng người dùng truy cập, dẫn tới rank website bị giảm. Cho dù người dùng có truy cập vào nhưng do nội dung chính và tiêu đề không giống nhau, họ sẽ mau chóng rời đi -> tỷ lệ bounce rate sẽ ngày càng tăng.

## 【Description】

Trước tiên khi thiết lập Description, nội dung hiển thị trên search engine sẽ thay đổi tại đây:

![](https://viblo.asia/uploads/fe0e1e65-10cb-4092-a44f-1298ae8fda93.png)

Việc thêm mô tả cho nội dung mà người dùng mong muốn tìm kiếm, góp phần làm tăng tỷ lệ **click rate** trên search result.
Tuy nhiên nếu xét về mức độ ảnh hưởng về ranking trong thứ hạng xuất hiện trên Search Engine thì có vẻ là không lớn lắm.

Hơn nữa ở thời điểm hiện tại dù không có mô tả rõ ràng cho page thì Google cũng hiện thị Description mà nó tự động tạo ra cho web page.

Dựa vào các mô tả mà Google tự động sinh ra cho trang web, với các trường hợp đưa ra Description phán đoán chính xác thông tin trên website:

- Khuyến khích để Google tự động tạo **description** cho web page
- Các page khác nhau phải có nội dung khác nhau
- Nội dung **description** cần nhất quán với **title** tag
- Trên search engine chỉ hiển thị khoảng **124** ký tự cho phần **description**
- Khi tìm kiếm bằng thiết bị di động thì chỉ hiển thị khoảng **80** ký tự cho phần **description**
- Không bắt buộc văn phong phải chính xác tuy nhiên nội dung của tag phải rõ ràng, chuẩn xác.

Bạn có thể sử dụng tool sau để đánh giá **description** trên 1 web page: [http://seolaboratory.jp/description/](http://seolaboratory.jp/description/)

## 【h1】

Do việc lạm dụng thẻ **h1** quá nhiều dẫn tới Google đã hạ chỉ số đánh giá của nó, tuy nhiên do vẫn còn xuất hiện trên kết quả tìm kiếm, nên đối với SEO vẫn còn khá quan trọng.

- Mỗi page chỉ nên có 1 thẻ h1
- Mặc dù Google có công bố chính thức rằng có thể thiết lập nhiều thẻ **h1**, tuy nhiên nếu làm vậy sẽ gây khó khăn cho việc nhận biết chủ đề của nội dung web page
- Có thể thiết thể ảnh bên trong thẻ tag **h1**

/iphone6/?color="white"

```
<h1>
  <img src="/images/iphone6_white.jpg" alt="Danh sách bao da cho điện thoại iPhone 6 được nữ giới ưa chuộm" />
</h1>
```

Với cách đặt ảnh như trên thì nó cũng được nhận diện như 1 phần của **h1** tag, do đó hãy mô tả chính xác ảnh bằng cách thêm nội dung vào thuộc tính _alt_ (văn bản thay thế).

### ★ Keyword truyền tải bởi TDH (Title Description H1)

Nếu bạn đặt từ khóa mình muốn SEO trong tất cả các thẻ TDH（Title 　 Description 　 H1）sẽ là cách đầu tiên giúp Google nhận biết chính xác từ khóa cần SEO.
Do đó, cần xem xét 3 thẻ trên có chứa từ khóa mình cần lên top không?

## Lưu ý với thẻ【img】và thuộc tính 【alt】

Bằng cách sử dụng thuộc tính _alt_ mô tả nội dung trong ảnh và video, thì người khiếm thị (Sử dụng tính năng đọc văn bản) hoặc người dùng có tốc độ mạng internet chậm cũng có thể dễ dàng nhận được thông tin về website của bạn, điều này được Google đánh giá rất cao.

Tham khảo source code bên dưới về **Google Search Console**
Nguồn: [https://support.google.com/webmasters/answer/114016?hl=vi](https://support.google.com/webmasters/answer/114016?hl=vi)

- Cách sử dụng không tốt thẻ **img** với thuộc tính alt

```html
<img src="puppy.jpg" alt="" />

<img
  src="puppy.jpg"
  alt="puppy dog baby 
dog pup pups puppies doggies pups litter puppies dog retriever 
 labrador wolfhound setter pointer puppy jack russell terrier 
puppies dog food cheap dogfood puppy food"
/>
```

Việc nhồi nhét quá nhiều từ khóa vào thuộc tính _alt_ dẫn tới việc bị google nhận diện thành Spam content.

- Cách sử dụng tối ưu thẻ **img** với thuộc tínhalt

```html
<img src="puppy.jpg" alt="puppy" />

<img src="puppy.jpg" alt="Dalmatian puppy playing fetch" />
```

Nếu có thể thì tốt nhất hãy mô tả bằng câu văn thay vì chỉ sử dụng 1 từ khóa cho các **img** tag.

### ★ Các hạng mục khác được khuyến khi khi sử dụng thẻ 【img】 (Không bắt buộc)

- Thống nhất file name và nội dung thuộc tính alt
- Có thể thiết lập nội dung trong alt mà không có khoảng trắng
- Cố gắng thiết lập mô tả cho ảnh sao cho gần với nội dung trong bức ảnh đó nhất có thể
- Các ảnh tương tự nhau thì nên để trong cùng 1 thư mục host
- Nếu một ảnh giống nhau được sử dụng ở nhiều nơi, thì hãy mô tả thật chi tiết ảnh đó trên website của mình, khi đó Google sẽ nhận diện ảnh của site bạn là original image, và hiển thị trên search result !

### ★ Khả năng index và thu thập dữ liệu ở cùng thời điểm

【Khả năng thu thập dữ liệu】
Để crawler của GoogleBot dễ dàng thu thập dữ liệu, chúng ta cần

- Cấu trúc, sử dụng thẻ HTML phải đúng chuẩn
- Với các page có nội dung liên quan cần có liên kết tới nhau, để đảm bảo khả năng crawler trải dài trên toàn bộ website

【Khả năng index - đánh chỉ mục tìm kiếm】
Nếu đã chuẩn bị sẵn các thuộc tính alt cho ảnh, âm thanh, video trên website của mình thì khi GoogleBot crawl sẽ index được chính xác nội dung của chúng.

## 【a】tag

Hãy thiết lập chuẩn xác anchor link (text), việc này sẽ giúp truyền tải thông tin tới Google dễ dàng hơn.

### Các implement có thể ảnh hưởng tới khả năng crawler

- Sử dụng javascript để di chuyển tới link cần vô (Google có khả năng nhận biết điều đó)
- Tìm kiếm bên trong website bằng cách gửi form
- Link content sử dụng FLASH

## 【rel="next" or "prev"】

Khi thiết lập Pagination cho website cần chỉ định thuộc tính rel với giá trị _next_ hoặc _prev_

### ★ rel=”prev/next” được xếp hạng ưu tiên hơn rel=”canonical”

Ví dụ vể rel="canonical" cho mọi người dễ hiểu

```html
<link rel="canonical" href="http://example.com/wordpress/seo-plugin/" />
```

Cho dù bạn có để link trên các page 2, 3, 4 về page 1 bằng thuộc tính canonical, thì next và prev vẫn được đánh giá ưu tiên hơn canonical, do đó với các URL không có parameter giống nhau như bên dưới sẽ không được tính là next và prev.

- Ví dụ chưa tối ưu

```
http://example.com/iphone7?page=1
http://example.com/iphone7?color=red&page=2
http://example.com/iphone7?page=3
http://example.com/iphone7?page=4
```

- Ví dụ tối ưu: được tính là next và prev

```
// page=
http://example.com/iphone7?color=red&page=1
http://example.com/iphone7?color=red&page=2
http://example.com/iphone7?color=red&page=3
http://example.com/iphone7?color=red&page=4

// viết tắt p=
http://example.com/foo.html
http://example.com/foo.html?p=2
http://example.com/foo.html?p=3

// Sử dụng URL path thay thế cho param page
http://example.com/foo/1/
http://example.com/foo/2/
http://example.com/foo/3/
```

### ★ Các điểm cần lưu ý

- 1 page chỉ được phép có 1 next và 1 prev
- Absolute path thì ngon hơn Relative path URL (Không bắt buộc)
- Trường hợp hiển thị kết quả tìm kiếm của 1 page có sử dụng điều kiện filter, thì ở trong trang điều kiện đó cũng cần bổ sung thuốc tính next và prev
- Nếu bạn không muốn hiển thị một page trên kết quả tìm kiếm, hãy học cách sử dụng canonical

## 【rel="nofollow"】

Với các target link có gắn thuộc tính rel="nofollow" sẽ không được search engine visit. Thuộc tính này xuất hiện ở thẻ meta và thẻ a.
Hơn nữa, khi GoogleBot visit target link, nó cũng tính toán độ tin cậy của các target link trên website và đánh giá thứ hạng site đó.

### ★ Khuyến khích sử dụng "nofollow" với link trỏ tới các website sau

- Các bảng tin và ô comment có thể được người dùng nhập
- Liên kết tới bookmark site
- Liên kết tới ranking site
- Liên kết khi nhận được đánh giá bằng tiền
- powerd by... link

### ★ Các liên kết có thể gây ảnh hướng xấu tới website cần lưu ý

- Các link mà người dùng không nhìn thấy, bị ẩn đi cũng như không click được
- Liên kết qua lại bằng các trang web hỗ trợ liên kết lẫn nhau
- Các liên kết đến các trang web được Google xác định là có mã nguồn độc hại

## Sử dụng【robots.txt】để không bị crawl thừa

Nếu không muốn search engin crawl trong những trường hợp dưới đây, hãy thiết lập file **robot.txt**

- Các web page có chất lượng thấp, các web page không muốn xuất hiện trên kết quả tìm kiếm

File **robots.txt** được đặt ở thư mục gốc (root directory) của website, Các Bot search engine sẽ tự động đọc và lấy ra.

Ví dụ về nội dung file **robots.txt**

```
User-Agent: *
Disallow: /*/matome/
Disallow: /ajax/*.json
Disallow: /image/
Disallow: /search
```

Hơn nữa Google cũng hỗ trợ tool kiểm tra file **robots.txt** : [Google robots.txt Tester](https://support.google.com/webmasters/answer/6062598?hl=vi)

## 【rel="noindex"】

Hãy sử dụng nó khi bạn có chủ ý muốn 1 page nào đó trên website của mình không xuất hiện trên kết quả tìm kiếm của Google.

### ★ Điểm khác biệt với robots.txt

Sử dụng **robots.txt** đồng nghĩa với việc không cho Bot Search Enginer thu thập dữ liệu cũng như xếp hạng page đó.

Trong khi sử dụng **noindex** thì sau một thời điểm nào đó khi link tới website của bạn được share nhiều trên mạng xã hội, thì SEO rank vẫn còn và link tới web page đó vẫn được xếp hạng.

### ★ Mục đích chính của việc sử dụng "noindex”

- Với các page chất lượng thấp, nếu có gắn thuộc tính **noindex** sẽ ko bị xếp hạng thấp website
- Support các page chưa được setting trong **robots.txt** cho tới thời điểm hiện tại
- 404 Page (Thiết lập ở các page trả về status lỗi 404)

_Cách thức setting:_

```
<meta name=”robots” content=”noindex”>
```

### ★ Cách kiểm tra tình trạng index của một website

Có thể dùng [Google Search Console - Index Status](https://www.google.com/webmasters/tools/index-status)
![image](https://qiita-image-store.s3.amazonaws.com/0/69647/8c1cc73b-969a-00c3-6712-ebc76333e717.png)

## Hiển thị Rich snippets

**Rich Snippets** là đoạn thông tin đặc biệt dùng để hiển thị các thông tin thêm có trong những bài viết đặc biệt (bài đánh giá, sản phẩm, ứng dụng, công thức nấu ăn, địa chỉ công ty..v.v..) trên các máy tìm kiếm (Google, Yahoo, Bing) nhằm cung cấp thêm những thông tin giá trị đến người tìm kiếm giúp họ xác định kết quả tìm kiếm mà họ đang cần. Nhìn vào kết quả tìm kiếm sau, ta thấy có một điều rất đặc biệt: Xuất hiện ảnh thumbnail trong kết quả :v

![](https://viblo.asia/uploads/bdc6e3b1-aaf9-411e-a032-31cc42214397.jpg)

**Rich Snippets** có 10 loại phổ biến sau:

- Author
- Breadcrumbs
- Event
- Organizations
- People
- Products
- Recipes
- Review
- Software Application
- Facebook Share

Việc sử dụng các markup bằng cấu trúc được công bố trên **schema.org** sẽ làm tăng khả năng hiển thị **rich snippet** trên kết quả tìm kiếm của google.
Hiện tại thì **rich snippet** không ảnh hưởng tới rank của 1 website, tuy nhiên có thể ảnh hưởng tới thứ hạng trong kết quả tìm kiếm: [Google Webmaster Central office-hours hangout](https://www.youtube.com/watch?v=QWL864VlW7I&feature=youtu.be)

Ví dụ về 1 page có hiển thị **snippets**

```html
<section itemscope itemtype="http://schema.org/Game">
  <h1>Monster Hunter Game Series</h1>
  <span itemprop="name">Monster Hunter Double Cross</span>
  <p itemprop="description">Latest Monhan Series with 6 large main Monsters</p>
  <div itemprop="author" itemscope itemtype="http://schema.org/Corporation">
    <p itemprop="name">CONAMI</p>
    <p itemprop="email">example@conamikan.jp</p>
  </div>
</section>
```

# Những lưu ý về URL (Đường dẫn)

## 【Soft 404】

Tình trang một page có status=200 nhưng nội dung page đó lại cho biết URL này không tồn tại được gọi là **soft 404**

Chi tiết thêm về lỗi này bạn có thể tham khảo tại đây: [https://support.google.com/webmasters/answer/181708?hl=vi](https://support.google.com/webmasters/answer/181708?hl=vi)

Sử dụng Google Search Console, để dễ dàng confirm lại các page dính lỗi **soft 404**
![](https://viblo.asia/uploads/3b7f2325-7f12-4bb5-92eb-ee7f346daa95.png)

Gần đây Google Bot có khả năng phân biệt được lỗi **soft 404**, nên sẽ ko có hình phạt nào được áp dụng với site dính lỗi này.

- Trả về status code = 404 khi có lỗi trong CakePHP

```
throw new NotFoundException();
```

Ngoài ra, bạn có thể tìm hiểu thêm về lỗi **soft 404** ở đây: [https://www.suzukikenichi.com/blog/does-google-penalize-your-site-for-having-soft-404/](https://www.suzukikenichi.com/blog/does-google-penalize-your-site-for-having-soft-404/)

## Chuẩn hóa URL

Việc hiển thị 1 web page có nội dung giống nhau nhưng với nhiều URL khác nhau trên trình duyệt xảy ra khá phổ biến. Tuy nhiên, nếu việc này xảy ra với Google search engine thì có thể website của bạn sẽ bị áp dụng các hình phạt làm giảm thứ hạng tìm kiếm. Chính vì lẽ đó chúng ta cần chuẩn hóa lại URL.

### ★ Các lợi ích có được khi quy chuẩn hóa đường dẫn

Giả sử: Việc url một website có chứa www và ko chưa www được coi là các page khác nhau
Vấn đề: Lúc này việc đánh giá rank cho website bị phân tán giữa các link có và ko có www
Hướng giải quyết: Có thể chuyển hướng (301 redirect) các page có www sang page ko có www

### ★ 301 Redirect

- Wiki: [List of HTTP status codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes)
- Khi thay đổi tên miền/url, hãy sử dụng chuyển hướng 301 sang đường dẫn mới
- Từ sau khi thiết lập 301 Redirect, có thể mất tới một tháng đẻ Bot Search crawl lại website

### ★ Ví dụ sử dụng 301 Redirect

- Sử dụng 301 Redirect trong việc có và không có **www** trên URL
- Loại bỏ việc thêm **index.html** vào sau URL
- Trường hợp **Pagination**　/search/?page=1 và /search/ hiển thị nội dung giống nhau
- Trường hợp có và ko có dấu slash (/) sau URL. Ex: /search/ và /search

Lưu ý khi code: tùy vào chức năng của trình duyệt web, nếu thực hiện điều hướng 301 từ 1 URL tới 1 URL nhất định thì việc di chuyển page này sẽ được lưu vào cache cho tới khi trình duyệt xóa nó đi.

## 【Canonical】

Cùng một nội dung tương tự nhau (Có thể là 1 bài viết được chia làm nhiều phần), thì không chỉ người dùng mà Google Bot cũng muốn biết bài viết nào là bài viết gốc, câu trả lời cho vấn đề này chính là thuộc tính **rel="canonical"**.

Mặt khác chắc hẳn bạn cũng gặp phải trường hợp Single Page và Search Page có chứa 1 lượng lớn nội dung trùng lặp. Nhờ việc thiết lập **canonical** cho 1 page, mà ta có thể ngăn ngừa được việc Google đánh tụt thứ hạng tìm kiếm từ nội dung bị trùng lặp

- Ví dụ khi website có 2 phiên bản cho Desktop và Mobile:

```html
<head>
  ...
  <link rel="canonical" href="http://www.example.com/" />
  ...
</head>
```

Ngoài **canonical**, còn có thể sử dụng đồng thời với **alternate** được giải thích chi tiết bên dưới.

### ★ Ví dụ về sử dụng Canonical

- Trên kết quả tìm kiếm xuất hiện nhiều page có content giống nhau
- Mobile page và Desktop page có nội dung tương tự nhau
- Thiết lập URL để Google Analytics tiến hành đo lường các thông số
- Khi công khai cùng 1 nội dung trên nhiều website
- Trường hợp không sử dụng 301 redirect
- Trường hợp sử dụng mirror site để giảm tải cho web/detect DDOS. (Tuyên nhiên việc này ko được khuyến khích sử dụng vì dễ bị nhận diện là spam)

## 【Alternate】

Thẻ **alternate** được khuyến khích sử dụng khi bạn có :

- Một phiên bản website được phiên dịch hoàn toàn sang một ngôn ngữ khác
- 2 trang với cấu trúc, nội dung tương tự nhau và chỉ có một vài điểm nhấn khác biệt về ngôn ngữ trong nội dung

**Ví dụ:**

- Website example.com

```html
<head>
  ...
  <link rel="alternate" href="http://example.com/" />
  ...
</head>
```

- Khi sử dụng **alternate**, chúng ta thông báo cho Bot biết website cho smart phone là sp.example.com.
- Khi sử dụng **canonical**, chúng ta thông báo cho Bot biết phiên bản website chính thức của hệ thống là example.com
- Website sp.example.com

```html
<head>
  ...
  <link rel="canonical" href="http://sp.example.com/" />
  ...
</head>
```

**canonical** dùng để thông báo với Search Engine đâu là page gốc (original page). Có thể ví như quan hệ n:1
**alternate** trở thành quan hệ 1:1 khi cùng tham chiếu tới **canonical** và **alternate**

Thuộc tính **canonical** và **alternate** trên website [https://ferret-plus.com/1426](https://ferret-plus.com/1426) đã giúp Bot Search Engine biết được phiên bản nào là website dành cho thiết bị di động.

## Cloaking

Cloaking là sự che đậy hay che dấu một cái gì đó. Trong kỹ thuật SEO thì cloaking ám chỉ hành động của webmaster che dấu bot của search engine như Google crawl các nội dung mà người dùng nhìn thấy, đồng thời đề xuất cho các cậu Bot nhìn thấy các nội dung được Onpage optimize tốt nhằm mục đích đạt được các vị trí cao trên Search Engine.

- Việc tồn tại các thông tin trên website mà hiển thị giữa GoogleBot và người sử dụng khác biệt nhau sẽ ảnh hưởng tới thứ hạng hiển thị của website trên kết quả tìm kiếm. (Website có hành vi này sẽ bị google áp dụng các hình phạt)
- Website khi truy cập = PC hiện ra thông báo「Hãy truy cập bằng smart phone」, dù cho khi User-Agent là smart phone truy cập có hiển thị chính xác đi chăng nữa cũng rất có thể bị Google hiểu là Cloaking ???
- Website ở tình trạng bị hack cũng có thể bị đưa vào trạng thái Cloaking, hãy thường xuyên quan sát log để tìm ra các hành động khả nghi và tiến hành deploy lại nếu cần.

## Đánh giá độ ổn định của URL

Các bộ máy tìm kiếm có tiêu chí để xếp hạng URL là: **URL đã cung cấp thông tin cho người sử dụng trong một thời gian dài bao lâu?**.
Do đó khi bạn thay đổi URL, sử dụng 301 Redirect thì cũng ko có gì đảm bảo là toàn bộ ranking của URL trên site cũ sẽ được chuyển hết sang URL site mới.

### ★ Các hạng mục cần kiểm tra khi thiết kế URL

- Có chứa ext của file như **.php** hay không ? Việc này sẽ gây ảnh hưởng nếu chuyển framework ví dụ từ CakePHP sang Rails chẳng hạn.
- Có thể dùng dấu **-** hoặc **\_** trong URL, tuy nhiên Google khuyến khích sử dụng dấu **-** để phân tách từ khóa
- Toàn bộ ký tự trong URL phải được viết thường
- URL dài cũng không vấn đề (Sẽ giải thích sau)
- URL không nên chia quá nhiều cấp, nằm sâu trong nhiều directory
- Chứa từ khóa thì càng tốt (Có thể chứa tiếng Nhật)
- URL không die cho dù sau này có áp dùng nhiều thay đổi SEO đi chăng nữa
- Không sinh ra duplicated content

### ★ Đảm bảo việc thiết kế URL không sinh ra nội dung trùng lặp

Web Page bên dưới sinh ra nội dung trùng lặp, dó đó kiểu thiết kế URL này không được khuyến khích
Ví dụ：Anime Home Page

- Hero list page
- All characters list page

Khi đó giả sử ta có nhân vật tên là "yamada", khi đó nội dung 2 trang sau là giống nhau và đều mô tả về "yamada"

- heros/yamada.html
- characters/yamada.html

Cùng 1 nội dung nhưng lại khác URL là một thiết kế tồi và bị xếp vào duplicated content.

## URL dài cũng không vấn đề

Theo Google công bố thì độ dài của URL có thể ngắn hoặc dài tùy ý

> Độ dài của URL thì không ảnh hưởng tới ranking
> Tuy nhiên cần đủ để nhận diện được URL

Mặc dù không ảnh hưởng tới SEO, tuy nhiên trình duyệt IE chỉ support URL có độ dài tối đa 2083 ký tự, nên hãy setting URL length `<= 2083`

### ★ Các khuyến khích về URL

- Vì URL là thứ hiển thị trên kết quả search, nên hãy chọn các từ đơn trong URL có liên quan tới nội dung bài viết
- Khi URL có chứa từ ngữ trùng với từ khóa mà user search thì sẽ được bôi đậm trên kết quả
- Search engine sử dụng dấu "**-**" để tách từ, nên URL cũng nên sử dụng dấu "**-**" để ngăn cách các từ khóa trong nó.

Mặt khác việc sử dụng quá nhiều GET parameter như ?color=2 trong URL có thể khiến URL khó nhớ, dễ nhầm lẫn, và khó chia sẻ. Dẫn tới việc truy cập phải URL không chính xác nếu không đủ parameter.

## Cấu trúc liên kết cần được chú trọng hơn cấu trúc thư mục

Chúng ta có 2 đường dẫn sau:

[https://viblo.asia/cau-truc-duong-dan-nao-tot-cho-seo-file-name-hay-thu-muc.html](https://viblo.asia/cau-truc-duong-dan-nao-tot-cho-seo-file-name-hay-thu-muc.html)
[https://viblo.asia/seo/seo-onpage/cau-truc-duong-dan-nao-tot-cho-seo-file-name-hay-thu-muc.html](https://viblo.asia/seo/seo-onpage/cau-truc-duong-dan-nao-tot-cho-seo-file-name-hay-thu-muc.html)

Như bạn đã biết, hai đường dẫn trên đều là 2 đường dẫn tối ưu cho SEO. Đường dẫn thứ nhất là đường dẫn kiểu file name và đường dẫn thứ hai là đường dẫn theo kiểu thư mục. Câu hỏi đặt ra ở đây là đường dẫn nào tốt hơn?

### ★ Nếu cấu trúc thư mục quá sâu có thể khiến Bot ko crawl được

Tham khảo link : [https://support.google.com/webmasters/answer/156184?hl=vi](https://support.google.com/webmasters/answer/156184?hl=vi)
Google Bot sẽ crawl theo thứ tự từ nông tới sâu, dó đó URL ở các cấp sâu mà không được liên kết tới bởi page nào trong site có thể rơi vào tình trạng được crawl chậm và không được đánh index.
Với tư cách là developer, bạn đừng quên tạo các link trong site internal liên kết tới các page quan trọng của site.

Lưu ý: Việc tạo cấu trúc thư mục đơn giản chỉ giúp cho Google Bot crawl dễ dàng hơn chứ không ảnh hưởng tới thứ hạng trên Search Result.

### ★ Cấu trúc liên kết ảnh hưởng tới SEO

Cấu trúc liên kết được tóm gọn trong câu sau: "Khi bạn click vào liên kết bao nhiêu lần cũng vẫn access được page đó".

Cấu trúc link nếu vượt quá 5 cấp có thể khiến Google index chậm. Về cơ bản chỉ nên setting dưới 4 cấp đổ lại.

Tham khảo: [http://s-supporter.hatenablog.jp/entry/seo-difference-of-the-hierarchy#](http://s-supporter.hatenablog.jp/entry/seo-difference-of-the-hierarchy#)ディレクトリ階層とリンク階層の違い

## Lưu ý khi thêm Parameter vào URL

Theo kỹ sư John Muelle từ Google thì việc thêm params vào URL của các dynamic page để dễ dàng thay đổi nội dung được khuyến khích.

> Just wanted to add that from Google's point of view, the clean, parameterized URL is generally preferred to any unnecessary URL-rewriting. If you want a nice-looking URL-line in search, use breadcrumb markup instead.

Tuy nhiên trên kết quả search thì với những page động sử dụng params để thay đổi nội dung cần thiết lập thêm **Canonical** để tránh xảy ra hiện tượng duplicated content.

## Dùng GET params sẽ làm giảm index

Việc sử dụng quá nhiều GET params có thể làm khả năng index giảm đi, do đó cần tránh thêm quá nhiều param là URL quá dài, hoặc thực hiển chuyển đổi url động sang url tĩnh với param ngắn hơn.

### ★ Chuyển đối URL tĩnh

Việc chuyển đổi URL động sang tĩnh có thể hiểu đơn giản như sau: loại bỏ bớt GET params, chuyển nó vào path của URL

**Ví dụ:**
Ta có 1 URL khá dài với 3 GET params

```
https://phocase.jp/iphone7/?color=3&material=3&category=cute
```

Ta sẽ đưa category vào path của URL, lúc này số lượng params chỉ còn là 2

```
https://phocase.jp/iphone7/cute/?color=3&material=3
```

### ★ Các điểm cần lưu ý khi chuyển đổi sang URL tĩnh

- Loại bỏ các params không cần thiết
- Không quản lý param theo session ID
- Thực hiển chuyển đổi các params có thẻ đưa vào URL path
- Không nên đưa quá nhiều param vào URL path dẫn tới URL quá dài, giảm khả năng index cũng như crawl
- URL càng có ý nghĩa càng tốt

### ★ Các thức đơn giản để thực chuyển đổi tĩnh

Để chuyển đổi sang URL tĩnh có thể implement lại routing của system, tuy nhiên cách đơn giản nhất là thiết lập lại file .htaccess

```
RewriteEngine On

RewriteRule http://phocase.jp/([0-9]+)/$　http://phocase.jp/?color=$1 [L,NC]
```

[How To Create Temporary and Permanent Redirects with Apache and Nginx](https://www.digitalocean.com/community/tutorials/how-to-create-temporary-and-permanent-redirects-with-apache-and-nginx)

# Các điểm cần lưu ý với Site content

## Site có số lượng index lớn

Theo nguồn tin chính thức từ Google thì việc 1 website có quá nhiều page không được chú trọng vào nội dung sẽ được coi là 1 website vô nghĩa, chỉ nên tập trung vào 1 số lượng page có nội dung được chú trọng thay vì tạo ra hàng loạt các page có nội dung nghèo nàn.

### ★ Site ranking

- Thông tin chỉ được tồn tại/sở hữu duy nhất bởi website
- Có chứ nhiều nội dung dễ hiểu như ảnh và video
- Mô tả thông tin chi tiết, rõ ràng và dễ hiểu

Khi implement các page động thì số lượng page được index sẽ tăng lên, do đó cần xác định trước số lượng tối đa page sẽ được sinh ra.

### ★ Cách thức đối ứng

- Sử dụng chức năng URL parameter trong Google Search Console
- Sử dụng noindex content bằng file robots.txt
  [Japanese search quality guidelines](https://valueagent.co.jp/blog/2959)

## Tồn tại nội dung hữu ích với First View không?

Khi truy cập 1 website mà ko thực hiện scroll xuống dưới, thì phạm vi người dùng quan sát được trên màn hình lúc này được gọi là **First view**

Về cơ bản First view có kích thước khoảng 500×950px thì cần lưu ý những điểm sau:

### ★ Các điểm cần lưu ý

- Không setting external link
- Setting keyword cho SEO vừa phải
- Thiết lập alt cho ảnh, và tên file ảnh phải có liên quan tới nội dung bức ảnh

## Các công cụ mà tác giả đang sử dụng

- [https://adwords.google.co.jp/KeywordPlanner](https://adwords.google.co.jp/KeywordPlanner)
- [http://www.related-keywords.com](http://www.related-keywords.com)
- [https://www.google.com/intl/ja_jp/analytics](https://www.google.com/intl/ja_jp/analytics)
- [https://www.similarweb.com](https://www.similarweb.com)
]]></description>
            <link>https://hungvn.com/blog/cac-ky-thuat-seo-toi-thieu-ma-developer-can-nam-vung-trong-lap-trinh-web</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cac-ky-thuat-seo-toi-thieu-ma-developer-can-nam-vung-trong-lap-trinh-web</guid>
            <pubDate>Sun, 01 Oct 2017 15:28:15 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tạo loading Facebook bằng CSS thật đơn giản!]]></title>
            <description><![CDATA[
Dạo gần đây nhà mình hay mất mạng, mà ai cũng biết rồi dân IT, Design, Gaming, XXX, mà không có internet thì hỡi ơi cứ như là sống ở thời kì đồ đá.

Nhưng cũng nhờ thế mà tình cờ phát hiện được cái loading hay hay của facebook, twitter, bitbucket ... nếu mạng bạn quá chậm nó sẽ show ra tương tự giống này.

[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/4i0dnfi0me_Screen%20Shot%202017-03-02%20at%2010.31.06%20AM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/4i0dnfi0me_Screen%20Shot%202017-03-02%20at%2010.31.06%20AM.png)

[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/jpoxotnryg_Screen%20Shot%202017-03-02%20at%204.13.50%20PM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/jpoxotnryg_Screen%20Shot%202017-03-02%20at%204.13.50%20PM.png)
Sau đây là chút tò mò và mô phỏng để có được sự nhấp nháy kì lạ đó.

<YouTube id="wAtI6ACXbM4" />

### Vẽ Photoshop cái khung

Bước này chỉ để chảnh chó là biết Photoshop thôi nha, chớ ai dùng gì vẽ cũng được, hoặc đếch cần vẽ cũng chẳng sao :D!

[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/vfjbxy99p5_Screen%20Shot%202017-03-03%20at%2011.06.34%20AM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/vfjbxy99p5_Screen%20Shot%202017-03-03%20at%2011.06.34%20AM.png)<a></a>

Mình chụp cái hình nó lại, mở cái gì đó lên check lại được mấy cái mã màu của nó.
Cụ thể là:

- Thumnail: **#f6f7f9**;
- background: **#e9ebee**;
- background line: **#ebedf0**;
- box-shadow: **#d0d1d5**;

còn thiếu màu trắng tinh của **trung tình** cho các box bự.
Các bác có thắc mắc vụ lấy mã màu gì không? Nói chung các bác lấy mã nào cũng được tại đang chém nên vẽ bậy đó thôi.

Okay, xong vụ lấy mã màu, giờ thì xác định vị trí cũng như kích thước của từng thành phần trong của cái box này.
[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/b816itugz9_Screen%20Shot%202017-03-03%20at%2011.11.55%20AM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/b816itugz9_Screen%20Shot%202017-03-03%20at%2011.11.55%20AM.png)<a></a>

Cụ thể là:

- Thumbnail: 40x40
- Line: height 6px còn width thì tuỳ chỉnh thấy đụp đụp là ổn nhé các bác
- Khoản cách của line: 13px, số hơi xui tí.
- Cái box bự: 520x325.

<YouTube id="GM8prMEsJiM" />

Thế là có dữ liệu thô rồi, nhào vào phần lên cúc trúc html nào.

### Lên cấu trúc HTML

Rồi bây giờ chúng ta tạo 1 thưc mục, tạo 1 file tên là **index.html** mở nó lên bằng editor nào mà bạn thích, rồi chiến:
[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/bicnul27yb_Screen%20Shot%202017-03-03%20at%2011.33.20%20AM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/bicnul27yb_Screen%20Shot%202017-03-03%20at%2011.33.20%20AM.png)<a></a>

Nghía qua cái box bằng đôi mắt không được **lé** của chúng ta thì các thành phần chính như sao:

- Cái box to **class="box-loading"**
- Cái thumbnail **class="box-thumbnail"**
- Có khoản 5 cái line với các kích thước khác nhau nên chúng ta có thể đặt tên là "box-line-xs, -sm, -df, -lg, -lgx"

```html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Loading-facebook</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div class="box-loading">
      <div class="box-thumbnail"></div>

      <div class="box-line-sm"></div>
      <div class="box-line-xs"></div>

      <div class="box-line-df"></div>
      <div class="box-line-lgx"></div>
      <div class="box-line-lg"></div>
    </div>
  </body>
</html>
```

<YouTube id="9O9c_c1FK7o" />

Okay vậy là xong rồi cái phần html nhé, quá nhanh và quá huy hiểm.

### Lên cấu trúc CSS

Đã done html rồi thì bây giờ ta tạo 1 file **style.css** nhé. Để tô màu chơi cho vui thôi.
Nhớ link vào file html nhé

```html
<link href="style.css" />
```

Sau đó ta mở file style.css và viết vào giống thế lầy.

```css
body {
  background: #e9ebee;
}
.box-loading {
  background: #fff;
  height: 325px;
  width: 520px;
  display: block;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  -o-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  border-radius: 3px;
  -o-border-radius: 3px;
  -moz-border-radius: 3px;
  -webkit-border-radius: 3px;
  margin: 0 auto;
}
```

Để có được kết quả là cái box:
[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/adbekb29q8_Screen%20Shot%202017-03-03%20at%2012.07.33%20PM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/adbekb29q8_Screen%20Shot%202017-03-03%20at%2012.07.33%20PM.png)<a></a>

> Canh chỉnh box content

<YouTube id="i239gN6nfGM" />

Phần box-shadow mình viết như thế để nó gần giống với mã màu của cái line trên facebook và cũng như là all device, để vào phần Sass các bạn sẽ thấy thú vị hơn ở chổ này nhé.

Tiếp đến là mấy cái line:

```css
body {
  background: #e9ebee;
}
// cái nào có class là box- thì nó sẽ nhận css
[class*="box-"] {
  height: 6px;
  width: 400px;
  background: #f6f7f9;
  margin-bottom: 13px;
  margin-right: 5px;
}

.box-loading {
  background: #fff;
  height: 305px;
  width: 500px;
  padding: 10px;
  display: block;
  box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  -o-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  -moz-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
  border-radius: 3px;
  -o-border-radius: 3px;
  -moz-border-radius: 3px;
  -webkit-border-radius: 3px;
  margin: 0 auto;
}

.box-thumbnail {
  height: 40px;
  width: 40px;
  float: left;
  margin-right: 20px;
  display: inline-block;
}
// chịu khó viết style cho từng line nhé
.box-line-sm {
  width: 120px;
  margin-top: 10px;
  margin-left: 50px;
}
.box-line-xs {
  width: 80px;
  margin-left: 50px;
}
.box-line-df {
  margin-top: 30px;
  width: 380px;
}
.box-line-lg {
  width: 200px;
}
.box-line-lgx {
  width: 450px;
}
```

[![alt text](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/2e5amwtrb6_Screen%20Shot%202017-03-03%20at%204.01.05%20PM.png)](https://s3-ap-southeast-1.amazonaws.com/kipalog.com/2e5amwtrb6_Screen%20Shot%202017-03-03%20at%204.01.05%20PM.png)<a></a>

<YouTube id="yxtX-CuIb7c" />

### Animation CSS loading

Các bạn thấy nãy giờ toàn là trò mèo đúng không? Giờ chúng ta mới vào phần trọng tâm của cái loading facebooking

<YouTube id="_jARHUUT4N0" />

```javascript
[class*="box-line"],
.box-thumbnail {
    animation: timeline; // tên của animation để truyền action
    animation-duration: 1s; // thời gian thực thi action
    animation-timing-function: linear; // hiệu ứng cho action, có nhiều lắm thực chất nó là cubic-bezier, ai muốn custom thì xem link này http://cubic-bezier.com
    animation-iteration-count: infinite; // số lần chạy action, mình cho nó vô tận luôn
    background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%); // gradient cho từng cái line
    background-size: 800px auto; // kích thước của cái bóng mờ mờ (gradient)
}
// hành động của animation cho nó chạy từ trái sang phải
@keyframes timeline {
  0% {
    background-position: -350px 0;
}
  100% {
    background-position: 400px 0; }
}
```

### Recode CSS thành SASS

Cái này cũng chẳng có gì hấp dẫn lắm, nhưng viết luôn cho bác nào thích chơi với thằng thứ ba thì chơi:

<YouTube id="kXOlIGH6L6Y" />

```scss
body {
  background: #e9ebee;
}

[class*="box-"] {
  height: 6px;
  width: 400px;
  background: #f6f7f9;
  margin-bottom: 13px;
  margin-right: 5px;
}
@mixin box-shadow($box_shadow) {
  box-shadow: $box_shadow;
  -o-box-shadow: $box_shadow;
  -moz-box-shadow: $box_shadow;
  -webkit-box-shadow: $box_shadow;
}
@mixin border-radius($border_radius) {
  border-radius: $border_radius;
  -o-border-radius: $border_radius;
  -moz-border-radius: $border_radius;
  -webkit-border-radius: $border_radius;
}
.box {
  &-loading {
    background: #fff;
    height: 305px;
    width: 500px;
    padding: 10px;
    display: block;
    margin: 0 auto;
    @include box-shadow(0 0 0 rgba(0, 0, 0, 0.1));
    @include border-radius(3px);
  }
  &-thumbnail {
    height: 40px;
    width: 40px;
    float: left;
    margin-right: 20px;
    display: inline-block;
  }
}
.box-line {
  &-sm {
    width: 120px;
    margin-top: 10px;
    margin-left: 50px;
  }
  &-xs {
    width: 80px;
    margin-left: 50px;
  }
  &-df {
    margin-top: 30px;
    width: 380px;
  }
  &-lg {
    width: 200px;
  }
  &-lgx {
    width: 450px;
  }
}

[class*="box-line"],
.box-thumbnail {
  animation: timeline;
  animation-duration: 1s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
  background: linear-gradient(to right, #eeeeee 8%, #dddddd 18%, #eeeeee 33%);
  background-size: 800px auto;
  background-position: 100px 0;
}
@keyframes timeline {
  0% {
    background-position: -350px 0;
  }
  100% {
    background-position: 400px 0;
  }
}
```

Các bác có thể xem trên này luôn cho tiện nhá.

<Codepen url="https://codepen.io/tuds/embed/RpaJNO" height="500px" />

### Lời kết

Okay thế là có cái loading của facebook rồi, mặt dù là hàng face nhưng hi vọng cũng có thế giúp ít cho bác nào muốn dùng.

Lưu ý:

Bạn nên đọc lại kỹ một chút về các thuộc tính
**background: linear-gradient, background-size, background-position và các thuộc tính animation, trước khi làm**
Nên tự gõ, đừng copy rồi paste, vì như thế bạn chẳng nhớ gì đâu.
]]></description>
            <link>https://hungvn.com/blog/tao-loading-facebook-bang-css-that-don-gian</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tao-loading-facebook-bang-css-that-don-gian</guid>
            <pubDate>Wed, 27 Sep 2017 11:31:18 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Một bộ phim hoạt hình giới thiệu về Redux]]></title>
            <description><![CDATA[
One thing that causes even more confusion than Flux is the difference between Flux and Redux, a pattern that was inspired by Flux. In this article I’ll explain the differences between the two.

If you haven’t read the [last article about Flux](https://code-cartoons.com/a-cartoon-guide-to-flux-6157355ab207), you should do that first.

### Why change Flux?

Redux solves the same problems as Flux, plus some.

Just like Flux, it makes state changes in apps more predictable. If you want to change state, you have to fire off an action. There’s no way to change the state directly because the thing holding the state (the store) only has a getter, not setters. These basics of Flux and Redux are pretty similar.

So why a different pattern? Redux creator Dan Abramov saw an opportunity to improve on Flux. He wanted better developer tools. He saw that if you moved a couple of things around, you could make better developer tools possible, but still have the same predictability that Flux gives you.

He wanted hot reloading and time travel debugging (there’s [another cartoon to explain these](https://medium.com/@linclark/hot-reloading-and-time-travel-debugging-what-are-they-3c8ed2812f35)). But there were some problems which made developer tooling hard to do with Flux.

#### Problem 1: The code for stores can’t be reloaded without wiping out the state

In Flux, the store contains two things:

1.  The state change logic
2.  The current state itself

Having these two on the same object is a problem for hot reloading. When you reload the store object to see the effect that the new state change logic has, you lose the state that the store is holding on to. Plus, you mess up the event subscriptions that tie the store to the rest of the system.

![](https://cdn-images-1.medium.com/max/1600/1*L66K9uCQjjHmpAwT-a9C5Q.png)

**Solution** Separate these two functions. Have one object that holds on to the state. This object doesn’t get reloaded. Have another object that contains all of the state change logic. This object can be reloaded because it doesn’t have to worry about holding on to any state.

![](https://cdn-images-1.medium.com/max/1600/1*nBsGCWmJTR-Zj7aXeIE8yg.png)

#### Problem 2: The state is being rewritten with every action

In time travel debugging, you keep track of each version of a state object. That way, you can go back to an earlier state.

Each time the state is changed, you need to add the old state to an array of previous state objects. But because of the way JavaScript works, simply adding the variable to the array won’t work. This doesn’t create a snapshot of the object, it just creates a new pointer to the same object.

To make it work, each version needs to be an entirely separate object so that you aren’t accidentally changing past versions.

![](https://cdn-images-1.medium.com/max/1600/1*4zODv5vgvKsi6Ts7TihsoA.png)

**Solution**
When an action comes in to the store, don’t handle it by changing the state. Instead, copy the state and make changes to the copy.

![](https://cdn-images-1.medium.com/max/1600/1*wLRhZ0wtI0duLsigdxL1CA.png)

#### Problem 3: There aren’t good places for third-party plugins to jump in

When you’re making developer tools, you need to be able to write them generically. A user should be able to just drop the tool in without having to custom fit their own code around it.

For this to work, you need extension points… places where the code expects to have things added to it.

An example is logging. Let’s say you want to console.log() every action as it comes in, and then console.log() the state that results from it. In Flux, you’d have to subscribe to the dispatcher’s updates and to updates from each store. But that’s custom code, not something a third-party module can easily do.

![](https://cdn-images-1.medium.com/max/1600/1*MG736zGtLMBbSkhwu4D3cA.png)

**Solution**
Make it easy to wrap parts of the system in other objects. These other objects add their bit of functionality on top of the original. You can see these kinds of extension points in things like “enhancers” or “higher order” objects, as well as middleware.

In addition, use a tree to structure the state change logic. This makes it so the store only emits one event to notify the views that the state has changed. This event comes after the whole state tree has been processed.

![](https://cdn-images-1.medium.com/max/1600/1*5JaZSc3Jsn9PJY7daEDVDA.png)

_Note: With these problems and solutions, I‘m focusing on the developer tooling use case. These changes help in other use cases, too. On top of that, there are other differences between Redux and Flux. For example, Redux also reduces boilerplate and it makes it easier to reuse logic in the store. Here’s a list of some other_ [_upsides to Redux_](http://stackoverflow.com/a/32920459)_._

So let’s see how Redux makes these things possible.

### The new cast of characters

The cast of characters changes a little bit from Flux to Redux.

#### Action creators

![](https://cdn-images-1.medium.com/max/1200/1*Uljrrh4Z7UiUwk8AjUO9PA.png)

Redux keeps the action creator from Flux. Whenever you want to change the state of the application, you shoot off an action. That’s the only way that the state should be changed.

As I said in the [article on Flux](https://code-cartoons.com/a-cartoon-guide-to-flux-6157355ab207), I think of the action creator as a telegraph operator. You go to the action creator knowing basically what message you want to send, and then the action creator formats that in a way that the rest of the system can understand.

Unlike Flux, action creators in Redux do not send the action to the dispatcher. Instead, they return a formatted action object.

#### The store

I described stores in Flux as over-controlling bureaucrats. All state changes must be made personally by a store and have to go through the action pipeline, instead of being requested directly. The store in Redux is still controlling and bureaucratic, but it’s a little bit different.

![](https://cdn-images-1.medium.com/max/1200/1*Gztc7THzxzOgJmGvJ95IQA.png)

In Flux, you can have multiple stores. Each store has its own little fiefdom, and it is in total control. It holds on to its little slice of state, and has all the logic for changing that little slice of state.

The Redux store tends to delegate more. And it has to. In Redux, there is only one store… so if it did everything itself, it would be taking on too much work.

Instead, it takes care of holding on to the whole state tree. It then delegates the work of figuring out what state changes need to happen. The reducers, headed up by the root reducer, take on this task.

You might have noticed there’s no dispatcher. That’s because, in a bit of a power grab, the store has also taken over dispatching.

#### The reducers

When the store needs to know how an action changes the state, it asks the reducers. The root reducer takes charge and slices the state up based on the state object’s keys. It passes each slice of state to the reducer that knows how to handle it.

![](https://cdn-images-1.medium.com/max/1200/1*Vocy_6Gl9PbFlCIJsE9r3A.png)

I think of the reducers as a department of white-collar workers who are a little overzealous about photocopying. They don’t want to mess anything up, so they don’t change the state that has been passed in to them. Instead, they make a copy and make all their changes on the copy.

This is one of the key ideas of Redux. The state object isn’t manipulated directly. Instead, each slice is copied and then all of the slices are combined into a new state object.

The reducers pass their copies back to the root reducer, which pastes the copies together to form the updated state object. Then the root reducer sends the new state object back to the store, and the store makes it the new official state.

If you have a small application, you might only have one reducer making a copy of the whole state object and making its changes. Or if you have a large application, you might have a whole tree of reducers. This is another difference between Flux and Redux. In Flux, the stores aren’t necessarily connected to each other and they have a flat structure. In Redux, the reducers are in a heirarchy. This hierarchy can have as many levels as needed, just like the component hierarchy.

#### The views: smart and dumb components

Flux has controller views and regular views. The controller views act as middle managers, managing the communication between the store and their child views.

![](https://cdn-images-1.medium.com/max/1200/1*TgCkFcjlD9SxSrMvVX3DrA.png)

In Redux, there’s a similar concept: smart and dumb components. The smart components are the managers. They follow a few more rules than the controller views, though:

- Smart components are in charge of the actions. If a dumb component underneath them needs to trigger an action, the smart component passes a function in via the props. The dumb component can then just treat that as a callback.
- Smart components do not have their own CSS styles.
- Smart components rarely emit DOM of their own. Instead, they arrange dumb components, which handle laying out DOM elements.

Dumb components don’t depend on action files directly, since all actions are passed in via props. This means that the dumb component can be reused in a different app that has different logic. They also contain the styles that they need to look reasonably good (though you can allow for custom styling — just accept a style prop and merge it in to the default styles).

#### The view layer binding

![](https://cdn-images-1.medium.com/max/1200/1*D1RcVrMV2rp6AH9hk5xZ8g.png)

To connect the store to the views, Redux needs a little help. It needs something to bind the two together. This is called the view layer binding. If you’re using React, this is react-redux.

The view layer binding is kind of like the IT department for the view tree. It makes sure that all of the components can connect to the store. It also takes care of a lot of technical details so that the rest of the hierarchy doesn’t have to understand them.

The view layer binding introduces three concepts:

1.  The Provider component: This is wrapped around the component tree. It makes it easy for the root component’s children to hook up to the store using connect().
2.  connect(): This is a function provided by react-redux. If a component wants to get state updates, it wraps itself using connect(). Then the connect function will set up all the wiring for it, using the selector.
3.  selector: This is a function that you write. It specifies what parts of the state a component needs as properties.

#### The root component

![](https://cdn-images-1.medium.com/max/1200/1*JXPeiNP-it60-QYKb-p2eQ.png)

All React applications have root components. This is just the component at the top level of the component hierarchy. But in Redux applications, this component takes on more responsibility.

The role it plays is kind of like a C-level executive. It puts all of the teams in place to tackle the work. It creates the store, telling it what reducer to use, and brings together the view layer binding and the views.

The root component is pretty hands-off after it initializes the app, though. It doesn’t get caught up in the day-to-day concerns of triggering rerenders. It leaves that to the components below it, assisted by the view layer binding.

### How they all work together

Let’s see how these parts work together to create a functioning app.

#### The setup

The different parts of the app need to be wired up together. This happens in setup.

1\. **Get the store ready.** The root component creates the store, telling it what root reducer to use, using createStore(). This root reducer already has a team of reducers which report to it. It assembled that team of reducers using combineReducers().

![](https://cdn-images-1.medium.com/max/1600/1*8_fU31-jNQnQ0dp-wplm5w.png)

2\. **Set up the communication between the store and the components.** The root component wraps its subcomponents with the provider component and makes the connection between the store and the provider.

The Provider creates what’s basically a network to update the components. The smart components connect to network using connect(). This ensures they’ll get state updates.

![](https://cdn-images-1.medium.com/max/1600/1*NYMutQLW8TcEgbO8VNeqHA.png)

3\. **Prepare the action callbacks.** To make it easier for dumb components to work with actions, the smart components can setup action callbacks by using bindActionCreators(). This way, they can just pass down a callback to the dumb component. The action will be automatically dispatched after it is formatted.

![](https://cdn-images-1.medium.com/max/1600/1*aVoD3gGddKUy3VCxwylthQ.png)

#### The data flow

Now that the application is set up, the user can start interacting with it. Let’s trigger an action to see the data flow.

![](https://cdn-images-1.medium.com/max/1600/1*GNDs7SY53lEhp7mX8V25lw.png)

1\. The view requests an action. The action creator formats it and returns it.

![](https://cdn-images-1.medium.com/max/1600/1*p4EkWE_8upZ97Z0IapKDcQ.png)

2\. The action is either dispatched automatically (if bindActionCreators() was used in setup), or the view dispatches the action.

![](https://cdn-images-1.medium.com/max/1600/1*zmFp3bmDq7b6Bvlo8Ineag.png)

3\. The store receives the action. It sends the current state tree and the action to the root reducer.

![](https://cdn-images-1.medium.com/max/1600/1*zrsSoAAyf4pqTMHiA6P8Ww.png)

4\. The root reducer cuts apart the state tree into slices. Then it passes each slice to the subreducer that knows how to deal with it.

![](https://cdn-images-1.medium.com/max/1600/1*-S_dYe6BoQBgwSRpF7Hriw.png)

5\. The subreducer copies the slice and makes changes to the copy. It returns the copy of the slice to the root reducer.

![](https://cdn-images-1.medium.com/max/1600/1*_R-rGNfKr2Xu2FlXNZNPJg.png)

6\. Once all of the subreducers have returned their slice copies, the root reducer pastes all of them together to form the whole updated state tree, which it returns to the store. The store replaces the old state tree with the new one.

![](https://cdn-images-1.medium.com/max/1600/1*bUMekI8QlEfFxSBCuVuIkw.png)

7\. The store tells the view layer binding that there’s new state.

![](https://cdn-images-1.medium.com/max/1600/1*x6vBvUlFJktJqty56jr0QQ.png)

8\. The view layer binding asks the store to send over the new state.

![](https://cdn-images-1.medium.com/max/1600/1*qGatznV4QujuxGe49YfX5A.png)

9\. The view layer binding triggers a rerender.

![](https://cdn-images-1.medium.com/max/1600/1*Je2mow8mjYLngXreGGlIEg.png)

So that’s how I think of Redux and its differences from Flux. Hope it helps!

---

### Coming up next

I’m making a list of topics. If you have any suggestions, or there are any parts of the React ecosystem that you find confusing and you’d like to see explained, let me know on [Twitter](https://twitter.com/codecartoons).

[![](https://cdn-images-1.medium.com/max/1200/1*b4pDY7WpzfoGJ2IeRnSiYQ.png)](https://leanpub.com/codecartoons-react)[![](https://cdn-images-1.medium.com/max/800/1*Vhx6UMeHXRPAEOGaPq8vQA.png)](https://tinyletter.com/codecartoons)[![](https://cdn-images-1.medium.com/max/800/1*_oQtFJQYeeOkz4T81Sg4dA.png)](https://twitter.com/codecartoons)

### Resources

- [Redux docs](http://rackt.org/redux/index.html)
- [Dan Abramov’s React Europe talk](https://www.youtube.com/watch?v=xsSnOQynTHs)
- [The Evolution of Flux Frameworks](https://medium.com/@dan_abramov/the-evolution-of-flux-frameworks-6c16ad26bb31)
- [Smart and Dumb Components](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0)
- [The upsides of using Redux](http://stackoverflow.com/a/32920459)
- [The downsides of using Redux](http://stackoverflow.com/a/32916602)
- [JS Jabber: The Evolution of Flux Libraries with Andrew Clark and Dan Abramov](https://devchat.tv/js-jabber/181-jsj-the-evolution-of-flux-libraries-with-andrew-clark-and-dan-abramov)
]]></description>
            <link>https://hungvn.com/blog/mot-bo-phim-hoat-hinh-gioi-thieu-ve-redux</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mot-bo-phim-hoat-hinh-gioi-thieu-ve-redux</guid>
            <pubDate>Fri, 22 Sep 2017 14:25:25 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Redux thật là đơn giản (Phần 2)]]></title>
            <description><![CDATA[
### Redux với React Native

![](https://cdn-images-1.medium.com/max/1600/1*49G6uGo35MbTX5n7or6zuA.jpeg)

> Bài trước [**_Nguyên Lý của Redux_**](https://medium.com/innovatube/redux-th%E1%BA%ADt-l%C3%A0-%C4%91%C6%A1n-gi%E1%BA%A3n-ph%E1%BA%A7n-1-76a3fa2c31ab)
> các bạn đã nắm được cơ bản phần lý thuyết về Redux và dùng cho việc gì, sau đây
> chúng ta sẽ đi vào áp dụng nó với **React** hoặc React Native, ở đây mình chọn
> **React Native** vì nó vẫn đang còn khá HOT :D (Thực ra React hay React Native
> thì đều dùng Redux là y hệt nhau)

Đầu tiên các bạn vào link:[https://facebook.github.io/react-native/docs/getting-started.html](https://facebook.github.io/react-native/docs/getting-started.html) để làm theo và tạo 1 project với React Native.

_Lưu ý: Máy phải được cài sẵn_ **_yarn (_**[https://yarnpkg.com/en/](https://yarnpkg.com/en/)) hoặc dùng npm sau khi đã cài **node**, vì nếu cài yarn thì nó sẽ đồng thời cài node luôn cho bạn.

#### Phần 1: Tạo giao diện màn hình với React Native

Sau khi install xong, tạo thêm thư mục src -> file Main.js như sau:

![](https://cdn-images-1.medium.com/max/1600/1*NFjZttazBbGCbcf2lfsUEQ.png)

Ở đây mình sẽ minh họa tạo chức năng hết sức đơn giản là **Bấm — Tăng — Giảm 1 số** dùng React Native + Redux có màn hình hiển thị lên như sau:

![](https://cdn-images-1.medium.com/max/1600/1*UbvASuQS5ASxh8reRU6C8g.png)

Main.js

<Gist id="5e0e74a531f6637ba4c7e1c89f53e27f" />

Trong thư mục components ta tạo thêm 1 component có tên **Button**.js, thực tế bạn không cần phải viết hẳn 1 component chỉ render mỗi cái Button như này, do mình muốn tách nhỏ component nên tạm lấy ví dụ viết 1 component con riêng ra. (trong component này mình có dùng react-native-elements cài đặt nó qua yarn bằng lệnh sau:yarn add react-native-elements

<Gist id="f5b5be1a8b2b691132fd379acef13b3a" />

Component để hiển thị text number:

<Gist id="54801151c4a99c165358812cfe539e12" />

Okay tới đây coi như xong giao diện, như vậy bạn đã có 1 app counter khá đơn giản :D và hoàn toàn có thể làm dùng React Native đơn giản hơn nhiều, nhưng để hiểu về Redux thì chúng ta nên bắt đầu từ việc đơn giản đã.

#### Phần 2: Cài đặt Redux

**Step1:** **install Redux, React-Redux dependencies**

yarn add redux react-redux

**Step 2:** **Tạo cấu trúc thư mục project như hình:**

![](https://cdn-images-1.medium.com/max/1600/1*zGivefFkBikPcUMfF6Tizg.png)

3 nhân tố của Redux là **actions**, **reducers** và **store** tương ứng với 3 thư mục trong project.

#### **actions:**

- index.js chứa các action (nó sẽ export ra cho các class có thể gọi tới các function bên trong nó)

<Gist id="377b80d980e269af5dc4fdbd7f463076" />

- types.js định nghĩa các hằng số về kiểu của actions:

<Gist id="518d34a4f221f88f471fc6ea1827a97f" />

#### reducers:

- Tạo 1 reducer **_counterReducer_**: làm nhiệm vụ update state counter mỗi khi có action click

<Gist id="f17d4c184b9c5e997218bdcd6548b5d0" />

- Tiếp theo tạo file index.js, file này có nhiệm vụ **combine** các **reducers** con thành 1 **reducer** duy nhất để đưa vào store

<Gist id="1cec9897584824c616ff473d75b6628a" />

#### Store:

tạo 1 file index.js trong thư mục store. (Mình có config thêm redux-devtools-extension để tiện debug và xem store khi redux hoạt động trên extention của chrome).

<Gist id="8133759e2d6ffb405a51d23f90c3b49d" />

**Step 3: connect React component với store của Redux**

Việc cần làm là làm sao để kết nối toàn bộ components của app với **store** của Redux.

Thư viện **react-redux** đã cung cấp 1 thằng có tên **Provider** để làm cầu nối cho React và Redux, chúng ta chỉ việc bọc nó bao ngoài root component của React và truyền 1 tham số duy nhất là **store** vào (store đã được tạo ở thư mục store và được import vào file này).

<Gist id="11800a8f9c828bf7353fc89cfabea70e" />

**Step 4: Gọi 1 action từ 1 component và map data từ store ra View**

Quay lại bài trước như đã biết thì flow của redux:

> action → reducer → store → View

3 bước đã thực hiện xong ở trên, việc còn lại là store và View tương tác như nào, câu hỏi đặt ra là :

- Phát đi 1 action từ component → store như thế nào?
- Cập nhật data thay đổi từ store → View ra sao?

Nhiệm vụ quan trọng này được thực hiện bởi hàm **_connect()_** trong react-redux.

![](https://cdn-images-1.medium.com/max/1600/1*Oc-Ee1lE8mFETwl4tvzoVg.png)

Hàm connect() có 2 tham số:

- mapDispatchToProps(dispatch) nhiệm vụ map hàm dispatch() của store trở thành 1 thuộc tính của props của component đó, cụ thể ở code bên dưới thì actions chính là 1 props của component đó và giờ muốn phát đi 1 action ta chỉ việc gọi this.props.actions.tên*action*

<Gist id="22c3b3169bc5ce92d86e17e4e5967d23" />

- mapStateToProps(state) nhiệm vụ hết sức đơn giản giống như cái tên của nó, biến các state từ store thành props của component và sau đó show ra View

<Gist id="e953692d8b678ba28ed01d21f8bebadd" />

Để đơn giản và ngắn gọn hơn ta sẽ bỏ đi hàm mapDispatchToProps(dispatch) và thay bằng việc truyền trực tiếp actions vào hàm connect() cuối cùng sẽ là:

connnect(mapStateToProps, actions)(COMPONENT)

Quay trở lại code React Native ở trên, ở phần View ta có:

**main.js**

<Gist id="6bf68818ccb0c4f270a80b5534eb6a74" />

Giải thích:

- Actions được import từ thư mục actions → được truyền vào là tham số thứ 2 của hàm connect()
- Mỗi khi button đc bấm thì ta gọi tới hàm handle tương ứng để xử lý actions, nhớ rằng đã thực hiện connnect(null, actions) ở trên thì bây giờ các actions export ra từ file index trong thư mực actions trở thành các thuộc tính của props trong component Main.js → khi gọi tới action thì ta chỉ việc gọi this.props.action*name_tương*ứng\_

Tiếp theo là hiển thị ra **View** ở component **_child.js_**

<Gist id="e594ff32394bdcaada46513ab6476ae1" />

Ở file này ta vừa gán thuộc tính _counter : state.counter_ lúc này counter cũng trở thành 1 props của component Child → gọi show ra View ta chỉ cần gọi như thông thường `<Text>{this.props.counter}</Text>`

Như vậy là 1 app **counter** đơn giản bằng React Native và Redux đã thực hiện xong tóm lại flow như sau:

> 1\. View gồm 2 button **_Increase_** và **_Decrease_** và 1 component hiển thị number

> 2\. Khi Button được click → dispatch() tới 1 **_action creator_** có tên counterIncrease()

> 3\. counterIncrease() sẽ tạo ra 1 **Object** (Trong redux action phải là 1 plain object có thuộc tính là type và payload, type là bắt buộc) ở đây chỉ có 1 thuộc tính `{type:"INCREASE"}` sau đó nó truyền tới `counterReducer()` để xử lý.

> 4\. `counterReducer(state, action) => kiểm tra xem action có kiểu type = "increase" trả ra 1 state mới là: `state + 1` (state của redux là immutable)

> 5 ở component View(**Child**) hiển thị number ta sẽ dùng hàm mapStateToProps(state) đẻ nhận state là counter rồi update vào View.

![](https://cdn-images-1.medium.com/max/1600/1*T7GbIXCBQIoayv2A6EUs7Q.png)

→ App đã chạy ngon lành :D

Giả sử bây giờ yêu cầu bài toán có thay đổi chút như sau:

- Nếu click vào **_nút tăng hoặc giảm mà sau 1s_** con số mới thay đổi.
- Nâng cao hơn chút là **_nếu click vào button increase number thì number chạy từ 0 cho tới 1 con số bất kỳ trong khoảng 1s rồi dừng lại._**

Bình thường ở bài toán trên ta bấm nút thì ngay lập tức action đáp trả kết quả, nhưng trong thực tế có nhiều bài toán ko lập tức có thay đổi luôn điển hình như call api tới server để fetch data, thì phải mất 1 lúc kết quả mới được trả về. Hay như bài toán bấm nút thì sau 1s mới thay đổi → thì những điều này người ta gọi đó là side-effect .

Như đã biết thì Redux yêu cầu 1 object được trả ra phải là Plain object: `{type: ACTION_TYPE, payload:params}` và reducer phải là pure function,hay nói cách khác là hoàn toàn ko có side-effect.

Okay có lẽ bài thứ 2 về redux đến đây là dài rồi :))

Mình sẽ giải quyết vấn đề side-effect ở bài sau dùng Redux-middleware

Hẹn gặp lại các bạn về bài cuối của Redux.

> **Source code ví dụ trên:** check out branch lesson_2

[https://github.com/tridungbk2010/react-native-class](https://github.com/tridungbk2010/react-native-class)
]]></description>
            <link>https://hungvn.com/blog/redux-that-la-don-gian-phan-2</link>
            <guid isPermaLink="true">https://hungvn.com/blog/redux-that-la-don-gian-phan-2</guid>
            <pubDate>Fri, 22 Sep 2017 14:13:23 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Redux thật là đơn giản! (Phần 1)]]></title>
            <description><![CDATA[
### Nguyên lý cơ bản của Redux

Redux nổi lên trong vòng 2 năm nay như 1 hiện tượng, nó thậm chí thay thế luôn kiến trúc Flux của Facebook dùng cho React, và hiện tại Facebook cũng khuyến cáo dev chuyển qua dùng Redux vì nhiều ưu điểm được cải tiến từ Flux.

Mặc dù nó ko còn tính thời sự như hơn 1 năm trước nhưng mình vẫn quyết định viết series Redux để giúp các bạn mới học React và Redux tiếp cận dễ dàng hơn.

**Series gồm 3 phần:**

> Phần 1: **Nguyên lý cơ bản của Redux**

> Phần 2: [**Cài đặt và sử dụng với React Native**](https://medium.com/innovatube/redux-v%E1%BB%9Bi-react-native-63ea25062084)

> Phần 3: **Redux-middleware (Thunk, Saga, Observable) nên dùng cái nào?**

**_Mời các bạn đón đọc!_**

![](https://cdn-images-1.medium.com/max/1600/1*XHMeHrC4tdwTSHWRalm_lQ.png)

**Lịch sử Redux (Câu chuyện vui)**

> Năm Quý Tị (2013), Facebook gia tộc bố cáo thiên hạ rằng Ăn Gô La đại pháp (Angular) của Google gia tộc chậm chạp, nặng nề, cho xuất thế một bộ chiêu thức gọi là Rối An Tâm Pháp (React).

> Thế nhưng Rối An Tâm Pháp lại chỉ là một bộ tâm pháp cường thân kiện thể, không thể dùng để rèn luyện nội công (chỉ là một library để render view). Do đó, không lâu sau Facebook gia tộc tiếp tục cho ra đời một bộ tâm pháp cơ bản (kiến trúc thiết kế) và một công pháp cùng tên là Phờ Lắc thần công (Flux). Nghe đồn Rối An Tâm Pháp và Phờ Lắc Thần Công kết hợp lại sẽ thành tuyệt học dời non lấp bể, không gì không làm đc. Nhân sĩ giang hồ (coder) vốn nhẹ dạ cả tin lại rủ nhau tu luyện.

> Phờ Lắc thần công rối rắm khó học, nhân sĩ 10 phần học thì 4–5 phần tẩu hỏa nhập ma, phần còn lại cũng trầy da tróc vẩy mà công lực cũng chẳng được như lời Facebook gia tộc quảng cáo.

> Bấy giờ có một nhân sĩ giang hồ tự là Đan (Dan Abramov), đang tu luyện đồng thời Phờ lắc thần công và Ê La thần công (Elm) mới nhận ra rằng hai môn võ công có nhiều điểm chung, chỉ khác chiêu thức, Đan bèn nảy ra ý định hợp nhất hai môn này lại. Không lâu sau (5/2015), Đan cho xuất thế một bộ công pháp mang tên Rì Đắt thần công (Redux), mang ưu điểm của cả hai môn võ công đồng thời loại bỏ những phức tạp dư thừa của Phờ Lắc thần công.

> Nhân sĩ giang hồ nghe vậy mừng lắm, thế là lại kéo nhau đi học Rì Đắt, còn Đan thì được Facebook
> gia tộc mời về làm tộc nhân.

> Trích [“JavaScript Lược Sử Giang Hồ”](https://toidicodedao.com/2016/08/18/js-truyen-ki-chuong-2-vo-lam-day-song/)

Đọc qua đoạn đậm màu sắc kiếm hiệp ở trên chắc các bạn phần nào cũng hình dung được Redux sinh ra để làm gì đúng ko?

#### **1\. Redux sinh ra để làm gì?**

Do yêu cầu cho các ứng dụng single-page sử dụng Javascript ngày càng trở lên phức tạp thì code của chúng ta phải quản lý nhiều state hơn. State có thể bao gồm là data trả về từ phía Server và được cached lại hay như dữ liệu được tạo ra và thao tác ở phía client mà chưa được đẩy lên phía server. UI state cũng trở lên phức tạp vì chúng ta cần quản lý việc active Routes, selected tabs, spinners, điều khiển phân trang …vv.

Việc quản lý từng thay đổi của **state** là rất khó: Vì nếu như khi ta thay đổi 1 **Model ->** Model khác cũng thay đổi theo **và** nếu 1 **View** thay đổi -> Model thay đổi -> Model khác nữa cũng thay đổi theo. Về phía Front-end development, thì được kỳ vọng xử lý các vấn đề như “**optimistic updates**” (_Hiểu như thể một thay đổi trên giao diện được thực hiện thành công trước khi được xác nhận từ phía server)_, **render phía server**, **featching data** trước khi thực hiện chuyển trang …vv. Nếu như ko có một luồng xử lý khoa học và rõ ràng thì việc quản lý dữ liệu với các dự án lớn là vô cùng phức tạp.

Vấn đề phức tạp như đề cập ở trên sẽ còn càng khó xử lý hơn nữa vì chúng ta đang trộn lẫn 2 khái niệm mà nó ko tự nhiên với tư duy thông thường của con người đó là: **Biến đổi dữ liệu (Mutation)** và **tính bất đồng bộ (Asynchronicity)**, mặc dù chúng sẽ là tuyệt vời nếu dùng tách rời nhau, nhưng hoạt động cùng nhau sẽ gây ra sự hỗn độn.

React JS đã cố gắng giải quyết điều này ở trong tầng View bằng việc loại bỏ **Bất đồng bộ** và **Không thao tác trực tiếp trên DOM**, tuy nhiên việc quản lý state là tùy thuộc vào cách của bạn do vậy đây chính là lí do Redux xuất hiện để giúp bạn quản lý state một cách khoa học và hiệu quả hơn.

#### 2\. Tại sao người ta hay dùng React với Redux?

Redux ra đời lấy cảm hứng từ tư tưởng của ngôn ngữ **Elm** và kiến trúc **Flux** của Facebook . Do vậy Redux thường dùng kết hợp với React. Tuy nhiên hoàn toàn có thể sử dụng với các framework khác như **Angular, Angular2, Backbone, Falcor, Deku, Swift.**

Vậy bạn có cần biết Flux trước khi đến với Redux ko? câu trả lời là **KHÔNG** vì thật sự nếu bạn đã dùng flux thì cũng tốt, còn không thì bạn lại dễ tiếp cận hơn (tránh lối mòn :D).

#### **3\. Quản lý state bằng Redux như thế nào?**

Giả xử chúng ta có 1 ứng dụng mà các node như trong hình là tượng trưng cho một single page application được mô hình tree-node.

![](https://cdn-images-1.medium.com/max/1600/1*8Lq3goIUVsxUJHUxCoV_BA.png)

Hình dung app của chúng ta vận hành bằng việc chuyển đổi qua lại data gữa các node, mỗi node (trang con) chứa một state và các node con nhận data được truyền từ node cha vào node con.

Giả sử nếu có 1 action ở **node d3** được kích hoạt và ta muốn thay đổi state **d4** và **c3** thì luồng dữ liệu sẽ được truyền từ **node d3** trở về node gốc là **a**, xong sau đó từ **node a** lại phát đi data đến các node con:

> Cập nhật state cho node d4: **d3-c2-b1-a-b2-c4-d4**

> Cập nhật state cho node c3: **d3-c2-b1-a-b2-c3**

![](https://cdn-images-1.medium.com/max/1600/1*6Z045wEavIIcRgIkHYlhJA.png)

Với những bài toán nhỏ (chỉ cần dùng React JS ko cần Redux) thì update state qua lại giữa các page có thể dễ dàng nhưng bạn thử hình dung ứng dụng lớn hơn có rất nhiều nhánh và node con thì việc thao tác update state qua lại giữa các page trở nên phức tạp hơn khiến cho flow của code cũng khó đọc và khó debug hơn.

Và giải pháp Redux đưa ra là như sau:

![](https://cdn-images-1.medium.com/max/1600/1*rIqP1BGb4jY2UK4qwDUBKQ.png)

Quay lại bài toán ở trên thì ta chỉ cần map Action từ node d3 về store của redux rồi ở node c3 và d4 chỉ cần connect với store và cập nhật data thay đổi -> hết sức đơn giản phải ko?

#### 4\. **Nguyên tắc hoạt động của Redux**

Vừa xong phần lý thuyết để phần nào các bạn mường tượng ra triết lý của Redux tiếp theo sau đây mình sẽ đi sâu vào giải thích cụ thể hơn các thành phần của Redux

**a. Khái niệm cốt lõi:**

Hãy tưởng tượng state của app của bạn được mô tả như 1 object thuần dưới đây:

```javascript
{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}
```

Thật sự thì nó trông giống như 1 **model** ko có phương thức **setters** ( nghĩa là chỉ có thể lấy ra data mà ko cho phép thay đổi data đó), điều này để tránh các thay đổi tùy tiện trong khi code gây ra việc khó debug.

Để thay đổi state, chỉ có 1 cách duy nhất là dispatch 1 action (Mình sẽ nói ở phần sau).

#### b. 3 nguyên tắc của Redux

> - **Single source of truth:** State của toàn bộ ứng dụng được lưu trong trong 1 store duy nhất là 1 Object mô hình tree.

> **- State is read-only:** Chỉ có 1 cách duy nhất để thay đổi state đó là tạo ra một action (là 1 object mô tả những gì xảy ra)

> - **Changes are made with pure functions:** Để chỉ rõ state tree được thay đổi bởi 1 action bạn phải viết pure **reducers**

#### **c. Nguyên lý vận hành**

![](https://cdn-images-1.medium.com/max/1600/1*QERgzuzphdQz4e0fNs1CFQ.gif)

### Actions

Trong Redux action là 1 pure object định nghĩa 2 thuộc tính là : **type**: kiểu mô tả action, và **payload**: giá trị tham số truyền lên

```javascript
{
  type: "KIEU_ACTION",
  payload: //tham số
}
```

### Reducers

Action có nhiệm vụ mô tả những gì xảy ra nhưng lại không chỉ rõ phần state nào của response thay đổi -> Việc này sẽ là của Reducer đảm nhiệm:

Reducer nhận 2 tham số vào: 1 state cũ và action được gửi lên sau đó trả ra một state mới, ko làm thay đổi state cũ.

```javascript
(previousState, action) => newState;
```

### Store

Store là 1 object lưu trữ state của toàn bộ ứng dụng có 3 phương thức sau:

- **getState()**: Giúp lấy ra state hiện tại
- **dispatch(action)**: Thực hiện gọi 1 action
- **subscrible(listener)**:Nó có vai trò cực quan trọng, luôn luôn lắng nghe xem có thay đổi gì ko rồi ngay lập tức cập nhật ra View

Để cho dễ hiểu hơn mình sẽ minh họa bằng ví dụ sau:

Ta có 1 reducer, khở tạo store thông qua hàm **createStore(reducer),** trong Redux.

<Gist id="0ca86f0c8baaaf3331a23b0da255d7cb" />

Phân tích vị dụ trên ta có:

- **Step 1**: Khởi tạo store cho project mà nó nhận tham số đầu vào là reducer **counter** ở trên:

```javascript
const store = createStore(counter);
```

- **Step 2**: Sau đó giả sử ta muốn tăng giá trị lên 1 thì call action với type là “INCREMENT” dùng hàm dispatch() của store:

```javascript
document.addEventListener("click", () => {
  store.dispatch({ type: "INCREMENT" });
});
```

- **Step 3**: lúc này là nhệm vụ của reducer, sẽ xem kiểu action gọi lên là gì “INCREMENT” hay “DECREMENT” để nó return ra 1 new state cụ thể ở đây là state + 1.
- **Step 4:** thằngsubcrible() trong store sẽ làm nhiệm vụ cập nhật tình hình thay đổi ra View:

```javascript
store.subcrible(() => {
  document.body.innerText = store.getState();
});
```

Đến đây thì cơ bản bạn đã nắm được nguyên lý hoạt động cơ bản nhất của Redux mà tôi tạm rút gọn lại flow là:

> action -> reducer -> store -> View

#### 5\. Tóm lại

Ở phạm vi bài này mình đã trình bày nguyên lý cơ bản và cách thức hoạt động của Redux để các bạn có thể nắm được cũng như hình dung nó sinh ra để làm việc gì, bài viết mới thể hiện được các tình huống đơn giản nhất thông qua ví dụ đơn giản, còn trong khi làm dự án thực tế công việc chủ yếu là tương tác với server (fetch data) và xử lý data sau đó, thì đó là về bất đồng bộ **asynchronous** và xử lý **side-effect** sau mỗi action được gọi.

Việc này sẽ được Redux xử lý với **Redux-middleware**

> Hẹn gặp lại các bạn ở phần 2 về Redux: “**Redux-middleware**”

**6\. Nguồn tham khảo:**

- [http://redux.js.org/](http://redux.js.org/)
- [https://toidicodedao.com/2016/08/18/js-truyen-ki-chuong-2-vo-lam-day-song/](https://toidicodedao.com/2016/08/18/js-truyen-ki-chuong-2-vo-lam-day-song/)
- [https://egghead.io/lessons/javascript-redux-store-methods-getstate-dispatch-and-subscribe](https://egghead.io/lessons/javascript-redux-store-methods-getstate-dispatch-and-subscribe)
]]></description>
            <link>https://hungvn.com/blog/redux-that-la-don-gian-phan-1</link>
            <guid isPermaLink="true">https://hungvn.com/blog/redux-that-la-don-gian-phan-1</guid>
            <pubDate>Fri, 22 Sep 2017 14:02:19 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Những khái niệm Javascript bạn cần biết khi phỏng vấn]]></title>
            <description><![CDATA[
### Tự học

Có hàng ngàn người đang học JavaScript và web development với hy vọng có được một công việc. Thường xuyên tự học những kiến thức hổng trong sự hiểu biết của con người về ngôn ngữ JavaScript.

Thật ngạc nhiên là cần ít ngôn ngữ để tạo ra các trang web phức tạp. Những người làm toàn bộ các trang web thường không nắm được các nguyên tắc cơ bản của Javascript.

Khá dễ dàng để tránh các chủ đề phức tạp và thực hiện các tính năng sử dụng các kỹ năng cơ bản. Cũng khá dễ để tạo ra một trang web bằng cách dựa vào Stack Overflow mà không hiểu code đang được copied.

> **Nếu bạn đang tìm kiếm để làm chủ phỏng vấn JavaScript, hãy vào đây** [**Step Up Your JS: A Comprehensive Guide to Intermediate JavaScript**](https://www.educative.io/collection/5679346740101120/5707702298738688?authorName=Arnav%20Aggarwal)

### Phỏng vấn

Vấn đề là các câu hỏi kiểm tra sự hiểu biết của bạn về JS là chính xác là những công ty công nghệ yêu cầu trong các cuộc phỏng vấn của họ. Nó trở nên rất nhanh khi người ứng tuyển biết đủ để vượt qua, nhưng không có sự hiểu biết chắc chắn về ngôn ngữ này.

Đây là những khái niệm được hỏi thường xuyên trong cách cuộc phỏng vấn về phát triển web. Điều này giả định bạn đã biết những điều cơ bản như loops, functions, và callbacks.

### Khái niệm

1.  [Value vs. Reference](https://www.educative.io/collection/page/5679346740101120/5707702298738688/5685265389584384/) — Understand how objects, arrays, and functions are copied and passed into functions. Know that the reference is what’s being copied. Understand that primitives are copied and passed by copying the value.
2.  [Scope](https://scotch.io/tutorials/understanding-scope-in-javascript#toc-scope-in-javascript) — Understand the difference between global scope, function scope, and block scope. Understand which variables are available where. Know how the JavaScript engine performs variable lookup.
3.  [Hoisting](http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/) — Understand that variable and function declarations are hoisted to the top of their available scope. Understand that function expressions are not hoisted.
4.  [Closures](http://javascriptissexy.com/understand-javascript-closures-with-ease/) — Know that a function retains access to the scope that it was created in. Know what this lets us do, such as data hiding, memoization, and dynamic function generation.
5.  [`this`](https://www.educative.io/collection/page/5679346740101120/5707702298738688/5676830073815040) — Know the rules of `this` binding. Know how it works, know how to figure out what it will be equal to in a function, and know why it’s useful.
6.  [`new`](https://codeburst.io/javascripts-new-keyword-explained-as-simply-as-possible-fec0d87b2741) — Know how it relates to object oriented programming. Know what happens to a function called with new. Understand how the object generated by using new _inherits_ from the function’s prototype property.
7.  [`apply, call, bind`](https://codeplanet.io/javascript-apply-vs-call-vs-bind/)  — Know how each of these functions work. Know how to use them. Know what they do to `this`.
8.  [Prototypes & Inheritance](https://codeburst.io/master-javascript-prototypes-inheritance-d0a9a5a75c4e) — Understand that inheritance in JavaScript works through the `[[Prototype]]` chain. Understand how to set up inheritance through functions and objects and how `new` helps us implement it. Know what the `__proto__` and `prototype` properties are and what they do.
9.  [Asynchronous JS](https://www.youtube.com/watch?v=8aGhZQkoFbQ&t=948s) — Understand the event loop. Understand how the browser deals with user input, web requests, and events in general. Know how to recognize and correctly implement asynchronous code. Understand how JavaScript is both asynchronous and single-threaded.
10. [Higher Order Functions](https://www.sitepoint.com/higher-order-functions-javascript/) — Understand that functions are first-class objects in JavaScript and what that means. Know that returning a function from another function is perfectly legal. Understand the techniques that closures and higher order functions allow us to use.

### Tài nguyên khác

Nếu các link trên chưa đủ, có vô số tài nguyên trên mạng để giúp bạn tìm hiểu những khái niệm này.

Cá nhân tôi đã tạo [Step Up Your JS: A Comprehensive Guide to Intermediate JavaScript](https://www.educative.io/collection/5679346740101120/5707702298738688?authorName=Arnav%20Aggarwal) để giúp các dev nâng cao kiến thức của họ. Nó bao gồm các khái niệm này và nhiều hơn nữa.

Đây là những resources Tôi đã đọc hoặc xem ít nhất và có thể gợi ý cho bạn:

- [Step Up Your JS](https://www.educative.io/collection/5679346740101120/5707702298738688?authorName=Arnav%20Aggarwal)
- [You Don’t Know JS](https://github.com/getify/You-Dont-Know-JS)
- [JavaScript is Sexy](http://javascriptissexy.com/16-javascript-concepts-you-must-know-well/)
- [javascript.com](https://www.javascript.com/resources)
- [Frontend Masters](https://frontendmasters.com/)
- [Eloquent JavaScript](http://eloquentjavascript.net/)

Chúc may mắn trong cuộc phỏng vấn của bạn.
]]></description>
            <link>https://hungvn.com/blog/nhung-khai-niem-javascript-ban-can-biet-khi-phong-van</link>
            <guid isPermaLink="true">https://hungvn.com/blog/nhung-khai-niem-javascript-ban-can-biet-khi-phong-van</guid>
            <pubDate>Sat, 09 Sep 2017 09:11:28 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Truy cập và thay đổi các biến CSS với Javascript]]></title>
            <description><![CDATA[
### Tại sao nó tốt hơn sử dụng biến SASS

**B**iến trong [SASS](http://sass-lang.com/guide) đã được sử dụng trong một thời gian. Chúng cho phép bạn định nghĩa một biến một lần lúc runtime và sử dụng biến đó ở nhiều nơi.
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓

#### Tương tác với các biến CSS với JS post-runtime.

Trong bản demo này chúng ta sẽ xây dựng một form đơn giản và sẽ sử dụng JS để tự động cập nhật các biến CSS (trong trường hợp này là thay đổi color và margin của một dấu chấm)

![](https://cdn-images-1.medium.com/max/1600/1*2MZOxx1HO5xGtgIB0iU9vQ.png)<figcaption class="image-caption">jsfiddle result</figcaption>

[JSFiddle Demo](https://jsfiddle.net/btg5679/9e22zasm/5/)

Chúng ta hãy nhìn vào những phần dưới đây:

### CSS

![](https://cdn-images-1.medium.com/max/2000/1*7Nq8ZrdI5ctUelDJgumWuA.png)<figcaption class="image-caption">css with root vars</figcaption>

[Đây](https://developer.mozilla.org/en-US/docs/Web/CSS/:root) là một vài thông tin về CSS `:root`, [ở đây](https://www.w3schools.com/cssref/sel_root.asp) cũng vậy. Từ MDN:

> The `:root` CSS [pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes) matches the root element of a tree representing the document. In HTML, `:root` represents the [html](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/html) element and is identical to the selector `html`, except that its [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) is higher.

Các biến CSS được định nghĩa trong `:root` và được sử dụng ở dòng 13–14\. `--` là định nghĩa chuẩn của CSS cho các biến.

### HTML

![](https://cdn-images-1.medium.com/max/2000/1*Zjm71PitjK5BQeM33Gt_jQ.png)<figcaption class="image-caption">form markup</figcaption>

Dễ dàng ở đây, lưu ý các thuộc tính input trên `type="range"`. Chúng giữ giá trị _min_ và _max_ cũng như giá trị khởi tạo _value_. Tương tự cho loại input `type="color"`. Giá trị màu khởi tạo là `#2cba92`.

### JAVASCRIPT

![](https://cdn-images-1.medium.com/max/2000/1*dlF3gNzQBRrFhU_3SnY9lg.png)<figcaption class="image-caption">js accessing css vars</figcaption>

Thông tin từng dòng:

- 4 — lấy phần tử footer
- 5 — lấy tất cả input trên trang [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList)
- 7 — input **CHANGE** **EventListener**
- 8 — input **MOUSEMOVE** **EventListener**(updates dynamic margin on slide)
- 10 — hàm đặt lại giá trị mong muốn CSS var(chú ý chúng ta thêm `px` vào biến cho margin ở dòng line 14)

---

Và đó tất cả cho **Truy cập và thay đổi các biến CSS với Javascript**.
]]></description>
            <link>https://hungvn.com/blog/truy-cap-va-thay-doi-cac-bien-css-voi-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/truy-cap-va-thay-doi-cac-bien-css-voi-javascript</guid>
            <pubDate>Fri, 08 Sep 2017 20:46:11 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cheatsheet cơ bản về Flexbox]]></title>
            <description><![CDATA[
### Tổng quan về cách sử dụng flexible box layout

I spent the last days wrapping my head around **flexbox**, and how to use it correctly. Maybe you can relate to when I say, that it is not that easy to understand how it exactly works, or why some CSS rules don’t behave as expected under certain circumstances.

In this article, I just want to give a summary of what I think is important to know. So please keep in mind that this will not be an exhaustive description of all possible CSS rules and scenarios.

### What’s flexbox?

> Flexbox is a layout mode which is designed for laying out more complex applications and webpages. — [w3.org](https://www.w3.org/TR/css-flexbox-1/#intro)

When using the flexbox layout model we distinguish between the two main elements: flex container and flex items.

The flex container is the parent element of your flex items. You set `display: flex` or `display: inline-flex` on this element to activate the flex layout mode.

Before outlining the details of a flex container or flex items, I want to talk about the terminology of the flex box layout model, which I found somehow confusing in the beginning. Here’s what I found about that in the [flexbox specification](https://www.w3.org/TR/css-flexbox-1/#box-model):

![](https://cdn-images-1.medium.com/max/2000/1*dH2D2U0yOf4a2Z_OYxRsKg.png)An illustration of the various directions, sizing and positioning terms as applied to a ‘row’ flex container.

First of all, in flexbox layout there is no _horizontal_ or _vertical_. Instead, we orientate ourselves by a _main axis_ and a _cross axis_.

Flex items are always laid out along the **main-axis**. In the image above, you can see, that the main-axis for a _row_ flex container goes from the left end of the flex container (**_main start_**) to the right end (**_main end_**).

> Basically, a column flex container is just a row flex container tilted by 90 degrees to the right.

![](https://cdn-images-1.medium.com/max/1200/1*_G8vYJ2P_l1CeRETSx43NQ.jpeg)An illustration of the various directions, sizing and positioning terms as applied to a ‘column’ flex container.

For a _column_ flex container things would look a bit different.

As you can see in the image on the left, as soon as you use `flex-direction: column`, the _main-axis_ points towards the bottom of the screen, while the _cross-axis_ goes from the right end to the left end of the flex container. So basically the whole picture is just tilted to the right, by 90 degrees.

This helped me a lot to orientate myself within a column flex container, since the CSS properties change their effective direction between _row_ and _column_ flex containers.

Now that’s all we need for now. In the following sections I’m going to describe the different CSS rules which are applicable for flex container and flex items.

### The Flex Container CSS Rules

Let’s start with the CSS rules which are used on the flex container. I included some screenshots and put the respective CSS setting into the caption of the images.

#### **flex-direction**

This rule determines if the flex-items are aligned in a row or in a column. Additionally, there is an option to align them in reverse order, heading from main-end to main-start.

![](https://cdn-images-1.medium.com/max/1600/1*amKZ2KxBD-1huE56oIHHiQ.png)

<figcaption class="image-caption">flex-direction: row; (default)</figcaption>

![](https://cdn-images-1.medium.com/max/1600/1*LSl2HQ6FcCfqwVTIpHsiHA.png)

<figcaption class="image-caption">flex-direction: column;</figcaption>

#### flex-wrap

If you add more flex-items to a line, you will get to the point where there is not enough space for more. Since the flex-items shrink by default (see: shrink the flex-items section) the items will get smaller the more items you add. By using flex-wrap you can control this behaviour if the items should stay in the same line (this is the default behaviour; `flex-wrap: nowrap;`) or wrap to the next line ( `flex-wrap: wrap;` or `flex-wrap: wrap-reverse;`)

![](https://cdn-images-1.medium.com/max/1600/1*Q2Qc5OiAJrWhgWF6BHYIVQ.png)

<figcaption class="image-caption">
  flex-wrap: nowrap; as as applied to a ‘row’ flex-container
</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*4mpb0H6Dn2UK5uLFD9_rHg.png)
<figcaption class="image-caption">flex-wrap: wrap;</figcaption>

#### flex-flow

This is the first shorthand I will show you today. You can combine the CSS rules _flex-direction_ and _flex-wrap_ within one single CSS rule. The following list should speak for itself:

- `flex-flow: row wrap;`
- `flex-flow: row wrap-reverse;`
- `flex-flow: column wrap;`
- `flex-flow: column wrap-reverse;`

#### justify-content

To position the flex-items alongside the main axis, you can use _justify-content_:

![](https://cdn-images-1.medium.com/max/1600/1*GoU8Z5Jk0VZvgchlAoFZgQ.png)

<figcaption class="image-caption">justify-content: flex-start; (default behaviour)</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*GcJfvAx72fkZJaWiAxL6ug.png)
<figcaption class="image-caption">justify-content: flex-end;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*bqgVSv8CYbd5sbqnHomfcQ.png)
<figcaption class="image-caption">justify-content: center;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*xn5xnkoUNMtXcfsIs92JNw.png)
<figcaption class="image-caption">justify-content: space-between;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*DSt6QAuAXPl4EpPKGpR7Gw.png)
<figcaption class="image-caption">justify-content; space-around;</figcaption>

#### align-items

Now that you learned about justify-content to lay out items along the main axis, this is an easier one. _align-items_ is used to align items **along the cross-axis** **on the current line**.

![](https://cdn-images-1.medium.com/max/1600/1*_1XwY-xQJU6v82fKGueYwg.png)

<figcaption class="image-caption">align-items: flex-start; (default behaviour)</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*MQyjqpuA3eIMUJEgUuecCg.png)
<figcaption class="image-caption">align-items: flex-end;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*i9K2YX_EBDtxxmHP0FT2sg.png)
<figcaption class="image-caption">align-items: center;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*d3yXuFZNDYal8GDv_NFUJA.png)
<figcaption class="image-caption">align-items: stretch;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*DqQEdsCtWhfjWseSz8P_xQ.png)
<figcaption class="image-caption">align-items: baseline;</figcaption>

As you see, _align-items_ also allows to stretch items to use the available space in the current line, as well as `align-items: baseline;`aligns items along the bottom line of their first line of text.

But what do you do if you don’t want to align the items within one line, but rather align the whole bunch of items within the available space of the flex-container? That’s what _align-content_ is used for.

#### align-content

Let’s have a look how we can align the whole bunch of _flex-items_ within our flex container:

![](https://cdn-images-1.medium.com/max/1600/1*aK6Y1x6s6tmNY68wjgEA9w.png)

<figcaption class="image-caption">align-content: flex-start; (default behaviour)</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*N3qM1kVTqPyqB6yWzcqPFg.png)
<figcaption class="image-caption">align-content: flex-end;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*hX2F70c0MdZf2Xhof6E37g.png)
<figcaption class="image-caption">align-content: center;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*iTMcb2NayM5YdDhWYCSEsA.png)
<figcaption class="image-caption">align-conent; stretch;</figcaption>

That was a rather short overview of what you are capable to do with flex-container CSS rules. In the next section I’m going to show you how you can adjust the behaviour of flex-items.

### The Flex Item CSS Rules

In the last section you learned how to align all flex items at once — either within their line or within the available space of their flex container. Now it’s time to have a look at `grow` ,`shrink` ,`flex-basis` and the `flex` shorthand for those three rules.

#### grow

Defines if items cang row to use the available space along the main-axis. The default value is 0, which means that flex-items don’t grow automatically. In the following pictures you can see which effect grow has on flex items in a ‘row’ and in a ‘column’ container.

![](https://cdn-images-1.medium.com/max/1600/1*8I6rq-lPe9cUWyxtOU6ZsA.png)

<figcaption class="image-caption">grow: 0; (default behaviour) in a ‘row’ container</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*lSrfcRMbjsWOzZEmPIG-MQ.png)
<figcaption class="image-caption">grow: 1; in a ‘row’ container</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*X0P2Z46934QObV7nskeGCQ.png)
<figcaption class="image-caption">grow: 0; (default behaviour) in a ‘column’ container</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*Ak6iZ36xtiO98loOmWUEfA.png)
<figcaption class="image-caption">grow: 1; in a ‘column’ container</figcaption>

With _flex-grow_ it is also possible to let certain items grow more than others.

Example: We have three items. Two of them have grow set to 1, while one of them got grow set to 2.

![](https://cdn-images-1.medium.com/max/1600/1*WFNQhpqX_7GPh0SD4kJ3Tg.png)

What happened here? First of all, all grow values of a line are added, which results in a total of 4 which represents 100% of our available space.
Then each item is sized according to the relational size of its grow setting to the sum of all grow settings of said line. According to that calculation, the first two items get 25% of the available space and the third one gets 50%. Please note that I did not consider the padding and margin which is set in the image.

#### **flex-shrink**

By default, the shrink rule is set to 1\. This means that as soon as the window is resized, the flex items will shrink if necessary. Possible values are 0 and 1.

**Example:** The flex item of the following picture has a width of 500px. With shrink set to it’s default value 1, resizing the window means that the item will shrink to less than 500px width. When setting shrink to 0, the item will not shrink and would exceed the window size and a scrollbar appears.

![](https://cdn-images-1.medium.com/max/1600/1*y-xL7-dpnWZs7oGwbpUUIQ.png)

<figcaption class="image-caption">
  The item has a width of 500px. (Sidenote: grow is switched off)
</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*yCL3eUCd-KC-emVKyPigJA.png)
<figcaption class="image-caption">
  shrink is turned on — resizing the window also resizes the item.
</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*xcDvBTj8-fsuiqPlHE__sw.png)
<figcaption class="image-caption">
  shrink turned off. The item exceeds the window (scrollbars omitted in this picture)
</figcaption>

#### flex-basis

The flex basis defines the initial _main-size_ of a flex item. This setting will be evaluated before the available space is distributed to flex-grow, or the items are resized by flex-shrink.

> The initial main size of the flex item before free space is distributed to the flex factors. — [w3.org](https://www.w3.org/TR/css-flexbox-1/#flex-basis-property)

flex-basis accepts either a length in `px || em || rem` or percentages, as well as `auto`.

If flex-basis is set to `auto`, the width will be calculated based on content size. So the more you increase the content of a flex item, the bigger it gets.

As soon as you set a fixed size to flex-basis, the content of the item will adjust to fit into the item.

![](https://cdn-images-1.medium.com/max/1600/1*jiePFv0eUl_DqRjCiP7Q2Q.png)

<figcaption class="image-caption">flex-basis: auto;</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*kCLeXxe2uimOLt0rjEZEGQ.png)
<figcaption class="image-caption">flex-basis: auto; with more content</figcaption>
![](https://cdn-images-1.medium.com/max/1600/1*wH-iTB9Hm2kDckwJYajaYw.png)
<figcaption class="image-caption">flex-basis: 100px;</figcaption>

#### The flex shorthand

Because it is way more comfortable to set the above rules all at once, there is a shorthand to do so: The default setting for this is `flex: 0 1 auto;`

With the shorthand you define **_flex-grow_** with the **first**, **_flex-shrink_** with the **second**, and **_flex-basis_** with the **third argument.**

It is also possible to omit the last parameter: `flex: 0 1` which defaults flex-basis to zero*.*

The following pictures show some examples how you can arrange flex-items using the flex shorthand.

**flex: 0 1 auto (default behaviour)** The item size is defined by its content.

![](https://cdn-images-1.medium.com/max/1600/1*-_OHfGSjTwuF5GMDEuYMJg.png)

<figcaption class="image-caption">flex: 0 1 auto; (default behaviour)</figcaption>

**flex: 1 1 auto**

![](https://cdn-images-1.medium.com/max/1600/1*dtjRc5zRutFWrHSsvSMugQ.png)

<figcaption class="image-caption">flex: 1 1 auto;</figcaption>

**flex: 0 0 auto**
This is the same as the example in the above section “flex-shrink”. Shrinking is turned off, which leads to the item overflowing the window size.

![](https://cdn-images-1.medium.com/max/1600/1*C0yZxme_Vj0dIZXUtR1GYA.png)

<figcaption class="image-caption">flex: 0 0 auto;</figcaption>

**Relative size of flex-items** To use the same “relative” sizing technique I described in the section “flex-grow”, you have to set flex-basis to zero. In the next picture, the first item has `flex: 2 1 0;` while the second item has `flex: 1 1 0;`

![](https://cdn-images-1.medium.com/max/1600/1*qFW-emQqaJGV1ePBrgdFzQ.png)

<figcaption class="image-caption">
  The first item got 2/3 of the available size while the second one got 1/3
</figcaption>

### Conclusion

Well that article grew a bit bigger than it was planned, but in the end, I hope you enjoyed the read. Maybe this article can serve as a handy guide to look up the different CSS rules if you want to brush up your knowledge, as this is something one might not memorize completely.

As I said in the beginning, this was never meant to be an exhaustive list of szenarios and rules which can apply, if you are interested in this in detail, I would suggest to read the articles I mentioned in the beginning of the article, as well as parts of the specification (if you don’t want to read the whole thing)

- [Understanding Flexbox: Everything you need to know](https://medium.freecodecamp.org/understanding-flexbox-everything-you-need-to-know-b4013d4dc9af) ([Ohans Emmanuel](https://medium.com/@ohansemmanuel))
- [11 things I learned reading the flexbox spec](https://hackernoon.com/11-things-i-learned-reading-the-flexbox-spec-5f0c799c776b) ([David Gilbertson](https://medium.com/@david.gilbertson))
- [CSS Flexible Box Layout Module Level 1](https://www.w3.org/TR/css-flexbox-1/)

At first, I planned to also create this as a handy cheatsheet, but then I found a **really good one** by [Chris Coyier](https://medium.com/@chriscoyier) which I want to share with you:

- [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)

Thanks for reading this article!
]]></description>
            <link>https://hungvn.com/blog/cheatsheet-co-ban-ve-flexbox</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cheatsheet-co-ban-ve-flexbox</guid>
            <pubDate>Wed, 06 Sep 2017 07:05:26 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Một số SASS Mixins nên sử dụng]]></title>
            <description><![CDATA[
Danh sách một số SASS mixins mà các Web designers nên có để công việc của họ nhanh hơn.

![Một số SASS Mixins nên sử dụng](http://w3bits.com/wp-content/uploads/must-have-sass-mixins.jpg)

Tôi đã sử dụng SASS không quá lâu, nhưng kể từ khi tôi bắt đầu với nó, Tôi đã sử dụng một số _mixins_ để auto một số thứ trong dự án của tôi. Mixins giống như các hàm tự động tạo ra code CSS và giúp bạn tiết kiệm viết code giống nhau lặp đi lặp lại.

Có một số lượng tốt thư viện SASS mixin sẵn có trên web (eg. bourbon) một hoặc một số trong số đó bạn có thể đã sử dụng. Hoặc như tôi, bạn có thể đã tạo ra một bộ tùy chỉnh bằng cách thu thập các mixins siêu hữu ích từ web.

Tạo thư viện tùy chỉnh luôn luôn phục vụ tốt và gọn gàng. Bằng cách này bạn tránh thêm code không cần thiết và chỉ thêm những gì bạn thực sự cần.

Dưới đây là danh sách một số SASS mixins tiện dụng Tôi đã sử dụng hằng ngày với các dự án của tôi. Một số trong số chúng được thu thập từ web, một số đơn giản là đủ để viết cho mình. Kiểm tra các đoạn mixins dưới đây, cách sử dụng ví dụ, và output của chúng:

## 1. Thêm kích thước

Một mixin đơn giản để cho kích thước vào một box.

```scss
@mixin box($width, $height=$width) {
    width: $width;
    height: $height;
}
```

#### Usage

Bạn phải cung cấp ít nhất một tham số để làm cho nó hoạt động:

```scss
.square {
  @include box(50px);
}

.rectangle {
  @include box(100px, 50px);
}
```

#### Output

```scss
.square {
    width: 50px;
    height: 50px;
}

.rectangle {
    width: 100px;
    height: 50px;
}
```

## 2. Clearfix

Implementing [micro-clearfix hack](http://w3bits.com/clearfix/) the SASS way.

```scss
@mixin clearfix {
  &:after {
    content: "";
    display: table;
    clear: both;
  }
}
```

#### Usage

```scss
.cf {
  @include clearfix;
}
```

#### Output

```scss
.cf:after {
    content: "";
    display: table;
    clear: both;
}
```

## 3. Opacity

CSS Opacity with fallback for IE8+.

```scss
@mixin opacity($opacity) {
    opacity: $opacity;
    $opacity-ie: $opacity * 100;
    filter: alpha(opacity = $opacity-ie); //IE8
}
```

#### Output

```scss
.fade {
  @include opacity(.4);
}
```

#### Output

```scss
.fade {
    opacity: 0.4;
    filter: alpha(opacity = 40); //IE8
}
```

## 4. Positioning

Easy and quick CSS positioning, thanks to [Hugo Giraudel](http://www.sitepoint.com/sass-mixins-kickstart-project/).

```scss
@mixin position($position, $args) {
  @each $o in top right bottom left {
    $i: index($args, $o);
    @if $i and $i + 1 <= length($args) and type-of(nth($args, $i + 1)) == number {
      #{$o}: nth($args, $i + 1);
    }
  }
  position: $position;
}

// Positioning helpers
@mixin absolute($args: '') {
  @include position(absolute, $args);
}

@mixin fixed($args: '') {
  @include position(fixed, $args);
}

@mixin relative($args: '') {
  @include position(relative, $args);
}
```

#### Usage

You should only use `absolute()`, `relative()`, and `fixed()` functions to add the respective positioning to the elements. Parameters are optional and can be given as demonstrated below:

```scss
.menu li {
  @include relative;
}

.sub-menu {
  @include absolute(top 100% left 0);
}

.sticky-bar {
  @include fixed(top 0 left 0);
}
```

## 5. Rem units

Implementing CSS `rem` units with [pixel fallback](http://w3bits.com/rem-fallback/).

```scss
@mixin font-size($size, $base: 16) {
    font-size: $size; // fallback for old browsers
    font-size: ($size / $base) * 1rem;
}
```

#### Usage

```scss
body {
  @include font-size(16);
}

p {
  @include font-size(12, 10);
}
```

Bạn phải cung cấp ít nhất một giá trị khi sử dụng mixin, giá trị này sẽ được coi là font-size và sẽ được xuất ra sau khi được tính toán với font-size mặc định (16). Hoặc bạn có thể cung cấp một giá trị cơ sở khác nếu bạn muốn.

#### Output

```scss
body {
    font-size: 16px;
    font-size: 1rem;
}
```

## 6. Vendor prefixing

Vendor prefixing made easy with full control over prefixes, customize as you use:

```scss
@mixin prefix($property, $value, $vendors: webkit moz ms o, $default: true) {
  @if $vendors {
    @each $vendor in $vendors {
      #{"-" + $vendor + "-" + $property}: #{$value};
    }
  }
  @if $default {
    #{$property}: #{$value};
  }
}
```

#### Usage

```scss
html {
  @include prefix('box-sizing', 'border-box', moz webkit);
}

*,
*:before,
*:after {
  @include prefix('box-sizing', 'inherit', moz webkit);
}
```

As shown above, you may provide the vendor prefixes as the 3rd parameter in the mixin, each separated by a space.

#### Output

```scss
html {
    -moz-box-sizing: border-box;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}

*,
*:before,
*:after {
    -moz-box-sizing: inherit;
    -webkit-box-sizing: inherit;
    box-sizing: inherit;
}
```

## 7. Media queries

Handling CSS Media queries was never this easy:

```scss
@mixin screen($size) {
  $desktop: "(min-width: 1024px)";
  $tablet: "(min-width: 768px) and (max-width: 1023px)";
  $mobile: "(max-width: 767px)";
  @if $size == desktop {
    @media only screen and #{$desktop} {
      @content;
    }
  }
  @else if $size == tablet {
    @media only screen and #{$tablet} {
      @content;
    }
  }
  @else if $size == mobile {
    @media only screen and #{$mobile} {
      @content;
    }
  }
  @else {
    @media only screen and #{$size} {
      @content;
    }
  }
}
```

#### Usage

```scss
.wrapper {
  margin: 0 auto;
  width: 100%;
  @include screen('tablet') {
    width: 90%;
  }

  @include screen('desktop') {
    width: 85%;
  }
}
```

#### Output

```scss
.wrapper {
  margin: 0 auto;
  width: 100%;
}
@media only screen and (min-width: 768px) and (max-width: 1023px) {
  .wrapper {
    width: 90%;
  }
}
@media only screen and (min-width: 1024px) {
  .wrapper {
    width: 85%;
  }
}
```

In place of 'mobile', 'tablet', or 'desktop', you may also provide a custom breakpoint values, for eg:

```scss
.wrapper {
  @include screen('(min-width: 1367px)') {
    width: 1280px;
  }
}
```

## 8. Retina Images

Show the retina images on retina-friendly devices only:

```scss
@mixin retina($image, $width, $height) {
  @media (min--moz-device-pixel-ratio: 1.3),
  (-o-min-device-pixel-ratio: 2.6/2),
  (-webkit-min-device-pixel-ratio: 1.3),
  (min-device-pixel-ratio: 1.3),
  (min-resolution: 1.3dppx) {
    /* Serving 2x image on Retina display */
    background-image: url($image);
    background-size: $width $height;
  }
}
```

#### Usage

```scss
.logo {
background-image: url("img/logo.png");
  @include retina("img/logo@2x.png", 100px, 21px);
}
```

#### Output

```scss
.logo {
  background-image: url("img/logo.png");
}
@media (min--moz-device-pixel-ratio: 1.3), (-o-min-device-pixel-ratio: 2.6 / 2), (-webkit-min-device-pixel-ratio: 1.3), (min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx) {
  .logo {
    /* Serving HQ image on Retina display */
    background-image: url("img/logo@2x.png");
    background-size: 100px 21px;
  }
}
```

The above example usage may not be perfect and you may add more rules for specifying width and height of the element to be optimized for retina screen.

## 9. CSS3 Keyframes

CSS3 keyframes can't be implemented with the vendor prefixing mixin mentioned above. The below mixin is meant to render keyframes correctly with the vendor prefixes:

```scss
@mixin keyframes($name) {
  @-webkit-keyframes #{$name} {
    @content;
  }

  @-moz-keyframes #{$name} {
    @content;
  }

  @keyframes #{$name} {
    @content;
  }
}
```

#### Usage

```scss
@include keyframes(animate) {
  50% {
    transform: rotate(90deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}
```

#### Output

```scss
@-webkit-keyframes animate {
  50% {
    transform: rotate(90deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}
@-moz-keyframes animate {
  50% {
    transform: rotate(90deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}
@keyframes animate {
  50% {
    transform: rotate(90deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}
```

## 10. Background Gradient

Quick and simple SASS mixin to implement CSS linear gradients:

```scss
@mixin gradient($start-color, $end-color, $orientation) {
  background: $start-color;
  @if $orientation == 'vertical' {
    background: -webkit-linear-gradient(top, $start-color, $end-color);
    background: linear-gradient(to bottom, $start-color, $end-color);
  } @else if $orientation == 'horizontal' {
    background: -webkit-linear-gradient(left, $start-color, $end-color);
    background: linear-gradient(to right, $start-color, $end-color);
  } @else {
    background: -webkit-radial-gradient(center, ellipse cover, $start-color, $end-color);
    background: radial-gradient(ellipse at center, $start-color, $end-color);
  }
}
```

#### Usage

```scss
.gradient {
  @include gradient(#07c, #06f, vertical);
}
```

#### Output

```scss
.gradient {
    background: #07c;
    background: -webkit-linear-gradient(top, #07c, #06f);
    background: linear-gradient(to bottom, #07c, #06f);
}
```

## 11. @font-face

```scss
@mixin font-face($font-name, $file-name, $weight: normal, $style: normal) {
  @font-face {
    font-family: quote($font-name);
    src: url($file-name + '.eot');
    src: url($file-name + '.eot?#iefix')  format('embedded-opentype'),
    url($file-name + '.woff') format('woff'),
    url($file-name + '.ttf')  format('truetype'),
    url($file-name + '.svg##{$font-name}')  format('svg');
    font-weight: $weight;
    font-style: $style;
  }
}
```

#### Usage

```scss
@include font-face("MyFont", "path/to/MyFont", $style: normal, $weight: normal);
```

#### Output

```scss
@font-face {
    font-family: "MyFont";
    src: url("path/to/MyFont.eot");
    src:
    url("path/to/MyFont.eot?#iefix") format("embedded-opentype"),
    url("path/to/MyFont.woff") format("woff"),
    url("path/to/MyFont.ttf") format("truetype"),
    url("path/to/MyFont.svg#MyFont") format("svg");
    font-weight: normal;
    font-style: normal;
}
```

## 12. Centering a block

```scss
@mixin center-block {
    display: block;
    margin-left: auto;
    margin-right: auto;
}
```

#### Usage

```scss
.wrapper {
  @include center-block;
}
```

#### Output

```scss
.wrapper {
    display: block;
    margin-left: auto;
    margin-right: auto;
}
```

## 13. Vertical centering

```scss
@mixin center-vertically {
  position: absolute;
  top: 50%;
  left: 50%;
  @include prefix(transform, translate(-50%, -50%), 'webkit' 'ms');
}
```

#### Usage

```scss
.vc-box {
  @include center-vertically;
}
```

#### Output

```scss
.vc-box {
    position: absolute;
    top: 50%;
    left: 50%;
    -webkit-transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    transform: translate(-50%, -50%);
}
```

Kết thúc ở đây, hy vọng nó có ích. Vui lòng chỉ ra vấn đề hoặc chia sẻ các đề xuất của bạn qua nhận xét. Thanks :)
]]></description>
            <link>https://hungvn.com/blog/mot-so-sass-mixins-nen-su-dung</link>
            <guid isPermaLink="true">https://hungvn.com/blog/mot-so-sass-mixins-nen-su-dung</guid>
            <pubDate>Fri, 01 Sep 2017 09:53:15 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Hướng dẫn toàn tập về Flexbox]]></title>
            <description><![CDATA[
### [Background](#flexbox-background)

The Flexbox Layout (Flexible Box) module nhằm cung cấp một cách hiệu quả hơn việc bố trí, sắp xếp và cân đối không gian giữa các phần tử trong một Container, ngay cả khi kích thước của các phần tử này chưa được biết hay nói cách khác là động (flex).

Mục đích chính của Flex layout là cung cấp một flex container có khả năng thay đổi các item bên trong nó chiều rộng, chiều cao, thứ tự của các item giúp cho Flex container này hiển thị tốt trên mọi thiết bị và mọi kích cỡ màn hình. Các item trong một flex container sẽ tự mở rộng để lấp đầy không gian hoặc tự co lại để ngăn chặn chống tràn (Overflow).

Quan trọng nhất, Flexbox layout dựa trên phương hướng bố trí ngược với cách bố trí bình thường (block theo chiều dọc và inline theo chiều ngang). Mặc dù những trang này hoạt động tốt, nhưng chúng thiếu tính linh hoạt để hỗ trợ các ứng dụng lớn hoặc phức tạp (đặc biệt liên quan đến thay đổi hướng, thay đổi kích cỡ, kéo dài, co lại, etc.).

**Chú ý:** Flexbox layout là thích hợp nhất với các thành phần của một ứng dụng, và bố trí quy mô nhỏ, trong khi đó [Grid](http://css-tricks.com/snippets/css/complete-guide-grid/) layout là dành cho bố trí quy mô lớn hơn.

### [Khái niệm cơ bản & Thuật ngữ](#flexbox-basics)

Flexbox là một module toàn bộ chứ không phải một thuộc tính duy nhất, nó bao gồm rất nhiều thứ kể cả các thuộc tính. Một số trong chúng là để được đặt cho container (element cha, được gọi là "flex container") trong khi những thứ khác là để được đặt cho children (gọi là "flex items").

**Flex container** là thành phần lớn bao quanh chứa các phần tử (Flex items) bên trong.

**Flex items** là phần tử con nằm trong thành phần lớn bao quanh gọi là những Flex items, các bạn có thể sắp xếp thứ tự của các Flex items này.

Nếu cách bố trí thông thường dựa trên luồng block và inline, flex layout là dựa vào "flex-flow directions". Nhìn vào những thông số kỹ thuật và giải thích ý tưởng của flex layout ở hình bên dưới.

![](https://cdn.css-tricks.com/wp-content/uploads/2011/08/flexbox.png)

Về cơ bản, những items sẽ được sắp xếp theo một trong hai trục chính (từ main-start đên main-end) hoặc trục dọc (từ cross-start đến cross-end).

- **main axis** - The main axis of a flex container is the primary axis along which flex items are laid out. Beware, it is not necessarily horizontal; it depends on the flex-direction property (see below).
- **main-start | main-end** - The flex items are placed within the container starting from main-start and going to main-end.
- **main size** - A flex item's width or height, whichever is in the main dimension, is the item's main size. The flex item's main size property is either the ‘width’ or ‘height’ property, whichever is in the main dimension.
- **cross axis** - The axis perpendicular to the main axis is called the cross axis. Its direction depends on the main axis direction.
- **cross-start | cross-end** - Flex lines are filled with items and placed into the container starting on the cross-start side of the flex container and going toward the cross-end side.
- **cross size** - The width or height of a flex item, whichever is in the cross dimension, is the item's cross size. The cross size property is whichever of ‘width’ or ‘height’ that is in the cross dimension.

![](//css-tricks.com/wp-content/uploads/2014/05/flex-container.svg)
_Properties for the Parent (flex container)_

#### display

Đây là định nghĩa một flex container; inline hoặc block tùy thuộc vào giá trị nhất định. Nó cho phép một flex context cho tất cả con trực tiếp của nó.

```css
.container {
  display: flex; /* or inline-flex */
}
```

Chú ý rằng CSS columns không có tác dụng trong vùng flex container.

#### flex-direction

![](//css-tricks.com/wp-content/uploads/2013/04/flex-direction2.svg)

Định nghĩa này cho trục chính, do đó định nghĩa direction flex items đặt ở trong flex container. Flexbox là một khái niệm layout đơn hướng. Hãy nghĩ flex items là chủ yếu đặt trong hàng ngang hoặc cột dọc.

```css
.container {
  flex-direction: row | row-reverse | column | column-reverse;
}
```

- row (default): từ trái sang phải trong ltr; từ phải sang trái rtl
- row-reverse: phải sang trái trong ltr; trái sang phải trong rtl
- column: giống như row nhưng từ trên xuống dưới
- column-reverse: giống như row-reverse nhưng từ trên xuống dưới

#### flex-wrap

![](//css-tricks.com/wp-content/uploads/2014/05/flex-wrap.svg)

Mặc định, flex items sẽ cố gắng đặt vào 1 dòng. Bạn có thể thay đổi điều đó và những items sẽ wrap khi có thuộc tính này.

```css
.container {
  flex-wrap: nowrap | wrap | wrap-reverse;
}
```

- nowrap (default): các flex items sẽ được hiển thị trên một dòng
- wrap: các flex items sẽ hiển thị thành nhiều dòng, từ trên xuống dưới.
- wrap-reverse: các flex items sẽ hiển thị thành nhiều dòng từ dưới lên trên.

Có một vài ví dụ [thực tế của flex-wrap ở đây](https://css-tricks.com/almanac/properties/f/flex-wrap/).

#### flex-flow (Áp dụng cho: phần tử cha flex container)

Đây là cách viết gọn của thuộc tính flex-direction và flex-wrap, chúng cùng nhau định nghĩa flex container's trục chính hay trục dọc. Mặc định là row nowrap.

```css
flex-flow: <‘flex-direction’> || <‘flex-wrap’>;
```

#### justify-content

![](https://cdn.css-tricks.com/wp-content/uploads/2013/04/justify-content-2.svg)
Điều này xác định sự sắp xếp theo trục chính. It helps distribute extra free space left over when either all the flex items on a line are inflexible, or are flexible but have reached their maximum size. It also exerts some control over the alignment of items when they overflow the line.

```css
.container {
  justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly;
}
```

- flex-start (default): items are packed toward the start line
- flex-end: items are packed toward to end line
- center: items are centered along the line
- space-between: items are evenly distributed in the line; first item is on the start line, last item on the end line
- space-around: items are evenly distributed in the line with equal space around them. Note that visually the spaces aren't equal, since all the items have equal space on both sides. The first item will have one unit of space against the container edge, but two units of space between the next item because that next item has its own spacing that applies.
- space-evenly: items are distributed so that the spacing between any two items (and the space to the edges) is equal.

#### align-items

![](https://cdn.css-tricks.com/wp-content/uploads/2014/05/align-items.svg)
This defines the default behaviour for how flex items are laid out along the cross axis on the current line. Think of it as the justify-content version for the cross-axis (perpendicular to the main-axis).

```css
.container {
  align-items: flex-start | flex-end | center | baseline | stretch;
}
```

- flex-start: cross-start margin edge of the items is placed on the cross-start line
- flex-end: cross-end margin edge of the items is placed on the cross-end line
- center: items are centered in the cross-axis
- baseline: items are aligned such as their baselines align
- stretch (default): stretch to fill the container (still respect min-width/max-width)

#### align-content

![](//css-tricks.com/wp-content/uploads/2013/04/align-content.svg)
This aligns a flex container's lines within when there is extra space in the cross-axis, similar to how justify-content aligns individual items within the main-axis.

**Note:** this property has no effect when there is only one line of flex items.

```css
.container {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
```

- flex-start: lines packed to the start of the container
- flex-end: lines packed to the end of the container
- center: lines packed to the center of the container
- space-between: lines evenly distributed; the first line is at the start of the container while the last one is at the end
- space-around: lines evenly distributed with equal space around each line
- stretch (default): lines stretch to take up the remaining space

![](//css-tricks.com/wp-content/uploads/2014/05/flex-items.svg)
_Thuộc tính của Children (flex items)_

#### order

![](//css-tricks.com/wp-content/uploads/2013/04/order-2.svg)
Mặc định các phần tử được sắp xếp theo giá trị nguồn html, với thuộc tính order chúng ta có thể xắp xếp lại thứ tự các phần tử theo ý muốn mà ko cần thay đổi giá trị nguồn html.

```css
.item {
  order: <integer>;
}
```

#### grow

![](//css-tricks.com/wp-content/uploads/2014/05/flex-grow.svg)
This defines the ability for a flex item to grow if necessary. It accepts a unitless value that serves as a proportion. It dictates what amount of the available space inside the flex container the item should take up.

If all items have grow set to 1, the remaining space in the container will be distributed equally to all children. If one of the children has a value of 2, the remaining space would take up twice as much space as the others (or it will try to, at least).

```css
.item {
  grow: <number>; /* default 0 */
}
```

Số âm không hợp lệ với thuộc tính này.

#### shrink

Định nghĩa một flex item có thể khả năng thu nhỏ nếu cần thiết.

```css
.item {
  shrink: <number>; /* default 1 */
}
```

Số âm không hợp lệ với thuộc tính này.

#### flex-basis

Định nghĩa kích thước mặc định của một phần tử trước khi phân bố không gian của phần còn lại. Nó có thể là một chiều dài (e.g. 20%, 5rem, etc.) hay một từ khóa. Từ khóa auto có nghĩa là "nhìn vào thuộc tính width hoặc height của tôi" (which was temporarily done by the main-size keyword until deprecated). The content keyword means "size it based on the item's content" - this keyword isn't well supported yet, so it's hard to test and harder to know what its brethren max-content, min-content, and fit-content do.

```css
.item {
  flex-basis: <length> | auto; /* default auto */
}
```

If set to 0, the extra space around content isn't factored in. If set to auto, the extra space is distributed based on its grow value. [See this graphic.](http://www.w3.org/TR/css3-flexbox/images/rel-vs-abs-flex.svg)

#### flex

Đây là viết tắt cho flex-grow, shrink và flex-basis. Các thông số thứ hai và thứ ba (flex-shrink và flex-basis) là tùy chọn. Mặc định là 0 1 auto.

```css
.item {
  flex: none | [ < "grow" > < "shrink" >? || < "flex-basis" >];
}
```

**It is recommended that you use this shorthand property** rather than set the individual properties. The short hand sets the other values intelligently.

#### align-self

![](//css-tricks.com/wp-content/uploads/2014/05/align-self.svg)
This allows the default alignment (or the one specified by align-items) to be overridden for individual flex items.

Please see the align-items explanation to understand the available values.

```css
.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
```

Note that float, clear and vertical-align have no effect on a flex item.

### Examples

Let's start with a very very simple example, solving an almost daily problem: perfect centering. It couldn't be any simpler if you use flexbox.

```css
.parent {
  display: flex;
  height: 300px; /* Or whatever */
}

.child {
  width: 100px; /* Or whatever */
  height: 100px; /* Or whatever */
  margin: auto; /* Magic! */
}
```

This relies on the fact a margin set to `auto` in a flex container absorb extra space. So setting a vertical margin of auto will make the item perfectly centered in both axis.

Now let's use some more properties. Consider a list of 6 items, all with a fixed dimensions in a matter of aesthetics but they could be auto-sized. We want them to be evenly and nicely distributed on the horizontal axis so that when we resize the browser, everything is fine (without media queries!).

```css
.flex-container {
  /* We first create a flex layout context */
  display: flex;

  /* Then we define the flow direction and if we allow the items to wrap 
   * Remember this is the same as:
   * flex-direction: row;
   * flex-wrap: wrap;
   */
  flex-flow: row wrap;

  /* Then we define how is distributed the remaining space */
  justify-content: space-around;
}
```

Done. Everything else is just some styling concern. Below is a pen featuring this example. Be sure to go to CodePen and try resizing your windows to see what happens.

See the Pen [Demo Flexbox 1](http://codepen.io/team/css-tricks/pen/EKEYob/).

Let's try something else. Imagine we have a right-aligned navigation on the very top of our website, but we want it to be centered on medium-sized screens and single-columned on small devices. Easy enough.

```css
/* Large */
.navigation {
  display: flex;
  flex-flow: row wrap;
  /* This aligns items to the end line on main-axis */
  justify-content: flex-end;
}

/* Medium screens */
@media all and (max-width: 800px) {
  .navigation {
    /* When on medium sized screens, we center it by evenly distributing empty space around items */
    justify-content: space-around;
  }
}

/* Small screens */
@media all and (max-width: 500px) {
  .navigation {
    /* On small screens, we are no longer using row direction but column */
    flex-direction: column;
  }
}
```

See the Pen [Demo Flexbox 2](http://codepen.io/team/css-tricks/pen/YqaKYR/).

Let's try something even better by playing with flex items flexibility! What about a mobile-first 3-columns layout with full-width header and footer. And independent from source order.

```css
.wrapper {
  display: flex;
  flex-flow: row wrap;
}

/* We tell all items to be 100% width */
.header,
.main,
.nav,
.aside,
.footer {
  flex: 1 100%;
}

/* We rely on source order for mobile-first approach
 * in this case:
 * 1\. header
 * 2\. nav
 * 3\. main
 * 4\. aside
 * 5\. footer
 */

/* Medium screens */
@media all and (min-width: 600px) {
  /* We tell both sidebars to share a row */
  .aside {
    flex: 1 auto;
  }
}

/* Large screens */
@media all and (min-width: 800px) {
  /* We invert order of first sidebar and main
   * And tell the main element to take twice as much width as the other two sidebars 
   */
  .main {
    flex: 2 0px;
  }

  .aside-1 {
    order: 1;
  }
  .main {
    order: 2;
  }
  .aside-2 {
    order: 3;
  }
  .footer {
    order: 4;
  }
}
```

See the Pen [Demo Flexbox 3](http://codepen.io/team/css-tricks/pen/jqzNZq/).

### [Prefixing Flexbox](#flexbox-sass)

Flexbox requires some vendor prefixing to support the most browsers possible. It doesn't just include prepending properties with the vendor prefix, but there are actually entirely different property and value names. This is because the Flexbox spec has changed over time, creating an ["old", "tweener", and "new"](http://css-tricks.com/old-flexbox-and-new-flexbox/) versions.

Perhaps the best way to handle this is to write in the new (and final) syntax and run your CSS through [Autoprefixer](http://css-tricks.com/autoprefixer/), which handles the fallbacks very well.

Alternatively, here's a Sass @mixin to help with some of the prefixing, which also gives you an idea of what kind of things need to be done:

```css
@mixin flexbox() {
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
}

@mixin flex($values) {
  -webkit-box-flex: $values;
  -moz-box-flex: $values;
  -webkit-flex: $values;
  -ms-flex: $values;
  flex: $values;
}

@mixin order($val) {
  -webkit-box-ordinal-group: $val;
  -moz-box-ordinal-group: $val;
  -ms-flex-order: $val;
  -webkit-order: $val;
  order: $val;
}

.wrapper {
  @include flexbox();
}

.item {
  @include flex(1 200px);
  @include order(2);
}
```

### [Related Properties](#flexbox-related)

- [A Complete Guide to Grid](//css-tricks.com/snippets/css/complete-guide-grid/)
- Almanac entries on Grid properties, like [grid-row / grid-column](https://css-tricks.com/almanac/properties/g/grid-row-column/)

### [Bugs](#flexbox-bugs)

Flexbox is certainly not without its bugs. The best collection of them I've seen is Philip Walton and Greg Whitworth's [Flexbugs](https://github.com/philipwalton/flexbugs). It's an open source place to track all of them, so I think it's best to just link to that.
]]></description>
            <link>https://hungvn.com/blog/huong-dan-toan-tap-ve-flexbox</link>
            <guid isPermaLink="true">https://hungvn.com/blog/huong-dan-toan-tap-ve-flexbox</guid>
            <pubDate>Thu, 31 Aug 2017 15:32:14 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Cách thức hoạt động của Flexbox - Giải thích với ảnh gif đầy màu sắc]]></title>
            <description><![CDATA[
Flexbox hứa hẹn sẽ giải quyết nhiều vấn đề hiện đang tồn tại trong CSS thuần (ví dụ như căn chỉnh chiều dọc).

Nhưng để có thể làm chủ và sử dụng được flexbox thì lại là việc không hề dễ dàng.

Nguyên tắc cơ bản của Flexbox là làm cho việc dàn trang linh hoạt và trực quan hơn.

Để thực hiện được điều này, các thành phần bao ngoài (containers) được tự quyết định cách phân bố các phần tử con (items) – bao gồm cả kích thước và khoảng cách giữa chúng.

Điều này về nguyên tắc nghe có vẻ tốt. Nhưng chúng ta hãy xem nó có vẻ như trong thực tế.

Trong bài viết này, chúng ta sẽ nghiên cứu 5 thuộc tính nổi trội nhất của Flexbox, khám phá chức năng cũng như cách sử dụng chúng và kết quả đạt được.

### Thuộc tính #1: Display: Flex

Hãy xem ví dụ trang web dưới đây:

![](https://cdn-images-1.medium.com/max/2000/1*ifusEqwI87nBKXgK9oZ_7A.gif)

Có 4 thẻ divs kích cỡ khách nhau được đánh dấu với các màu khác nhau đặt trong thẻ div container màu xám. Mặc định mỗi thẻ div sẽ có thuộc tính là `display: block`. Mỗi ô vuông vì vậy sẽ chiếm hết bề ngang của mỗi dòng.

Để bắt đầu với Flexbox, bạn cần đưa **container** của bạn về dạng của **flex container** như sau:

```css
#container {
  display: flex;
}
```

![](https://cdn-images-1.medium.com/max/2000/1*L2W-ziqU45a1BNWV79ijDQ.gif)

Chưa có thay đổi gì ngoài việc các thẻ div hiển thị trên cùng một dòng. Tuy nhiên đây lại là một sự thay đổi rất đáng kể. **Chúng ta đặt tên cho vùng xung quanh đó gọi là _flex context_.**

Bây giờ bạn có thể bắt đầu định vị trí cho chúng mà không gặp nhiều khó khăn như khi sử dụng CSS thông thường

### Thuộc tính #2: Flex Direction

Một Flexbox container có hai trục: **một trục chính** và **một trục dọc**, mặc định hiển thị như dưới đây:

![](https://cdn-images-1.medium.com/max/1600/1*_Ruy6jFG7gUpSf76IUcJTQ.png)

**Mặc định, các items được sắp xếp theo hướng của trục chính, từ trái qua phải**. Đây là lí do tại sao các ô vuông hiển thị trên cùng một dòng khi bạn sử dụng `display: flex`.

Tuy nhiên, bạn có thể thay đổi trục chính bằng thuộc tính `Flex-direction`.

```css
#container {
  display: flex;
  flex-direction: column;
}
```

![](https://cdn-images-1.medium.com/max/2000/1*4yKnG2-vuPF5XA-BmXADLQ.gif)

Có một sự khác biệt quan trọng tạo ra ở đây: `flex-direction: column` không sắp xếp các ô vuông trên trục dọc (across axis) thay vì trục chính (main axis). **Nó làm trục chính thay đổi, xoay từ ngang thành dọc.**

Bạn có thể sắp xếp flex-direction theo một số cách khác như: _row-reverse_ and _column-reverse._

![](https://cdn-images-1.medium.com/max/2000/1*PBr_ncouIehALaEOWmSbpQ.gif)

### Thuộc tính #3: Justify Content

_Justify-content_ sắp xếp các items theo theo **main axis.**

Chúng ta sẽ nghiên cứu chi tiết hơn về sự khác nhau giữa trục chính và trục dọc. Trước hết, hãy quay lại với flex-direction: row.

```css
#container {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
}
```

Bạn có năm thuộc tính để sử dụng với _justify-content_:

1.  Flex-start
2.  Flex-end
3.  Center
4.  Space-between
5.  Space-around

![](https://cdn-images-1.medium.com/max/2000/1*2-6Tw8jqWrMKOfIugKyuDA.gif)

Sự khác nhau giữa space-around và space-between hơi khó để nhận ra. **Với space-between, các ô vuông sẽ được căn cách đều nhau, không bao gồm khoảng cách giữa ô vuông đầu và cuối với container**

Space-around đặt một khoảng cách ở hai bên cạnh mỗi ô vuông — có nghĩa là **khoảng cách giữa ô vuông ngoài cùng phía đầu và cuối với container sẽ bằng một nửa khoảng cách giữa các ô vuông với nhau** (Giả sử mỗi ô vuông đều có một giá trị căn lề bằng nhau và không bị ghi đè, vì vậy khoảng cách giữa 2 ô vuông sẽ gấp đôi).

Chú ý: Hãy nhớ rằng thuộc tính **justify-content hoạt động theo trục chính**, và **flex-direction làm thay đổi trục chính**. Đây là điều quan trọng nhất để bạn chuyển sang phần tiếp theo…

### Thuộc tính #4: Align Items

Nếu như bạn đã nắm được thuộc tính justify-content, align-items sẽ không khó khăn.

Trong khi justify-content hoạt động theo trục chính, **align-items áp dụng đối với trục dọc.**

![](https://cdn-images-1.medium.com/max/1600/1*_Ruy6jFG7gUpSf76IUcJTQ.png)

Hãy thiết lập lại _flex-direction_ thành row, để hai trục hiển thị như hình trên.

Sau đó, bắt đầu đi sâu vào giá trị của align-items.

1.  flex-start
2.  flex-end
3.  center
4.  stretch
5.  baseline

Ba giá trị đầu tiên chính xác là giống như _justify-content_, vì vậy không có gì quá lạ ở đây.

Tuy nhiên, hai giá trị kế tiếp có một chút khác biệt.

Với giá trị stretch, các items sẽ chiếm toàn bộ trục chính, và baseline, đáy của những tags paragraph sẽ được canh đều.

![](https://cdn-images-1.medium.com/max/2000/1*htfdNmRIIFu_veRaFOj5qA.gif)

(Chú ý với `align-items: stretch`, Tôi đã phải đặt chiều cao của ô vuông là auto. Nếu không, thuộc tính chiều cao sẽ ghi đè lên stretch.)

Với baseline, hãy lưu ý rằng nếu bạn bỏ đi tags paragraph, các ô vuông sẽ được căn lề dưới như hình sau:

![](https://cdn-images-1.medium.com/max/2000/1*6dd9KnKMUN49lFsbHlJi6A.png)

Để minh họa rõ hơn cho trục chính và trục dọc với nó, hãy kết hợp thuộc tính justify-content và align-items và xem sự khác biệt giữa 2 giá trị center của thuộc tính flex-direction:

![](https://cdn-images-1.medium.com/max/2000/1*6mq-Uay7t6NhdF2E41Do0g.gif)

**Với dòng, các ô vuông được thiết lập dọc theo một trục chính ngang. Với cột, chúng xếp dọc theo trục chính thẳng đứng.**

Các ô vuông được căn giữa cả theo trục ngang và dọc trong 2 trường hợp, cả 2 trường hợp đều ko thay đổi!

### Thuộc tính #5: Align Self

_Align-self_ cho phép bạn thao tác thủ công liên kết của một phần tử riêng biệt.

Nó sẽ đè lên thuộc tính _align-items_ của 1 ô vuông. Tất cả thuộc tính đều như nhau, bởi vì mặc định nó là _auto_, nên các ô vuông sẽ theo thuộc tính _align-items_ của container bao nó.

```css
#container {
  align-items: flex-start;
}
.square#one {
  align-self: center;
}
// Only this square will be centered.
```

Hãy xem kết quả. Bạn sẽ đặt thuộc tính _align-self_ cho 2 ô vuông, và thuộc tính `align-items: center` và `flex-direction: row` với các ô vuông còn lại.

![](https://cdn-images-1.medium.com/max/2000/1*HIADl1oL6pxXb2dMh_pXSQ.gif)

### Conclusion

Mặc dù chỉ là những tìm hiểu cơ bản về Flexbox, tôi tin những điều này cũng cung cấp cho bạn những kiến thức để dàn trang một cách cơ bản nhất cũng như sắp xếp nội dung chính bài viết của bạn.

Cảm ơn vì đã đọc!
]]></description>
            <link>https://hungvn.com/blog/cach-thuc-hoat-dong-cua-flexbox</link>
            <guid isPermaLink="true">https://hungvn.com/blog/cach-thuc-hoat-dong-cua-flexbox</guid>
            <pubDate>Thu, 31 Aug 2017 09:45:26 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Trở thành Functional Programmer - Phần 6]]></title>
            <description><![CDATA[
Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những bước khó khăn nhất. Nhưng với cách tiếp cận đúng đắn, mọi thứ sẽ trở nên dễ hiểu hơn rất nhiều. Và đây là series được tạo ra nhằm mục đích giúp các bạn dễ thở hơn trong quá trình tiếp cận với FP.

## Bước tiếp theo

![](https://viblo.asia/uploads/6b50d1f5-1c5c-4d80-ab29-3ed59965a08d.png)

Thông qua 5 phần trước, tôi đã giới thiệu đến các bạn tất cả các concepts tuyệt vời mà FP mang lại, nhưng đồng thời cũng dấy lên trong các bạn câu hỏi : "Giờ thì sao? Liệu những kiến thức đó có thể có ích gì cho tôi trong công việc hàng ngày chứ?"

Câu trả lời sẽ là tùy theo từng người. Nếu bạn có thể/đang làm việc với các ngôn ngữ _Pure Functional Language_ như là Elm hay Haskell, thì bạn có thể tận dụng toàn bộ những kiến thức đã đề cập đến, đồng thời các ngôn ngữ đó sẽ hỗ trợ bạn trong việc vận dụng chúng một cách thuận tiện nhất.

Còn nếu bạn vẫn đang tiếp tục sử dụng các ngôn ngữ Imperative như Javascript - giống như hầu hết các lập trình viên hiện nay, thì bạn vẫn có thể vận dụng những concepts đã học được, nhưng sẽ cần một vài tùy chỉnh và nguyên tắc cần tuân thủ.

## Functional Javascript - Code JS theo hướng Functional

![](https://viblo.asia/uploads/3c9b615c-9302-4e69-a56e-c1bab6177ee2.png)

Javascript có thể thực hiện rất nhiều concepts của FP. Mặc dù nó không `thuần khiết` (pure) cho lắm, nhưng JS vẫn có lựa chọn để sử dụng khả năng immutability (tính bất biến) hoặc nếu sử dụng các thư viện đã có, thì việc hỗ trợ FP concepts còn mạnh mẽ hơn.

Mặc dù áp dụng FP vào JS không hoàn toàn lý tưởng, nhưng nếu bạn có thể tận dụng một vài lợi ích từ FP thì tại sao không thử nhỉ?

### Immutability - Tính bất biến

Điều đầu tiên mà ta có thể xem xét áp dụng là tính bất biến. Trong phiên bản ES2015 - hay còn gọi là ES6, có một từ khóa mới đã được giới thiệu có tên là **const**. Và đúng như tên gọi của từ khóa này, nó được dùng để khai báo một biến mà giá trị không thể gán lại được :

```
const a = 1;
a = 2; //  sẽ có exception có tên là TypeError trong Chrome, Firefox hoặc Node
       // nhưng không có nếu dùng Safari (bản 10/2016)

```

Ở đây biến `a` được khai báo là một `hằng số` (const) nên nó sẽ không thể được set lại giá trị nữa. Vì thế mà đoạn code `a = 2` sẽ sinh ra Exception (ngoại trừ Safari).

Tuy nhiên, có một vấn đề với `const`, đó là nó vẫn chưa hoàn toàn implement tính bất biến _một cách đầy đủ_. Đoạn code dưới đây sẽ thể hiện hạn chế này:

```
const a = {
    x: 1,
    y: 2
};
a.x = 2; // KHÔNG CÓ EXCEPTION!
a = {}; // có exception TypeError

```

Bạn sẽ thấy rằng khi set `a.x = 2` thì sẽ **không** gây ra lỗi. Thứ duy nhất mà từ khóa `const` áp dụng để kiểm tra tính bất biến chỉ là biến `a`. Còn tất cả những thành phần mà a có thể liên kết đến thì vẫn có thể thay đổi được (Ở đây sẽ hiểu là keyword `const` chỉ check `a` có là object vẫn tạo ra từ đầu hay không, mà _không_ check được các thuộc tính của a bị thay đổi).

Tôi thấy khá là thất vọng khi nhận ra điều này, vì nếu được implement một cách hoàn hảo, JS đã có thể trở nên tốt hơn rất nhiều.

Vậy liệu có cách nào để chúng ta có thể áp dụng tính bất biến vào JS một cách toàn diện nhất không?

Câu trả lời là _Có thể_, nhưng chúng ta phải sử dụng một thư viện có tên là [Immutable](https://facebook.github.io/immutable-js/). Thư viện này sẽ hỗ trợ tính bất biến tốt hơn so với `const` nhưng lại khiến code của chúng ta giống Java hơn là Javascript.

### Currying và Composition

Ở các series trước đó, chúng ta đã học được cách viết hàm hỗ trợ khả năng **Currying**. Dưới đây là một ví dụ phức tạp hơn:

```
const f = a => b => c => d => a + b + c + d

```

Để ý rằng phiền toái đầu tiên là chúng ta phải chỉ rõ phần currying (`a => b => c => d`)

Và nếu phải gọi hàm `f`, thì mọi thứ sẽ còn phức tạp hơn

```
console.log(f(1)(2)(3)(4)); // prints 10

```

Quá nhiều dấu ngoặc đơn như trên là đủ để khiến lập trình Lisp phải khóc ròng rồi (Lisp dùng nhiều dấu ngoặc đơn, nên nếu lập trình viên Lisp còn phải khóc trước số lượng dấu ngoặc đơn như này thì đủ thấy sự kinh khủng của dòng code trên là như nào :D)

Và vì thế có rất nhiều thư viện để giải quyết vấn đề này. Và thư viện mà tôi thích nhất có tên là [Ramda](http://ramdajs.com/)

Khi dùng Ramda thì chúng ta có thể viết lại đoạn code trên như sau:

```
const f = R.curry((a, b, c, d) => a + b + c + d);
console.log(f(1, 2, 3, 4)); // prints 10
console.log(f(1, 2)(3, 4)); // also prints 10
console.log(f(1)(2)(3, 4)); // also prints 10

```

Phần định nghĩa hàm không được cải thiện nhưng lắm, nhưng chúng ta đã loại bỏ được việc yêu cầu phải viết dấu ngoặc đơn ở phần gọi hàm phía sau. Đồng thời mỗi lần gọi hàm 'f', chúng ta có thể áp dụng đúng hoặc ít hơn số lượng tham số nếu muốn.

Dưới đây sẽ là code viết lại hàm `mult5AfterAdd10` (ở [Phần 4](https://viblo.asia/ta.duy.anh/posts/AoDKYNWQzvg)) sử dụng Ramda:

```
const add = R.curry((x, y) => x + y);
const mult5 = value => value * 5;
const mult5AfterAdd10 = R.compose(mult5, add(10));

```

Ngoài khả năng trên, Ramda còn có một số hàm đã được viết sẵn để hỗ trợ việc viết các hàm theo phong cách **Currying**, ví dụ như là `R.add` hoặc `R.multiply`, giúp chúng ta đỡ phải viết nhiều code hơn:

```
const mult5AfterAdd10 = R.compose(R.multiply(5), R.add(10));

```

### Các hàm Map, Reduce, Filter trong JS

Một khả năng nữa của thư viện Ramda là việc cung cấp sẵn các hàm `map, filter, reduce`. Mặc dù các hàm này đã có trong `Array.prototype` của JS core, nhưng các hàm này của Ramda cao cấp hơn ở chỗ chúng là các **curried function**.

```
const isOdd = R.flip(R.modulo)(2);
const onlyOdd = R.filter(isOdd);
const isEven = R.complement(isOdd);
const onlyEven = R.filter(isEven);

const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(onlyEven(numbers)); // prints [2, 4, 6, 8]
console.log(onlyOdd(numbers)); // prints [1, 3, 5, 7]

```

Hàm `R.modulo` yêu cầu 2 tham số, đầu tiên là `dividend` (số bị chia), tiếp theo là `divisor` (số chia).

Biến `isOdd` sẽ là hàm được dùng để lấy ra phần dư của việc lấy số bị chia chia cho 2\. Nếu phần dư là 0 sẽ tương đương với giá trị `false`, thể hiện số bị chia không phải là số lẻ, còn nếu phần dư là 1 thì sẽ tương đương với giá trị `true`, thể hiện số bị chia là số lẻ. Hàm `R.flip` được dùng để đổi vị trí giữa 2 tham số của hàm `R.modulo`, khiến giá trị tham số truyền vào lúc đầu sẽ là số chia (ở đây là 2).
(kết quả cuối cùng khi gọi `isOdd` với 1 tham số sẽ trả về kết quả là tham số đó có phải là số chẵn hay không. VD `isOdd(4) = false` hay `isOdd(5) = true`).

Và hàm `isEven` sẽ là `phần bù` của hàm `isOdd` (tức là giá trị trả về của `isEven` sẽ ngược với `isOdd` nên ta có thể sử dụng hàm `R.complement`)

Tiếp theo, hàm `onlyOdd` là kết quả của hàm `filter` với hàm dùng để lọc dữ liệu là `isOdd`, và hàm này sẽ cần tham số là một mảng các số nguyên để thực hiện. Tương tự với hàm `onlyEven`, chỉ khác là hàm này dùng `isEven` là hàm để lọc dữ liệu.

Khi chúng ta truyền một mảng vào tham số `numbers` tới hàm `onlyOdd` hoặc `onlyEven`, hàm `isOdd` và `isEven` sẽ nhận tham số là từng phần tử trong mảng và thực hiện trả về kết quả 0 hoặc 1, tương ứng với true và false, và từ đó hàm `onlyOdd` hoặc `onlyEven` sẽ giữ lại các giá trị mong muốn (chỉ số lẻ hoặc số chẵn).

### Những thiếu sót của Javascript

![](https://viblo.asia/uploads/61005b31-42b4-4169-9658-962efb65efbb.png)

Với tất cả những thư viện và những tính năng được chính JS hỗ trợ, chúng ta có thể có những bước tiến nhất định trong việc áp dụng FP vào JS. Tuy nhiên, có một sự thật không thể chối cãi rằng JS vẫn chỉ là một Imperative Language đang cố để thỏa mãn tất cả mọi người.

Rất nhiều lập trình viên frontend đang mắc kẹt với JS bởi lẽ đến thời điểm hiện tại, đó hầu như là lựa chọn duy nhất và không thể tránh khỏi. Nhưng xu hướng hiện nay thì rất nhiều lập trình viên JS đang viết code JS _một cách không trực tiếp_.

Thay vào đó, họ viết **một ngôn ngữ khác** và biên dịch, hay nói chính xác hơn, biến đổi chúng thành Javascript.

Một trong số các ngôn ngữ cho việc trên là **CoffeScript**. Và với AngularJS 2, **TypeScript** đã được giới thiệu với tính năng tương tự. Ngoài ra thì **Babel** cũng được coi như một công cụ để biến đổi JS.

Xu thế hiện nay cho thày càng ngày càng có nhiều người sử dụng cách tiếp cận này trong sản phẩm của mình.

Nhưng hạn chế rõ ràng nhất là các ngôn ngữ này đều xuất phát từ JS và chỉ có thể làm nó tốt hơn _một chút_ mà thôi. Vậy thì sao chúng ta không triệt để hẳn, biến đổi từ một ngôn ngữ _Pure Functional Language_ sang JS nhỉ? Và đó chính là cách mà Elm được phát triển.

## Elm

![](https://viblo.asia/uploads/4e572de0-6b64-4b16-9b57-b0771c9ce188.png)

Trong suốt series này, chúng ta đã từng sử dụng `Elm` để hỗ trợ trong việc hiểu về FP.

### Vậy Elm là gì? Và chúng ta có thể dùng Elm như thế nào?

Elm là một ngôn ngữ hoàn toàn là **Pure Functional Language**, mà source code được viết bởi Elm sau đó sẽ được biến đổi thành code Javascript. Và vì thế, ta có thể sử dụng Elm để tạo ra các Web Application theo [Kiến Trúc Elm](https://guide.elm-lang.org/architecture/), hay còn gọi là TEA (kiến trúc này thực tế đã gây cảm hứng cho các kỹ sư tạo ra Redux).

Ngôn ngữ Elm sẽ không có bất kỳ lỗi `Runtime Error` nào (lỗi khi thực hiện code).

Elm đã được sử dụng trong môi trường production (môi trường sản phẩm thật) bởi các công ty như là [NoRedink](https://www.noredink.com/), mà công ty đó hiện đang có Evan Czapliki - người tạo ra Elm - làm việc (trước đây ông đã làm cho [Prezi](https://prezi.com/)).

Để biết thêm chi tiết, mời các bạn tham khảo bài nói chuyện [6 tháng làm Elm với production](https://www.youtube.com/watch?v=R2FtMbb-nLs), được tạo ra bởi Richard Feldman và những tín đồ Elm.

### Liệu tôi có phải thay đổi tất cả code JS của mình bằng Elm không?

Không. Bạn có thể thay thế từng phần một. Bài viết sau đây sẽ mô tả chi tiết khả năng này : [Làm thế nào để sử dụng Elm trong công việc](http://elm-lang.org/blog/how-to-use-elm-at-work)

### Vì sao học Elm?

1.  Làm việc với một ngôn ngữ _Pure Functional Language_ vừa có sự hạn chế và sự tự do. Sự hạn chế đến từ việc bạn không thể làm những thứ đã làm được trước đó (mà những thứ này hầu hết lại giới hạn output mà bạn có thể tạo ra), nhưng đồng thời, sự tự do sẽ được thể hiện ở những phần mềm không có lỗi, có thiết kế tốt, bởi lẽ các phần mềm được viết bởi Elm sẽ tuân theo TEA (Kiến trúc Elm), một mô hình phù hợp với FP.
2.  FP sẽ giúp bạn trở thành một lập trình viên chất lượng hơn. Tất cả các ý tưởng trong series bài viết này chỉ là những phần trên của tảng băng trôi. Chỉ khi áp dụng chúng vào trong thực tế, bạn mới biết được sự lợi hại và hữu ích của FP trong việc phát triển các phần mềm phù hợp với nhiều yêu cầu, đồng thời tăng trưởng một cách ổn định.
3.  Javascript là một ngôn ngữ được viết trong 10 ngày, sau đó được chỉnh sửa trong 2 thập kỉ gần đây để cố gắng trở thành một ngôn ngữ vừa functional, vừa hướng đối tượng, trong khi bản chất vẫn là một imperative language. Trong khi đó, Elm được thiết kế dựa trên 30 năm kinh nghiệm làm việc với Haskell, và hàng thập kỷ nghiên cứu trong toán học cũng như khoa học máy tính. Đồng thời kiến trúc Elm(TEA) đã được thiết kế và tinh chỉnh hàng năm trời, và là kết quả từ luận văn của Evan về vấn đề hỗ trợ functional của các ngôn ngữ lập trình. Bạn có thể tham khảo bài nói [Watch Controlling Time and Space](https://www.youtube.com/watch?v=Agu6jipKfYw) để biết rõ hơn Evan đã hiện thực hóa ý tưởng của mình như thế nào khi thiết kế ra TEA
4.  Elm được thiết kế cho lập trình viên frontend. Mục tiêu của nó là khiến cuộc đời lập trình viên dễ thở hơn. Mời tham khảo bài nói [Let's be Mainstream](https://www.youtube.com/watch?v=oYk8CKH7OhE) để hiểu rõ hơn mục tiêu này.

## Tương lai

![](https://viblo.asia/uploads/9c50b295-7b38-4ed4-9b8c-27ebe0e5984e.png)

Việc biết trước tương lai sẽ diễn biến như thế nào là bất khả thi, nhưng chúng ta có thể có một vài dự đoán có cơ sở. Dưới đây là các dự đoán của tôi về tương lai:

> Sẽ có thêm nhiều ngôn ngữ được viết để biến đổi ra JS.
> Các ý tưởng của FP đã tồn tại trên 40 năm sẽ được tái nhìn nhận và sử dụng để giải quyết những vấn đề phức tạp của phần mềm hiện nay
> Hiện trạng của các thiết bị phần cứng hiện nay, như hàng Gigabytes bộ nhớ giá rẻ và chip xử lý nhanh sẽ biến các kỹ thuật FP thành khả thi
> CPUs sẽ tăng trưởng theo hướng có nhiều nhân hơn là tăng tốc độ xử lý
> Phần mềm có trạng thái biến đổi khi thực hiện sẽ được coi là một trong những vấn đề lớn nhất trong các hệ thống phần mềm phức tạp.

Lý do khiến tôi viết series này là bởi vì tôi tin rằng FP sẽ là tương lai của ngành phần mềm, và bởi vì tôi cũng đã tốn vài năm để học nó (hiện tại tôi _vẫn đang tiếp tục học FP_)

Nên mục tiêu của tôi với bài viết này là để giúp mọi người có thể hiểu được những concepts của FP một cách dễ dàng và nhanh chóng hơn so với tôi, đồng thời nếu có thể - giúp các bạn trở thành những lập trình viên tốt hơn, và có sự nghiệp sáng giá trong tương lai.

Kể cả việc dự đoán rằng Elm sẽ là một ngôn ngữ phát triển trong tương lai của tôi có thể sai, thì tôi vẫn có thể tự tin khẳng định rằng FP và Elm sẽ nằm trên quỹ đạo chuyển động của tương lai - cho dù đó là tương lai nào đi nữa.

Hy vọng rằng sau series này, mọi người sẽ tự tin hơn vào khả năng của mình, cũng như củng cố, nắm vững được những concepst mà tôi đã giới thiệu.

Lời cuối cùng, chúc mọi người may mắn trong những nỗ lực phía trước.

Nếu bạn muốn tham gia vào cộng đồng các nhà phát triển web muốn học và giúp đỡ lẫn nhau về FP trong Elm, mời các bạn tham gia Group Facebook sau: [Learn Elm Programming](https://www.facebook.com/groups/learnelm/)

Và đây là Twitter của tác giả : [@cscalfani](https://twitter.com/cscalfani)
]]></description>
            <link>https://hungvn.com/blog/tro-thanh-functional-programmer-phan-6</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tro-thanh-functional-programmer-phan-6</guid>
            <pubDate>Wed, 23 Aug 2017 23:30:13 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Trở thành Functional Programmer - Phần 5]]></title>
            <description><![CDATA[
Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những bước khó khăn nhất. Nhưng với cách tiếp cận đúng đắn, mọi thứ sẽ trở nên dễ hiểu hơn rất nhiều. Và đây là series được tạo ra nhằm mục đích giúp các bạn dễ thở hơn trong quá trình tiếp cận với FP.

## Concept 8 : Referential Transparency - Tham chiếu minh bạch

![](https://viblo.asia/uploads/d95f1311-8901-4647-b860-a531066cf329.png)

**Referential Transparency - Tham chiếu minh bạch** là một cụm từ khá là màu mè được dùng để mô tả khả năng của **pure function** (nếu chưa rõ pure function là gì, mời xem lại [Phần 1](https://viblo.asia/ta.duy.anh/posts/PqOzvNbWzAB)) khi các vị trí sử dụng **pure function** đều _có thể được thay thế bằng phần định nghĩa của chính nó_ (nói đơn giản là chỗ nào gọi hàm thì đều có thể thay thế bằng phần thân - các biểu thức định nghĩa hàm). Ví dụ dưới đây sẽ giúp chúng ta hiểu rõ hơn.

Giả sử ta có một **biểu thức toán học** khá quen thuộc như sau :

`y = x + 10`

Và khi gán giá trị cụ thể cho `x`:

`x = 3`

Thì chúng ta có thể thay thế `3` ở vị trí của `x` vào biểu thức, khiến biểu thức trở thành :

`y = 3 + 10`

Có thể thấy là `y = 3 + 10` vẫn là một biểu thức hoàn toàn hợp lệ. Và với _pure function_, việc thay thế tương tự như trên là hoàn toàn có thể.

Dưới đây là một hàm trong Elm được dùng để thêm dấu nháy đơn vào trước và sau một String :

```
quote str =
       "'"  ++ str ++ "'"

```

Và đây là một ngữ cảnh dùng hàm ở trên:

```
findError key =
     "Unable to find " ++ (quote key)

```

Ở đấy hàm `findError` sẽ xuất ra một message thông báo lỗi khi việc tìm kiếm `key` không thành công.

Vì hàm `quote` là một `pure function`, chúng ta có thể thay thế việc gọi hàm đó trong thân hàm `findError` bằng chính _phần thân hàm của hàm quote_ như sau :

```
findError key =
     "Unable to find " ++ ("'"  ++ str ++ "'" )

```

Việc thay thế này tôi gọi là **Tái cấu trúc ngược - Reverse Refactoring** (vì nó nghe hợp tai thôi), và được định nghĩa là quá trình có thể được sử dụng bởi lập trình viên hoặc chương trình phần mềm (ví dụ như bộ biên dịch - compiler hay là phần mềm test) để hiểu về ý nghĩa và luồng hoạt động của code, đặc biệt khi tìm hiểu các hàm đệ quy.

## Execution Order - Thứ tự thực hiện

![](https://viblo.asia/uploads/4522e8c2-c5eb-4315-9408-b70264c3bf5f.png)

Hầu hết các phần mềm hiện nay đều là đơn luồng (single-thread), có nghĩa là trong một thời điểm, có một và chỉ một đoạn code được thực hiện. Ngay cả khi bạn làm ra một phần mềm theo hướng đa luồng, hầu hết các luồng sẽ bị chặn và phải chờ cho các tác vụ xử lý I/O hoàn thành (tác vụ I/O là các tác vụ liên quan đến xử lý input và output của hệ thống như `file, network,...`

Dưới đây là một cách lý giải cho việc chúng ta thường sẽ nghĩ theo các bước tuần tự khi viết code. Trước hết hãy xem ví dụ sau :

```
1. Lấy bánh mỳ
2. Đặt 2 lát bánh mỳ vào máy nướng
3. Chọn mức nướng
4. Bấm nút bắt đầu nướng
5. Chờ cho đến khi bánh mỳ nướng xong
6. Cất máy nướng
7. Lấy bơ
8. Lấy dao cắt bơ
9. Phết bơ vào bánh mỳ nướng

```

Nhìn vào các bước thực hiện cho việc tạo ra bánh mỳ nướng bơ ở trên, chúng ta có thể thấy có 2 luồng hoạt động độc lập : Lấy bơ và nướng bánh. Và 2 luồng hoạt động này chỉ tương tác với nhau ở bước cuối cùng - bước thứ 9.

Vì thế chúng ta có thể thực hiện 2 công việc sau song song với nhau : 1 việc bao gồm các bước từ 1 đến 6, và 1 việc bao gồm 2 bước 7 và 8\. Và ta sẽ đưa 2 công việc này thành 2 luồng.

Nhưng khi chúng ta làm như vậy, mọi thứ sẽ trở nên phức tạp hơn :

> ## Luồng thứ 1
>
> 1.  Lấy bánh mỳ
> 2.  Đặt 2 lát bánh mỳ vào máy nướng
> 3.  Chọn mức nướng
> 4.  Bấm nút bắt đầu nướng
> 5.  Chờ cho đến khi bánh mỳ nướng xong
> 6.  Cất máy nướng
>
> ## Luồng thứ 2
>
> 1.  Lấy bơ
> 2.  Lấy dao cắt bơ
> 3.  **Chờ luồng thứ nhất thực hiện xong**
> 4.  Phết bơ vào bánh mỳ nướng

Ở đây luồng thứ 2 có thêm một công việc là chờ luồng thứ 1 thực hiện xong. Vậy điều gì sẽ xảy ra với luồng thứ 2 nếu luồng thứ 1 thất bại? Nguyên tắc và cách thức để 2 luồng có thể giao tiếp và hợp tác với nhau là gì? Ai sẽ sở hữu bánh mỳ nướng: Luồng 1, luồng 2, hay cả hai?

Tất cả các câu hỏi trên sẽ xảy ra khi chúng ta muốn làm đa luồng, và nếu cứ để nguyên ở dạng đơn luồng, chúng ta có thể bỏ qua không cần phải suy nghĩ gì đến các vấn đề phức tạp ở trên. Vậy là bạn đã hiểu lý do vì sao con người luôn tự nhiên suy nghĩ và thực hiện công việc theo một luồng có thứ tự duy nhất rồi chứ.

Nhưng chúng ta cần nâng cao tối đa hiệu năng của phần mềm bằng mọi cách có thể, nên việc áp dụng đa luồng sẽ trở thành một điều ta cần nỗ lực để có thể đạt được những kết quả đáng ghi nhận.

Tuy nhiên, sẽ có 2 vấn đề khi làm việc với đa luồng. Đầu tiên, các phần mềm đa luồng sẽ rất khó để viết, đọc, lý giải, test và debug (đương nhiên rồi).

Thứ hai, một số ngôn ngữ như Javascript thì _không hỗ trợ đa luồng_, hoặc các ngôn ngữ có hỗ trợ thì _hỗ trợ một cách nghèo nàn_.

Nhưng sẽ ra sao nếu thứ tự thực hiện bỗng chốc trở nên không còn quan trọng nữa, mọi thứ có thể thực hiện song song?

Điều này nghe có vẻ điên rồ, nhưng tôi sẽ cho bạn thấy rằng nó _có thể_. Hãy xem một đoạn code Elm mô tả cho lý luận trên:

```
buildMessage message value =
    let
        upperMessage =
            String.toUpper message
        quotedValue =
            "'" ++ value "'"
    in
        upperMessage ++ ": " ++ value

```

Ở đây hàm `buildMessage` nhận 2 tham số là `message` và `value`, sau đó sẽ trả về `message` phiên bản chữ hoa, kèm với một dấu hai chấm và `value` nằm trong dấu nháy đơn.

Trong hàm này 2 biến `upperMessage` và `quotedValue` là độc lập với nhau. Ta sẽ cùng tìm hiểu lý do vì sao có thể kết luận được như vậy?

Để xét về tính độc lập, sẽ có 2 nội dung cần được xác nhận là đúng. Thứ nhất, các đối tượng được xét đến đều phải là `pure function`. Điều này là cực kỳ quan trọng bởi vì các đối tượng này **phải** biệt lập với các xử lý khác bên ngoài. Nếu các đối tượng này không `pure`, chúng ta sẽ không bao giờ biết được chúng có độc lập hay không. Và trong trường hợp đó, ta sẽ phải dựa vào thứ tự được gọi của các hàm này được viết trong code để xác định thứ tự thực hiện của chúng. Và đó là cách mà các ngôn ngữ Imperative hoạt động.

Thứ hai, để xác định tính độc lập, thì output của một hàm _không được các hàm còn lại lấy làm input_. Nếu điều này bị vi phạm, thì chúng ta sẽ phải chờ một hàm được thực hiện xong thì mới thực hiện tiếp hàm còn lại, và điều này thì khiến chúng không còn độc lập nữa.

Trong ví dụ tôi vừa nêu, cả `upperMessage` và `quotedValue` đều là kết quả của 2 hàm `pure` và chúng đều không yêu cầu output của lẫn nhau.

Do đó, 2 hàm này có thể thực hiện theo _BẤT KỲ THỨ TỰ NÀO_.

Bộ biên dịch (compiler) - vì thế có thể tự quyết định thứ tự thực hiện của 2 hàm trên mà không cần sự chỉ đạo cụ thể của người lập trình. Việc này chỉ có thể khả thi với các ngôn ngữ được xác định là **Pure Functional Language** (là các ngôn ngữ FP mà các biểu thức - expression đều là pure - hay nói cách khác, không tạo ra side-effect), bởi vì nếu không sẽ rất khó, thậm chí là không thể xử lý các side-effect khi chúng xảy ra.

> Thứ tự thực hiện trong các ngôn ngữ Pure Functional Language có thể được quyết định bởi trình biên dịch (compiler).

Đây thực sự là một lợi ích hiển nhiên khi trong thời đại ngày nay, các bộ vi xử lý thay vì được nâng cao tốc độ thì chúng sẽ được trang bị ngày càng nhiều nhân hơn. Việc thứ tự thực hiện có thể được quyết định bởi trình biên dịch sẽ khiến cho code có thể được chạy song song trên nhiều nhân một lúc, và vì thế, hiệu năng sẽ được nâng cao.

Đáng tiếc là với các ngôn ngữ Imperative, chúng ta không thể tận dụng tối đa việc CPU có nhiều nhân, trừ khi có sự thay đổi ở phần thấp, thậm chí là lõi của ngôn ngữ, mà khi đó thì sẽ kéo theo rất nhiều thay đổi trong kiến trúc của các phần mềm viết ra dựa trên các ngôn ngữ đó.

Với các ngôn ngữ **Pure Functional Language**, chúng ta sẽ có tiềm năng vận dụng các nhân của CPU một cách hiệu quả nhất mà không cần phải thay đổi bất cứ dòng code nào.

## Type Annotation - Xác định kiểu dữ liệu

![](https://viblo.asia/uploads/093aba53-f216-4df1-9017-4928ba25d45f.png)

Trong các ngôn ngữ có kiểu dữ liệu tĩnh (Statically Typed Language), kiểu được định nghĩa trong cùng 1 dòng. Dưới đây là một đoạn code Java để tham khảo :

```
public static String quote(String str) {
    return "'" + str + "'";
}

```

Bạn hãy để ý phần xác định kiểu trả về của hàm và của tham số đều được viết trong cùng dòng với phần định nghĩa hàm. Và khi ta dùng _generics_, thì nhìn còn tệ hơn nữa :

```
private final Map<Integer, String> getPerson(Map<String, String> people, Integer personId) {
   // ...
}

```

Ở đây các phần dùng để xác định kiểu dữ liệu sẽ là `Map<Integer, String>, Map<String, String>, Integer`, và bởi vì chúng nằm lẫn với phần định nghĩa hàm, chứa cả tên hàm và các biến, nên chúng ta sẽ mất thời gian và cần nhiều sự tập trung để có thế tìm ra tên các tham số.

Ngược lại, với các ngôn ngữ có kiểu dữ liệu động (Dynamically Typed Language), chúng ta không gặp phải vấn đề ở trên. Ví dụ như với Javascript, hàm ở trên sẽ chỉ cần viết như sau là đủ :

```
var getPerson = function(people, personId) {
    //...
};

```

Có thể thấy rằng phiên bản bằng JS ở trên _dễ đọc hơn rất nhiều_ vì ko có những khai báo kiểu dữ liệu loằng ngoằng như với phiên bản của Java. Vấn đề duy nhất ở đây là mặc dù dễ đọc hơn, nhưng chúng ta đã phải bỏ qua sự an toàn khi định nghĩa rõ kiểu dữ liệu. Ta có thể dễ dàng truyền vào các biến có kiểu không phù hợp, như là một số cho biến `people` hoặc một Object cho biến `personID`. Và việc truyền nhầm kiểu dữ liệu này chỉ có thể phát hiện đến khi các đoạn code được thực hiện, nên _có thể sẽ xảy ra lỗi sau khi chúng ta đã đưa code lên môi trường thật hàng tháng trời_. Nhưng với Java thì sẽ không gặp lỗi này, và sẽ được phát hiện khi code được biên dịch (compile).

Đó là những điểm lợi và bất lợi giữa kiểu dữ liệu động và tĩnh, và nếu chúng ta có thể kết họp ưu điểm của cả hai, bao gồm syntax đơn giản dễ hiểu bên phía Javascript và sự an toàn khi định rõ kiểu dữ liệu bên Java, thì chẳng phải sẽ rất tuyệt hay sao?

Và thực tế là chúng ta _có thể làm được_. Đây là một ví dụ về một hàm trong Elm với việc định rõ kiểu dữ liệu:

```
add : Int -> Int -> Int
add x y =
    x + y

```

Hãy để ý rằng thông tin về kiểu dữ liệu của tham số và giá trị trả về của hàm được viết bằng _một dòng riêng biệt_. Và sự tách riêng như này đem đến rất rất nhiều điều khác biệt.

Nếu lần đầu nhìn vào đoạn code trên, bạn có thể nghĩ rằng phần khai báo thông tin kiểu dữ liệu (dòng đầu tiên) có lỗi đánh máy. Tôi cũng đã từng cảm thấy như vậy. Lúc đó tôi đã nghĩ dấu `->` đầu tiên nên là dấu phẩy. Nhưng thực tế thì câu lệnh đó hoàn toàn chính xác.

Nếu đặt thêm vài dấu đóng mở ngoặc, bạn sẽ bắt đầu thấy nó có vẻ hợp lý hơn :

```
add : Int -> ( Int -> Int)

```

Biểu thức ở trên chỉ ra rằng hàm `add` là một hàm có **một** tham số có kiểu `Int` và trả về một hàm cũng có **một** tham số kiểu `Int`với kết quả trả về là một giá trị `Int`.

Dưới đây là một khai báo hàm phức tạp hơn một chút:

```
doSomething : String -> (Int -> (String -> String))
doSomething prefix value suffix =
    prefix ++ (toString value) ++ suffix

```

Đoạn code trên được dùng để khai báo một hàm có tên là `doSomething` sẽ nhận _một tham số_ có kiểu String, và trả về 1 hàm (tạm gọi là hàm A). Hàm A là hàm nhận _một tham số_ có kiểu `Int`, và trả về 1 hàm (hàm B). Hàm B là hàm nhận _một tham số_ có kiểu `String`, và trả về kết quả là giá trị kiểu `String`.

Có thể thấy rằng tất cả các hàm đều chỉ **có một tham số**. Đó là bởi tất cả các hàm trong Elm đều hỗ trợ **Currying**.

Và bởi vì dấu ngoặc đơn luôn được đặt vào từ phía ngoài cùng bên phải, lần lượt theo từng dấu mũi tên nên chúng ta có thể bỏ qua không cần chỉ định rõ, và kết quả sẽ là:

```
doSomething : String -> Int -> String -> String

```

Dấu ngoặc đơn chỉ thực sự cần thiết khi chúng ta muốn truyền hàm trong tham số. Nếu không sử dụng chúng thì việc xác định kiểu dữ liệu sẽ trở nên mù mờ. Ví dụ:

```
takes2Params : Int -> Int -> String
takes2Params num1 num2 =
    -- do something

```

sẽ khác hoàn toàn so với :

```
takes1Param : (Int -> Int) -> String
takes1Param f =
    -- do something

```

`take2Params` là một hàm yêu cầu 2 tham số `Int`, để có thể trả về giá trị kiểu `String`. Nhưng `take1Param` là hàm _yêu cầu 1 tham số là một hàm f, mà hàm f đó có 1 tham số là Int và trả về kết quả là Int_.

Và đây là phần định kiểu dữ liệu cho hàm `map` chúng ta đã dùng ở phần trước

```
map : (a -> b) -> List a -> List b
map f list =
    // ...

```

Ở đây dấu ngoặc đơn là cần thiết bởi vì hàm `f` dùng trong hàm `map` sẽ có kiểu là `(a -> b)`, với ý nghĩa là một hàm nhận vào giá trị kiểu `a` và trả về giá trị kiểu `b`.

Chữ `a` ở đây được hiểu với nghĩa là _bất kỳ kiểu nào_. Nếu một kiểu có ký tự hoa, thì nó sẽ là một kiểu cụ thể, ví dụ như `String`. Còn nếu một kiểu chỉ có ký tự thường, nó có thể là bất cứ kiểu dữ liệu nào. Vì thế kiểu `a` có thể là `String` hay `Int` đều được.

Nếu bạn nhìn thấy kiểu định nghĩa hàm là `(a -> a)` thì nó sẽ có ý nghĩa là kiểu dữ liệu của tham số và giá trị trả về **PHẢI** giống nhau, mặc dù có thể là bất kỳ kiểu dữ liệu nào (tức là nếu hàm nhận input kiểu `Int` thì phải trả về kiểu `Int`, nhận input kiểu `String` thì phải trả về kiểu `String`).

Nhưng trong trường hợp của hàm `map` được viết là `(a -> b)`. Điều đó có nghĩa là hàm `f` _Có thể_ trả về kiểu dữ liệu khác với tham số nhưng _CŨNG có thể_ trả về kiểu dữ liệu giống với kiểu của tham số.

Nhưng khi kiểu của `a` đã được xác định, thì `a` sẽ mang kiểu đó trong suốt phần định nghĩa kiểu dữ liệu của hàm. Ví dụ nếu `a` là kiểu `Int` và `b` là `String` thì định nghĩa kiểu dữ liệu phía trên của hàm `map` sẽ tương đương với :

```
(Int -> String) -> List Int -> List String

```

Bạn sẽ thấy rằng tất cả các chỗ dùng `a` trong định nghĩa kiểu dữ liệu đã được thay thế bằng `Int` (ở phần định nghĩa hàm `f` có `(a -> b)`, cũng như phần tham số thứ 2 là `List a`), và tất cả các chỗ dùng `b` đều được thay thế bằng `String`.

Kiểu dữ liệu `List Int` có nghĩa là một danh sách chứa các phần tử có kiểu `Int`, và `List String` tương đương với một danh sách chứa các phần tử có kiểu `String`. Nếu bạn đã từng sử dụng `generics` trong Java hoặc các ngôn gnữu khác, thì hẳn bạn sẽ thấy quen thuộc với concept này (ví dụ trong Java là `List<T>`).

## Đầu của tôi!!!!

![](https://viblo.asia/uploads/3cb3a723-1140-4d4c-abc8-9da098acc7d6.png)

Hôm nay đến đây thôi là đủ.

Trong phần tiếp theo, cũng là phần cuối cùng của series này, tôi sẽ đề cập đến việc sử dụng tất cả những concept mà tôi đã giới thiệu vào công việc hàng ngày như thế nào, cụ thể sẽ là trong việc lập trình Javascript nhưng theo hướng functional, và lập trình với Elm.

Nếu bạn muốn tham gia vào cộng đồng các nhà phát triển web muốn học và giúp đỡ lẫn nhau về FP trong Elm, mời các bạn tham gia Group Facebook sau: [Learn Elm Programming](https://www.facebook.com/groups/learnelm/)

Và đây là Twitter của tác giả : [@cscalfani](https://twitter.com/cscalfani)
]]></description>
            <link>https://hungvn.com/blog/tro-thanh-functional-programmer-phan-5</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tro-thanh-functional-programmer-phan-5</guid>
            <pubDate>Wed, 23 Aug 2017 23:28:13 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Trở thành Functional Programmer - Phần 4]]></title>
            <description><![CDATA[
Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những bước khó khăn nhất. Nhưng với cách tiếp cận đúng đắn, mọi thứ sẽ trở nên dễ hiểu hơn rất nhiều. Và đây là series được tạo ra nhằm mục đích giúp các bạn dễ thở hơn trong quá trình tiếp cận với FP.

## Concept 7 : Currying

![](https://viblo.asia/uploads/75b303cf-5fdd-4e50-bfc9-a3a847bbff55.png)

Tiếp tục câu chuyện ở cuối [Phần 3](https://viblo.asia/ta.duy.anh/posts/JdAGJgkgRgk) , lý do khiến chúng ta gặp phải vấn đề trong việc kết hợp hai hàm `mul5` và `add` là bởi vì hàm `mult5` có 1 tham số, trong khi hàm `add` lại có 2.

Chúng ta có thể giải quyết vấn đề này bằng cách giới hạn lại mỗi hàm chỉ lấy một tham số.

Nghe có vẻ hơi kỳ kỳ, nhưng tin tôi đi, ý tưởng này không tệ một chút nào đâu.

Chúng ta sẽ chỉ đơn giản là viết một hàm `add` vẫn có hai tham số, nhưng có khả năng nhận giá trị cho **một** tham số trong một thời điểm. Và hàm hỗ trợ khả năng này được biết đến với cái tên là _Curried Function_.

> Một Curried Fuction là một hàm chỉ nhận một tham số trong một thời điểm.

Điều này sẽ cho phép chúng ta gán giá trị tham số đầu tiên của hàm `add` _trước khi_ kết hợp với hàm `mult5`. Và sau đó khi hàm `mult5AfterAdd10` được gọi, hàm `add` sẽ nhận giá trị tham số thứ hai.

Trong Javascript, chúng ta có thể đạt được điều này bằng cách viết lại hàm `add` như sau:

```
var add = x => y => x + y

```

Phiên bản này của hàm `add` sẽ nhận hai tham số gồm `x` và `y`, nhưng _một tham số (x) sẽ được set khi gọi hàm lần đầu tiên_ và _tham số còn lại (y) sẽ được set khi gọi hàm lần thứ 2_.

Cụ thể hơn, đầu tiên, hàm `add` sẽ nhận giá trị cho tham số `x`, và trả về một **hàm** mới với một tham số có tên là `y`, với giá trị kết quả trả về là **tổng của hai tham số x và y**.

Và bây giờ chúng ta có thể sử dụng phiên bản trên của hàm `add` để tạo ra hàm `mult5AfterAdd10` như mong muốn :

```
var compose = (f, g) => x => f(g(x));
var mult5AfterAdd10 = compose(mult5, add(10));

```

Hàm `compose` sẽ nhận 2 tham số là `f` và `g`, và trả về một hàm nhận 1 tham số `x`, mà khi được gọi sẽ thực hiện lần lượt 2 hàm `g` và `f` lên với tham số nhận được (gọi hàm `g(x)`, kết quả nhận được truyền vào hàm `f`, tương đương với việc gọi `f(g(x))`).

Vậy chính xác ta đã làm gì? Theo lý thuyết thì ta đã tạo ra một phiên bản `curried function` của hàm `add` truyền thống. Việc này làm hàm `add` trở nên linh động hơn, bởi vì 2 tham số có thể được set ở 2 thời điểm khác nhau. Tham số đầu tiên, 10 được truyền vào để _tạo ra hàm mult5AfterAdd10_, và tham số thứ 2 được truyền vào khi _thực hiện hàm mul5AfterAdd10 với một tham số bất kỳ_.

Đến đây, bạn có thể nghĩ rằng làm thế nào để viết lại hàm `add` theo phong cách trên bằng ngôn ngữ Elm. Tôi xin giải đáp luôn là bạn không cần phải làm thế đâu. Trong Elm và các ngôn ngữ FP khác, **tất cả các hàm đều là curried function**.

Vậy là hàm `add` trong Elm vẫn giữ nguyên cách khai báo :

```
add x y =
    x + y

```

Và đây là cách mà hàm `mult5AfterAdd10` _nên_ được viết:

```
mult5AfterAdd10 =
    (mult5 << add 10)

```

Về mặt cú pháp, có thể nói rằng Elm đã đánh bại hoàn toàn Javascript cũng như các ngôn ngữ Imperative khác bởi vì nó đã được tối ưu cho những concept cơ bản của FP như là **Currying** hay **Composition**.

## Currying và Tái cấu trúc code

![](https://viblo.asia/uploads/02af022c-a568-4f90-9cbe-3b8f2354afa1.png)

Ngoài khả năng dùng để tạo ra các hàm hợp như đã mô tả ở trên, Currying còn rất hữu ích khi chúng ta thực hiện tái cấu trúc code. Đó là khi ta muốn tạo một hàm tổng với rất nhiều tham số, và sau đó sử dụng nó để tạo ra các hàm cụ thể phù hợp với từng ngữ cảnh sử dụng, mà yêu cầu ít tham số hơn.

Lấy ví dụ, khi chúng ta có 2 hàm sau đây dùng để thêm 1 hoặc 2 dấu ngoặc nhọn vào trước và sau 1 String:

```
bracket str =
    "{" ++ str ++ "}"
doubleBracket str =
    "{{" ++ str ++ "}}"

```

Và đây là một số ngữ cảnh chúng ta sẽ sử dụng 2 hàm đó :

```
bracketedJoe =
    bracket "Joe"
doubleBracketedJoe =
    doubleBracket "Joe"

```

Chúng ta có thể tổng quát hóa 2 hàm `bracket` và `doubleBracket` thành 1 hàm như sau :

```
generalBracket prefix str suffix =
    prefix ++ str ++ suffix

```

Nhưng như vậy thì mỗi khi sử dụng hàm `generalBracket`, chúng ta sẽ phải truyền thêm giá trị dấu đóng/mở ngoặc :

```
bracketedJoe =
    generalBracket "{" "Joe" "}"
doubleBracketedJoe =
    generalBracket "{{" "Joe" "}}"

```

Cái chúng ta **thực sự muốn** là tập hợp các lợi ích của cả 2 cách: sử dụng đơn giản (truyền mỗi String vào hàm), nhưng không được lặp code.

Nếu chúng ta sắp xếp lại thứ tự các tham số của hàm `generateBracket`, chúng ta có thể tạo ra 2 hàm `bracket` và `doubleBracket` vì hàm `generateBracket` vốn đã hỗ trợ **Currying** rồi:

```
generalBracket prefix suffix str =
    prefix ++ str ++ suffix
bracket =
    generalBracket "{" "}"
doubleBracket =
    generalBracket "{{" "}}"

```

Để ý rằng bằng việc đưa các tham số có vẻ như sẽ được set cố định trước lên đầu tiên, trong ví dụ này là `prefix` và `suffix`, và đưa các tham số sẽ được set sau cùng vào phía sau, chúng ta có thể tạo ra các phiên bản cụ thể và phù hợp với nhu cầu sử dụng từ hàm `generalBracket`.

> Thứ tự các tham số là rất quan trọng trong việc tận dụng khả năng Currying.

Đồng thời, ta cũng có thể nhận thấy là các hàm `bracket` và `doubleBracket` đều được viết dưới dạng `Point-free Notation`, cụ thể trong trường hợp này tham số `str` được loại bỏ. Cả 2 hàm `bracket` và `doubleBracket` đều là những hàm đang chờ đợi tham số cuối cùng.

Và giờ chúng ta có thể sử dụng 2 hàm đó như trước khi tái cấu trúc code :

```
bracketedJoe =
    bracket "Joe"
doubleBracketedJoe =
    doubleBracket "Joe"

```

Nhưng lần này chúng ta đã sử dụng một hàm tổng quát hỗ trợ Currying có tên `generalBracket`.

## Một số hàm functional cơ bản

![](https://viblo.asia/uploads/a46820f6-9392-4205-9ad8-47a1b3830305.png)

Giờ chúng ta sẽ đến với 3 hàm cơ bản thường được sử dụng trong Functional Programming.

Nhưng trước tiên, tôi muốn mời bạn xem đoạn code sau trong Javascript:

```
for (var i = 0; i < something.length; ++i) {
    // do stuff
}

```

Có một vấn đề khá điển hình với đoạn code trên. Mặc dù không phải là bug, nhưng đoạn code trên sẽ được chúng ta viết hoặc copy paste mỗi lần muốn sử dụng vòng lặp (boilerplate code - code khuôn mẫu), nên sẽ khiến việc viết đọc code trở nên mệt mỏi dần theo thời gian.

Nếu làm việc với các ngôn ngữ Imperative như là Java, C#, Javascript, PHP, Python,... bạn sẽ dễ dàng nhận thấy mình phải liên tục viết đi viết lại các dòng code tương tự như trên nhiều hơn bất cứ thứ gì khác.

Và đó chính là vấn đề mà tôi muốn nói đến.

Vì vậy tiếp theo đây chúng ta sẽ bàn về việc khử các đoạn code nhàm chán đó. Hãy đưa chúng và một hàm (hoặc một vài hàm) và ta sẽ _không bao giờ_ phải viết một vòng lặp _for_ một lần nào nữa. Thực tế thì điều đó khá là bất khả thi, nếu như chúng ta không biết đến FP.

Trước hết, hãy bắt đầu bằng việc thay đổi một mảng có tên là `things`:

```
var things = [1, 2, 3, 4];
for (var i = 0; i < things.length; ++i) {
    things[i] = things[i] * 10; // MUTATION ALERT !!!!
}
console.log(things); // [10, 20, 30, 40]

```

Bạn có nhận thấy điều gì ở đây ko? Đó chính là **Mutability - biến things đã bị thay đổi giá trị**

Chúng ta sẽ thử lại, lần này sẽ không thay đổi giá trị biến _things_ nữa:

```
var things = [1, 2, 3, 4];
var newThings = [];
for (var i = 0; i < things.length; ++i) {
    newThings[i] = things[i] * 10;
}
console.log(newThings); // [10, 20, 30, 40]

```

Lần này thì chúng ta không thay đổi giá trị của biến _things_, nhưng về mặt kỹ thuật thì chúng ta _vẫn thay đổi giá trị của biến newThings_, nhưng chúng ta sẽ bỏ qua và chấp nhận điều đó, vì hiện tại ta vẫn đang sử dụng Javascript. Khi chuyển sang các ngôn ngữ FP, bạn sẽ không thay đổi biến được nữa đâu.

Mục đích mà tôi muốn nói ở đây là giải thích rõ ràng hơn cách hoạt động của những hàm cơ bản trong FP (map, reduce, filter,... ), cũng như tác dụng của chúng trong việc giảm bớt những phiền phức không đáng có trong code của mình. Do đó code JS có thể không mô tả đúng hoàn toàn cách các hàm đó thực hiện, nhưng về concept thì các bạn cứ yên tâm mà theo dõi nhé.

Giờ với đoạn code ở trên (không thay đổi biến `things`), chúng ta sẽ đưa nó vào một hàm cơ bản đầu tiên có tên là `map`, với nhiện vụ là ánh xạ (map) từng giá trị của mảng cũ đến một mảng mới, thông qua một hàm biến đổi `f`:

```
var map = (f, array) => {
    var newArray = [];
    for (var i = 0; i < array.length; ++i) {
        newArray[i] = f(array[i]);
    }
    return newArray;
};

```

Ta có thể thấy hàm map ngoài tham số là một mảng cần biến đổi, sẽ nhận thêm một tham số là `f`, đại diện cho việc mà chúng ta muốn xử lý với từng phần tử trong mảng cũ trước khi đưa vào mảng mới. (VD : nhân đôi từng phần tử thì hàm `f` sẽ là `var f = x => x *2`, hoặc cộng mỗi phần tử thêm 1 thì hàm `f` sẽ là `var f = x => x+1`, ...)

Và với code ban đầu, chúng ta có thể viết lại bằng cách sử dụng hàm `map` như sau :

```
var things = [1, 2, 3, 4];
var newThings = map(v => v * 10, things);

```

Bạn có thể thấy là chúng ta đã không còn sử dụng vòng lặp `for` nữa, đồng thời code cũng trở nên dễ hiểu hơn (chúng ta có thể hiểu đoạn code trên là tạo ra một `newThings` là một mảng gồm các phần tử như mảng `things`, nhưng mỗi phần tử có giá trị _được nhân lên 10 lần_).

Về mặt kỹ thuật thì vẫn có vòng lặp `for` ở trong hàm `map`. Nhưng ít ra thì chúng ta sẽ không phải copy paste hoặc gõ lại cái đoạn code mẫu đó thêm một lần nữa.

Giờ thì chúng ta sẽ viết thêm một hàm có `filter` để lọc các phần tử của một mảng theo điều kiện bất kỳ:

```
var filter = (pred, array) => {
    var newArray = [];
for (var i = 0; i < array.length; ++i) {
        if (pred(array[i]))
            newArray[newArray.length] = array[i];
    }
    return newArray;
};

```

Lưu ý hàm dùng để xác định có lấy phần tử đó hay không được truyền thông qua biến `pred`, chỉ trả về giá trị `Boolean` thôi nhé. Hàm này sẽ trả về TRUE khi chúng ta muốn giữ lại phần tử, và FALSE nếu chúng ta muốn loại nó ra.

Và đây là cách sử dụng hàm `filter` để lấy ra các phần tử là số lẻ trong một mảng :

```
var isOdd = x => x % 2 !== 0;
var numbers = [1, 2, 3, 4, 5];
var oddNumbers = filter(isOdd, numbers);
console.log(oddNumbers); // [1, 3, 5]

```

Sử dụng hàm `filter` vừa viết ở trên sẽ đơn giản và dễ dàng hơn rất nhiều với việc phải đóng mở vòng `for`, set các biến lưu giá trị,... những công việc nhàm chán lại hay sai.

Hàm thường xuyên được sử dụng trong FP tôi muốn giới thiệu cuối cùng có tên là `reduce`. Về cơ bản, nó được dùng với giá trị đầu vào là một danh sách, và kết quả trả ra là một giá trị đơn lẻ (nên mới được gọi là reduce - rút gọn), nhưng thực tế thì có rất nhiều cách để áp dụng.

Hàm `reduce` thường được biết đến với cái tên là `fold` trong FP:

```
var reduce = (f, start, array) => {
    var acc = start;
    for (var i = 0; i < array.length; ++i)
        acc = f(array[i], acc); // f() takes 2 parameters
    return acc;
});

```

Hàm `reduce` sẽ gồm 3 tham số, bao gồm một hàm `f` dùng để thực hiện rút gọn (reduce), một giá trị khởi đầu `start` và một mảng để thao tác `array`.

Để ý rằng hàm dùng cho việc rút gọn là `f` sẽ nhận 2 tham số, một là giá trị hiện tại của mảng `array`, một là giá trị tích lũy `acc` đang được tính toán và thay đổi khi duyệt qua từng phần tử trong mảng. Giá trị `acc` ở bước cuối cùng sẽ được trả về và cũng là kết quả của hàm `reduce`.

Ví dụ dưới đây sẽ giúp chúng ta hiểu rõ hơn cách hoạt động của hàm này :

```
var add = (x, y) => x + y;
var values = [1, 2, 3, 4, 5];
var sumOfValues = reduce(add, 0, values);
console.log(sumOfValues); // 15

```

Hàm `add` sẽ nhận vào 2 tham số và trả về tổng của chúng. Hàm `reduce` của chúng ta chấp nhận các hàm cho việc rút gọn với 2 tham số, nên trong trường hợp này hàm `add` là hoàn toàn hợp lý.

Chúng ta bắt đầu với giá trị `start` là 0 và truyền vào một mảng `values`, do đó kết quả nhận lại của hàm `reduce` sẽ là tổng các phần tử trong mảng `values`. Trong hàm `reduce`, giá trị tổng các phần tử sẽ được tích lũy, cộng dồn sau mỗi lần duyệt từng phần tử của mảng.

- Bắt đầu `acc = start = 0`, giá trị đầu tiên của mảng là `1`, lần thực hiện đầu tiên của hàm `add` sẽ là `add(1,0)` và `acc` mang giá trị 1
- giá trị thứ 2 của mảng là `2`, `acc = 1`, hàm `add` lúc này sẽ được gọi với giá trị `add(2, 1)`,và `acc = 3`

Tiếp tục như vậy đến cuối cùng, giá trị `acc = 15` sau lần duyệt phần tử cuối cùng (5) của mảng value và được trả về bởi hàm `reduce`.

Có thể thấy rằng, mỗi hàm `map, filter, reduce` sẽ cho phép chúng ta thực hiện các biến đổi thông thường với một mảng mà không phải viết những đoạn code sử dụng vòng lặp dài dòng và khó hiểu nữa.

Nhưng trong FP, khi mà chúng ta chỉ có đệ quy, còn vòng lặp thì không tồn tại, thì các hàm duyệt và biến đổi mảng ở trên sẽ trở nên cực kì hữu ích và cần thiết.

## Đầu của tôi!!!!

![](https://viblo.asia/uploads/3cb3a723-1140-4d4c-abc8-9da098acc7d6.png)

Hôm nay đến đây thôi là đủ.

Trong các phần sau của bài viết này, tôi sẽ nói về các vấn đề như là _Referential Integrity, Execution Order, Types và một vài thứ nữa_

Nếu bạn muốn tham gia vào cộng đồng các nhà phát triển web muốn học và giúp đỡ lẫn nhau về FP trong Elm, mời các bạn tham gia Group Facebook sau: [Learn Elm Programming](https://www.facebook.com/groups/learnelm/)

Và đây là Twitter của tác giả : [@cscalfani](https://twitter.com/cscalfani)
]]></description>
            <link>https://hungvn.com/blog/tro-thanh-functional-programmer-phan-4</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tro-thanh-functional-programmer-phan-4</guid>
            <pubDate>Wed, 23 Aug 2017 23:26:54 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Trở thành Functional Programmer - Phần 3]]></title>
            <description><![CDATA[
Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những bước khó khăn nhất. Nhưng với cách tiếp cận đúng đắn, mọi thứ sẽ trở nên dễ hiểu hơn rất nhiều. Và đây là series được tạo ra nhằm mục đích giúp các bạn dễ thở hơn trong quá trình tiếp cận với FP.

## Concept 5: Function Composition - Hàm hợp

![](https://viblo.asia/uploads/a43d04e0-b38a-414e-994f-483c2e68770d.png)

Lười là một trong những đặc trưng của lập trình viên chúng ta. Điển hình cho cái tính lười này là sự ngán ngẩm khi phải thực hiện đi thực hiện lại công việc chỉnh sửa, test, deploy code mà mình đã từng viết trước đó.

Vì thế, chúng ta luôn luôn tìm ra những cách để chỉ làm một lần và đem ra tái sử dụng một lúc nào đó.

Tái sử dụng code (code reuse) là một thứ thật tuyệt vời nhưng rất khó để đạt được. Nếu các đoạn code quá cụ thể thì ta không thể nào tái sử dụng được. Nhưng nếu các đoạn code đó lại quá chung chung thì lại rất khó khi áp dụng vào từng trường hợp cụ thể.

Do đó chúng ta cần một sự cân bằng giữa hai tính chất trên, cần một cách để tạo ra các khối code nhỏ, có thể dễ dàng tái sử dụng - giống như các viên gạch vậy - để tạo nên các chức năng phức tạp.

Trong FP, hàm được coi như các khối vật liệu xây dựng nên chương trình. Chúng ta sẽ viết các hàm cho những công việc cụ thể, nhưng sau đó chúng ta có thể ghép chúng lại như ghép Lego vậy.

Và concept mô tả cho việc này có tên là **Function Composition - Hàm hợp**

Vậy nó hoạt động như thế nào? Để hiểu rõ hơn, hãy cùng bắt đầu với 2 hàm Javascript sau :

```
var add10 = function(value) {
    return value + 10;
};
var mult5 = function(value) {
    return value * 5;
};

```

Nhìn 2 hàm này khá là rối rắm, nên chúng ta có thể viết lại bằng cách sử dụng [Arrow function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions) như sau:

```
var add10 = value => value + 10;
var mult5 = value => value * 5;

```

Gọn hơn rồi nhỉ. Lúc này hãy thử tưởng tượng rằng chúng ta có một hàm nhận một giá trị số rồi cộng với 10, sau đó nhân kết quả nhận được với 5\. Chúng ta _có thể_ viết như sau :

```
var mult5AfterAdd10 = value => 5 * (value + 10)

```

Mặc dù đây chỉ là một ví dụ đơn giản, nhưng chúng ta sẽ có cảm giác rằng mình không hề muốn viết hàm này từ con số 0 một chút nào. Lý do đầu tiên, vì chúng ta có thể phạm phải một số sai lầm như là quên mất dấu đóng/mở ngoặc.

Lý do thứ hai, chúng ta đã có 2 hàm trước đó, `add10` dùng để cộng thêm 10 vào 1 giá trị, `mult5` dùng để nhân 5 lần giá trị nhận được, nên việc viết lại hàm `mul5AfterAdd10` thực chất chỉ là viết lại những gì đã viết.

Và vì thế, chúng ta sẽ dùng 2 hàm `add10` và `mult5` làm thành phần cho việc _xây dựng_ nên hàm mới:

```
var mult5AfterAdd10 = value => mult5(add10(value));

```

Ta đã vừa sử dụng các hàm đã có để tạo nên hàm `mult5AfterAdd10`, nhưng vẫn còn cách cải thiện đoạn code trên.

Chúng ta sẽ nhắc lại một chút về toán học. `f ∘ g` là phép hợp hàm và được diễn giải là `hàm f kết hợp với hàm g`, hoặc theo ngôn ngữ phổ thong, `hàm f sau hàm g`. Vì thế `(f ∘ g)(x)` tương đương với việc gọi hàm `f` sau khi gọi hàm `g` với tham số là `x`, hay viết gọn lại là `f(g(x))`.

Ví dụ ở trên sẽ tương đương với `mult5 ∘ add10` hoặc là `hàm mult5 theo sau hàm add10`, và vì thế tên hàm sẽ là `mult5AfterAdd10`.

Và đó chính xác là những gì mà chúng ta đã làm. Ta gọi hàm `mult5` sau khi gọi hàm `add10` với tham số là `value`, hay viết gọn là `mult5(add10(value))`.

Vì Javascript không hỗ trợ FP một cách hoàn toàn nên code có vẻ khá phức tạp, chúng ta hãy nhìn sang phiên bản của Elm:

```
add10 value =
    value + 10
mult5 value =
    value * 5
mult5AfterAdd10 value =
    (mult5 << add10) value

```

Toán tử `<<` được dùng để _kết hợp hàm_ ở trong Elm. Và việc sử dụng toán tử này sẽ cho chúng ta một hình dung khá rõ ràng về luồng xử lý dữ liệu. Đầu tiên, biến `value` được truyền cho hàm `add10`, sau đó sẽ được truyền sang hàm `mult5`.

Đồng thời hãy lưu ý dấu mở và đóng ngoặc ở hàm `mult5AfterAdd10`, cụ thể là ở đoạn `(mult5 << add10)`. Việc sử dụng đóng mở ngoặc ở đây nhằm đảm bảo rằng 2 hàm sẽ được kết hợp _trước khi_ xử lý tham số `value`.

Ta cũng có thể kết hợp nhiều hàm nếu thích :

```
f x =
   (g << h << s << r << t)  x

```

Ở đây biến `x` sẽ được truyền vào hàm `t`, kết quả được truyền sang hàm `r`, sau đó kết quả ở hàm `r`lại sang hàng `s` và tiếp tục cho đến hết hàm `g`. Phiên bản hàm hợp tương đương ở Javascript sẽ là `g(h(s(r(t(x)))))` - trông như một đống ngổn ngang toàn dấu đóng mở ngoặc.

## Concept 6 : Point-Free Notation

(Lời người dịch : Từ này mình không tìm thấy từ tiếng Việt tương ứng, theo ý hiểu của mình có nghĩa là ký hiệu hàm mà không phải chỉ định rõ tham số nên được gọi là Point - Free)

![](https://viblo.asia/uploads/0c8cf48b-7b8a-4da8-b178-101aefb74ca3.png)

Có một phong cách viết code mà không phải chỉ định rõ tham số với tên gọi là **Point-Free Notation**. Ban đầu phong cách này nhìn có thể kỳ cục nhưng theo thời gian, chúng ta sẽ cảm nhận được tác dụng của sự vắn tắt này.

Quay trở lại ví dụ về hàm `mult5AfterAdd10`, ta nhận thấy rằng biến `value` được ghi ra hai lần. Một lần trong danh sách tham số và một lần được sử dụng trong thân hàm

```
-- This is a function that expects 1 parameter
mult5AfterAdd10 value =
    (mult5 << add10) value

```

Nhưng thực tế thì tham số này là không cần thiết vì hàm `add10` - hàm ở ngoài cùng bên phải của hàm hợp, cũng dùng chính xác tham số đó. Dưới đây sẽ là phiên bản `point-free` tương đương với hàm trên:

```
-- This is also a function that expects 1 parameter
mult5AfterAdd10 =
    (mult5 << add10)

```

Khi viết theo cách này, thực tế sẽ đem lại cho ta rất nhiều lợi ích.

Đầu tiên, chúng ta không phải chỉ rõ các tham số được rút gọn, do đó chúng ta không phải mất thời gian để nghĩ tên cho tất cả các tham số đó.

Thứ hai, viết theo kiểu này sẽ dễ đọc và suy luận hơn vì nó sẽ bớt rối rắm. Ví dụ phía trên rất đơn giản, nhưng hãy tưởng tượng nếu một hàm nhận _nhiều hơn một tham số_.

## Rắc rối chốn thiên đường

![](https://viblo.asia/uploads/b7929b21-7615-4740-9aa9-40b4dafd8aef.png)

Từ đầu bài viết đến giờ, chúng ta đã tìm hiểu cách _Hàm hợp_ hoạt động và lý do cũng như cách chúng ta nên viết hàm dưới dạng _Point-Free Notation_ cho sự mạch lạc, rõ ràng và linh động.

Giờ, hãy thử áp dụng các ý tưởng trên vào một bối cảnh khác và xem chúng hoạt động ra sao nhé. Tưởng tượng chúng ta thay hàm `add10` bằng hàm `add` như sau :

```
add x y =
    x + y
mult5 value =
    value * 5

```

Câu hỏi giờ là : Làm thế nào để tạo ra hàm `mult5After10` chỉ với 2 hàm trên.

Trước khi đi tiếp, tôi khuyên bạn hãy dừng lại và nghĩ một chút. Không có gì nghiêm trọng cả, chỉ đơn giản là dừng lại và thử ngẫm nghĩ một chút thôi.

Ok, nếu bạn đã bỏ thời gian suy nghĩ, thì _có thể_ bạn đã nghĩ đến giải pháp như dưới đây:

```
-- This is wrong !!!!
mult5AfterAdd10 =
    (mult5 << add) 10

```

Nhưng thực tế nó sẽ không hoạt động. Vì sao? Vì hàm `add` cần hai - hai chứ không phải một tham số.

Nếu trong Elm nhìn có vẻ không hiển nhiên, chúng ta sẽ quay lại với phiên bản Javascript:

```
var mult5AfterAdd10 = mult5(add(10)); // cái này không hoạt động

```

Đoạn code này không đúng, nhưng lý do là vì sao?

Nguyên nhân là vì hàm `add` chỉ lấy 1 trong 2 tham số để tính toán, tạo ra kết quả sai, mà _kết quả sai_ đó sẽ được truyền sang hàm `mult5`, dẫn đến kết quả cuối cùng không đúng.

Trong thực tế, với Elm, bộ biên dịch - compiler sẽ không bao giờ bỏ qua những dòng code sai định dạng như trên (và đó là một trong những điểm tuyệt vời của Elm).

Chúng ta có thể viết lại như sau :

```
var mult5AfterAdd10 = y => mult5(add(10, y)); // not point-free

```

Đây không phải là cách viết hàm theo phong cách _point-free_, nhưng ít ra thì nó sẽ đảm bảo được kết quả đúng. Nhưng giờ thì ta không thể dùng toán tử kết hợp các hàm lại thành hàm hợp nữa (là phần `<<`). Thay vì thế ta đang tạo ra một hàm mới. Sau này nếu kịch bản trở nên phức tạp hơn, ví dụ như muốn kết hợp hàm `mult5AfterAdd10` với một cái gì đó khác, lúc này mọi thứ sẽ trở nên thực sự rắc rối.

Vì thế khi chúng ta không thể kết hợp hai hàm ở trên, có một điều ta nhận thấy rõ ràng là **Hàm hợp** có sự hạn chế nhất định. Điều đó thật tệ vì **Hàm hợp** là một concept khá mạnh mẽ.

Vậy làm thế nào để chúng ta giải quyết vấn đề trên? Chúng ta cần thứ gì để có thể thổi bay sự rắc rối này?

Giả sử chúng ta có thể làm cách nào đó để chỉ truyền cho hàm `add` một giá trị tham số _trước tiên_ (khi tạo hàm hợp) , và tham số thứ 2 sẽ được truyền vào _sau đó_ khi thực hiện hàm hợp - ở đây là lúc hàm `mult5AfterAdd10` được gọi, chẳng phải vấn đề ở trên sẽ dễ dàng được giải quyết sao.

Và thực tế là cách đó có tồn tại, với tên gọi là **Currying**.

## Đầu của tôi!!!!

![](https://viblo.asia/uploads/3cb3a723-1140-4d4c-abc8-9da098acc7d6.png)

Hôm nay đến đây thôi là đủ.

Trong các phần sau của bài viết này, tôi sẽ nói về các vấn đề như là _Currying, các functional functions cơ bản (như là map, filter, fold,... ), Referential Transparency và một vài thứ nữa_

Nếu bạn muốn tham gia vào cộng đồng các nhà phát triển web muốn học và giúp đỡ lẫn nhau về FP trong Elm, mời các bạn tham gia Group Facebook sau: [Learn Elm Programming](https://www.facebook.com/groups/learnelm/)

Và đây là Twitter của tác giả : [@cscalfani](https://twitter.com/cscalfani)
]]></description>
            <link>https://hungvn.com/blog/tro-thanh-functional-programmer-phan-3</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tro-thanh-functional-programmer-phan-3</guid>
            <pubDate>Wed, 23 Aug 2017 23:25:03 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Trở thành Functional Programmer - Phần 2]]></title>
            <description><![CDATA[
Những bước đầu tiên của việc hiểu rõ các concepts trong lập trình hàm (Functional Programming - FP) là những bước quan trọng nhất, và đôi khi là những bước khó khăn nhất. Nhưng với cách tiếp cận đúng đắn, mọi thứ sẽ trở nên dễ hiểu hơn rất nhiều. Và đây là series được tạo ra nhằm mục đích giúp các bạn dễ thở hơn trong quá trình tiếp cận với FP.

## Một chút lưu ý

![](https://viblo.asia/uploads/a0316185-f724-4980-b7d9-3bbb1fc98a0b.png)

Tôi mong các bạn sẽ đọc các dòng code một cách từ tốn. Và hãy đảm bảo rằng bạn đã hoàn toàn hiểu rõ, nắm vững các nội dung vừa đọc được trước khi tiếp tục. Các phần tiếp theo được phát triển từ các phần trước đó, nên nếu bạn vội vã, bạn có thể bỏ qua một vài kiến thức quan trọng, cần thiết cho các phần sau này.

## Tái cấu trúc - Refactoring

![](https://viblo.asia/uploads/4e819b21-0572-4135-a423-456f9469a1bc.png)

Phần này sẽ nói về Tái cấu trúc - một kỹ thuật khá quen thuộc đối với các lập trình viên. Sau đây mời các bạn xem một đoạn code Javascript:

```javascript
function validateSsn(**ssn**) {
  if (**/^\d{3}-\d{2}-\d{4}**/.exec(**ssn**))
    console.log('Valid **SSN**');
  else
    console.log('Invalid **SSN**');
}

function validatePhone(**phone**) {
  if (/**^\(\d{3}\)\d{3}-\d{4}**/.exec(**phone**))
    console.log('Valid **Phone Number**');
  else
    console.log('Invalid **Phone Number**');
}
```

Hẳn là bạn đã từng viết những dòng code kiểu như thế này, và theo thời gian, bạn sẽ dần nhận ra rằng 2 hàm phía trên khá là giống nhau, chỉ có đôi chút khác biệt (phần được bôi đậm).

Vì thế, thay vì copy lại hàm `validateSSn` và thay đổi để tạo ra hàm `validatePhone` mới, chúng ta có thể chỉ tạo một hàm và biến các phần khác nhau thành tham số.

Trong ví dụ này, chúng ta nên tham số hóa phần `value`, phần `regulare expression` và phần `message` được in ra (là những phần bôi đậm ở trên).

Đây là code sau khi refactor:

```
function validateValue(value, regex, type) {
    if (regex.exec(value))
        console.log('Invalid ' + type);
    else
        console.log('Valid ' + type);
}

```

Các tham số `ssn` và `phone` ở trong phần code cũ đã được thay thế bằng biến `value`.

2 biểu thức chính quy (regulare expression) `/^\d{3}-\d{2}-\d{4}$/` và `/^\(\d{3}\)\d{3}-\d{4}$/` được thay thế bằng biến `regex`.

Và phần sau của message gồm `SNS` và `Phone Number` sẽ được thay thế bằng biến `type`.

Việc chỉ có một hàm như thế này sẽ tốt hơn rất nhiều so với việc có 2, hoặc xấu hơn là 3, 4 hay 10 hàm. Việc này sẽ giúp code của bạn sạch sẽ và dễ bảo trì hơn.

Ví dụ, nếu có lỗi xảy ra, bạn sẽ chỉ phải fix ở một chỗ thay vì tìm kiếm trong tất cả source code để tìm các chỗ mà hàm này _CÓ THỂ_ đã được copy/paste và thay đổi.

Tiếp theo chúng ta cùng xem xét trường hợp phức tạp hơn một chút :

```
function validateAddress(address) {
    if (parseAddress(address))
        console.log('Valid Address');
    else
        console.log('Invalid Address');
}
function validateName(name) {
    if (parseFullName(name))
        console.log('Valid Name');
    else
        console.log('Invalid Name');
}

```

Ở đây `parseAddress` và `parseFullName` là 2 hàm đều nhận vào một chuỗi và trả về `true` nếu parse thành công.

Bạn sẽ refactor code trong trường hợp này như thế nào đây?

Giống như trường hợp trước đó, ta có thể sử dụng biến `value` cho `address` và `name`, `type` cho `Address` và `Name` giống như đã làm trước đó, nhưng ở vị trí của biểu thức chính quy lúc trước giờ lại là 2 hàm khác nhau.

Nếu như chúng ta có thể đưa hàm vào tham số thì ...

## Concept 3: Higher-Order Functions

(Chú thích của người dịch: High-order Function mình đã tìm hiểu nhưng khó có từ tiếng Việt tương đương, bạn có thể hiểu Higher-Order Functions có nghĩa là Hàm có cấp bậc cao hơn - với ý nghĩa là hàm có nhiều khả năng và linh hoạt hơn so với các ngôn ngữ Imperative Programming thông thường như Java, C, C++)

![](https://viblo.asia/uploads/1bdda083-b23c-40c8-844c-f26d1a080b56.png)

Rất nhiều ngôn ngữ lập trình không hỗ trợ việc đưa hàm vào thành tham số. Một số ngôn ngữ thì có thể nhưng cách thực hiện thì không hề dễ dàng chút nào.

> Trong Functional Programming, một hàm sẽ được coi như là một công dân hạng nhất trong ngôn ngữ đó. Hay nói cách khác, hàm sẽ giống như các loại giá trị (số, text, object,...) khác.

Bởi vì hàm sẽ được coi như các loại giá trị khác, nên **hàm có thể được truyền dưới dạng tham số**.

Mặc dù không phải là ngôn ngữ hỗ trợ FP chính thống, nhưng một vài concept trong FP có thể được thực hiện bởi Javascript. Và đây là cách thu gọn hai hàm ở trên thành một bằng việc đưa hàm thực hiện việc parse dữ liệu thành tham số của hàm mới có tên là `parseFunc`:

```
function validateValueWithFunc(value, parseFunc, type) {
    if (parseFunc(value))
        console.log('Invalid ' + type);
    else
        console.log('Valid ' + type);
}

```

Và hàm mới của chúng ta được gọi là `Higher-order Function`.

> Higher-order Functions là các hàm hoặc nhận hàm làm tham số, hoặc trả về hàm, hoặc vừa nhận hàm làm tham số vừa trả về hàm.

Và giờ chúng ta có thể viết lại cả 4 hàm trên bằng cách sử dụng hàm `validateValueWithFunc` như sau ( lưu ý rằng hàm `Regex.exec` sẽ trả về `true` nếu chuỗi ký tự match với biểu thức chính quy ):

```
validateValueWithFunc('123-45-6789', /^\d{3}-\d{2}-\d{4}$/.exec, 'SSN');
validateValueWithFunc('(123)456-7890', /^\(\d{3}\)\d{3}-\d{4}$/.exec, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

```

Code được viết lại như trên nhìn ngon hơn hẳn so với việc có 4 hàm từa tựa nhau nhỉ? :D

Để ý kĩ hơn một chút, 2 hàm sử dụng biểu thức chính quy nhìn có vẻ khá là rườm rà, nhất là khi sau này biểu thức chính quy có thể trở nên dài và phức tạp hơn. Chúng ta có thể làm cho nó gọn hơn bằng cách đưa phần gọi biểu thức chính quy ra ngoài như sau :

```
var parseSsn = /^\d{3}-\d{2}-\d{4}$/.exec;
var parsePhone = /^\(\d{3}\)\d{3}-\d{4}$/.exec;

validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

```

Mọi thứ tốt hơn rồi nhỉ. Sau này nếu muốn kiểm tra một số điện thoại khác, thay vì phải copy lại biểu thức chính quy, ta có thể sử dụng hàm `parsePhone` và `validateValueWithFunc`.

Tuy nhiên, hãy thử tưởng tượng nếu chúng ta có nhiều biểu thức chính quy cần thực hiện, ngoài 2 hàm `parseSsn` và `parsePhone` thì sẽ ra sao nhỉ? Để ý rằng mỗi khi gọi hàm xử lý biểu thức chính quy, ta đều phải gọi thêm `.exec` vào cuối, và nếu số lượng biểu thức chính quy tăng lên thì sẽ khá là phiền phức, và tin tôi đi, sẽ có lúc bạn sẽ quên mất không thêm `.exec` vào đó.

Để tránh mắc phải lỗi này, chúng ta có thể tạo ra một hàm dạng `high-order function` được dùng để **trả về hàm exec từ biểu thức chính quy truyền vào** như sau :

```
function makeRegexParser(regex) {
    return regex.exec;
}
var parseSsn = makeRegexParser(/^\d{3}-\d{2}-\d{4}$/);
var parsePhone = makeRegexParser(/^\(\d{3}\)\d{3}-\d{4}$/);
validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
validateValueWithFunc('123 Main St.', parseAddress, 'Address');
validateValueWithFunc('Joe Mama', parseName, 'Name');

```

Ở đây, hàm `makeRegexParser` nhận tham số là một biểu thức chính quy, và trả về **hàm exec của biểu thức chính quy đó**, với tham số là một chuỗi string. Lúc này, hàm `validateValueWithFunc` sẽ nhận chuỗi string từ biến `value`, sau đó truyền sang hàm `parseSsn` hoặc `parsePhone`, đối ví dụ trên thực chất sẽ là hàm _exec được trả về từ hàm parseSsn hoặc parsePhone_.

Như các bạn đã thấy, đây tuy chỉ là một quá trình tái cấu trúc code nho nhỏ, nhưng nó đã thể hiện khả năng và sự tiện lợi của `High-order function` khi hỗ trợ việc trả về **hàm**.

Lợi ích của việc thay đổi này sẽ thể hiện một cách rõ ràng hơn khi hàm `makeRegexParser` trở nên phức tạp hơn.

Dưới đây là một ví dụ khác về một `High-order function` có kết quả trả về là một hàm :

```
function makeAdder(constantValue) {
    return function adder(value) {
        return constantValue + value;
    };
}

```

Chúng ta có một hàm `makeAdder` nhận vào tham số là `constantValue` (giá trị cố định), và trả về một hàm tên là `adder`, với khả năng cộng thêm giá trị `constantValue` vào tham số truyền vào.

Đây là cách hàm `adder` có thể sử dụng :

```
var add10 = makeAdder(10);
console.log(add10(20)); // prints 30
console.log(add10(30)); // prints 40
console.log(add10(40)); // prints 50

```

Chúng ta đã tạo ra một hàm có tên là `add10` bằng việc truyền giá trị `10` vào hàm `makeAdder`, mà hàm `add10` sẽ hoạt động đúng như tên của nó, cộng thêm 10 vào bất kỳ biến nào truyueenf vào.

Để ý rằng hàm `adder` có thể truy cập đến biến `constantValue` ngay cả khi hàm `makeAddr` đã hoàn thành. Lý do là bởi vì biến `constantValue` đã ở trong cùng một `scope` (phạm vi) khi hàm `adder` được tạo.

Khả năng này rất quan trọng bởi vì nếu thiếu nó, việc hàm trả về hàm sẽ không còn nhiều lợi ích nữa. Vì thế việc hiểu cách hoạt động và tên gọi của khả năng này cũng là điều mà chúng ta cần tìm hiểu, và nó có tên là **Closure**.

## Concept 4: Closures - Bao đóng

![](https://viblo.asia/uploads/3a139baa-3e92-4adf-86cc-1d8e0a33db27.png)

Dưới đây là một ví dụ giả tưởng nhằm minh họa việc hàm sử dụng **closures**:

```
function grandParent(g1, g2) {
    var g3 = 3;
    return function parent(p1, p2) {
        var p3 = 33;
        return function child(c1, c2) {
            var c3 = 333;
            return g1 + g2 + g3 + p1 + p2 + p3 + c1 + c2 + c3;
        };
    };
}

```

Trong ví dụ này, hàm `child` có thể truy cập các biến của chính nó, các biến của hàm `parent` và cả các biến của hàm `grandParent` nữa.
(đủ g1, g2, g3, p1, p2, p3, c1, c2, c3)

Hàm `parent` có thể truy cập các biến của chính nó và của hàm `grandParent`. (bao gồm g1, g2, g3, p1, p2, p3)

Hàm `grandParent` chỉ có thể truy cập các biến của chính nó. (bao gồm g1, g2, g3).

(Mọi người có thể tham khảo hình vẽ kim tự tháp phía bên trên để hiểu rõ hơn).

Sau đây là 1 ví dụ sử dụng hàm 3 đời ở trên :

```
var parentFunc = grandParent(1, 2); // returns parent() - trả về hàm parent() với g1 = 1, g2 = 2, g3 = 3
var childFunc = parentFunc(11, 22); // returns child() - trả về hàm child() với g1 = 1, g2 = 2, g3 = 3, p1 = 11, p2 = 22, p3 = 33
console.log(childFunc(111, 222)); // prints 738 - in ra 738 vì :
// 1 + 2 + 3 + 11 + 22 + 33 + 111 + 222 + 333 == 738

```

Ở đây, biến `parentFunc` sẽ giữ cho scope của hàm `parent` tồn tại sau khi thực hiện hàm `grandParent`, lúc này hàm `parent` sẽ trả về và tham chiếu thông qua biến `parentFunc` (scope của `parent` ở đây sẽ bao gồm các giá trị được hàm parent tham chiếu đến, tức là sẽ lưu giữ các giá trị g1, g2, g3, p1, p2, p3).

Tương tự như vậy, biến `childFunc` sẽ giữ scope của hàm `child` tồn tại sau khi thực hiện gọi hàm `parent` thông qua biến `parentFunc`, lúc này hàm `child` được trả về và tồn tại vì có biến `childFunc` tham chiếu đến.

Mỗi khi một hàm được tạo ra, tất cả các giá trị nằm trong scope của nó _ở thời điểm hàm được tạo_ sẽ được lưu trữ và có thể truy cập trong suốt vòng đời của hàm đó. Và hàm sẽ còn tồn tại chừng nào còn có tham chiếu (reference) đến nó. Ví dụ, scope của hàm `child` sẽ còn tồn tại cho đến khi nào biến `childFunc` vẫn tham chiếu đến nó.

> Một closure (bao đóng) là một scope của một hàm mà sẽ tồn tại chừng nào còn có tham chiếu đến hàm đó.

Lưu ý rằng, trong Javascript, closures sẽ gây ra nhiều rắc rối bởi vì các biến có thể thay đổi (mutable), và vì thế các biến đó có thể bị/được thay đổi giá trị từ lúc chúng được _đóng lại_ cho đến lúc hàm trả về được gọi.

(Ở đây _đóng lại_ ý nói lúc dùng _High-order function_ để trả về một hàm, lúc này các biến trong scope của hàm đó vẫn có thể truy cập và thay đổi giá trị, do đó đến lúc thực thi hàm này, các biến này giá trị có thể khác so với lúc được trả về, gây ra các kết quả không mong muốn)

Thật may mắn là các biến trong FP sẽ là bất biến (immutable - đã nói đến ở phần 1), nên các lỗi có thể xảy ra do _Closure_ như trong JS sẽ không gặp phải nữa.

## Đầu của tôi!!!!

![](https://viblo.asia/uploads/3cb3a723-1140-4d4c-abc8-9da098acc7d6.png)

Hôm nay đến đây thôi là đủ.

Trong các phần sau của bài viết này, tôi sẽ nói về các vấn đề như là _Functional Composition, Currying, các functional functions cơ bản (như là map, filter, fold,... ), và một vài thứ nữa_

Nếu bạn muốn tham gia vào cộng đồng các nhà phát triển web muốn học và giúp đỡ lẫn nhau về FP trong Elm, mời các bạn tham gia Group Facebook sau: [Learn Elm Programming](https://www.facebook.com/groups/learnelm/)

Và đây là Twitter của tác giả : [@cscalfani](https://twitter.com/cscalfani)
]]></description>
            <link>https://hungvn.com/blog/tro-thanh-functional-programmer-phan-2</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tro-thanh-functional-programmer-phan-2</guid>
            <pubDate>Wed, 23 Aug 2017 23:22:32 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Trở thành Functional Programmer - Phần 1]]></title>
            <description><![CDATA[
Việc sáng tỏ, ngộ ra concept của `Functional Programming` thường là một trong những bước phát triển quan trọng nhất trong sự nghiệp lập trình của bạn, và đôi khi cũng là bước khó khăn nhất. Tuy nhiên chúng ta có thể vượt qua nó một cách dễ dàng với cách tiếp cận đúng đắn. Bài viết sau đây sẽ hướng dẫn mọi người đến được với vùng chân lý đó.

## Bắt đầu từ việc học lái xe

![](https://viblo.asia/uploads/31209131-a7ee-4033-bd39-bbaf95277b01.png)

Lần đầu lái xe thường là những kỉ niệm đau thương và khốn khổ nhất của chúng ta. Sẽ thật dễ dàng khi nhìn người khác lái, nhưng khi thực sự đặt tay vào vô-lăng, mọi thứ bỗng trở nên khó khăn hơn chúng ta tưởng. Và chúng ta sẽ phải tập luyện bằng xe của gia đình cho đến khi có thể làm chủ những đoạn đường xung quanh nhà trước khi thoát xác lên cung đường cao tốc. Nhưng cuối cùng thì thông qua quá trình luyện tập lặp đi lặp lại và một số khoảng thời gian khiến gia đình thót tim, cuối cùng bạn cũng sẽ học được cách lái xe và có bằng lái cho riêng mình.

Với tấm bằng lái trong tay, chúng ta có thể lái bất cứ cái xe nào nếu có thể nổ máy. Và với mỗi chuyến đi, sự tự tin, làm chủ tay lái sẽ ngày càng được củng cố. Và cũng sẽ đến cái ngày chúng ta phải lái xe cuả người khác, hay là phải thay chiếc xe cà tàng bằng một chiếc mới hiện đại hơn.

Cảm xúc khi lái một **chiếc xe khác** sẽ như thế nào nhỉ? Liệu có giống với cảm xúc khi **lần đầu chạm tay vào vô lăng**? Không hẳn. Lần đầu tiên lái xe, chúng ta hoàn toàn bỡ ngỡ. Mặc dù trước đó đã ngồi trên xe nhưng chúng ta chỉ có vai trò là hành khách. Còn lầu đầu tiên lái xe là khi có qtoàn quyền điều khiển chiếc xe đó. Còn với lần lái chiếc xe thứ hai trở đi, chúng ta chỉ tìm kiếm câu trả lời cho những câu hỏi đơn giản : _Chìa khóa ở đâu nhỉ? Đèn ở đâu nhỉ? Chỉnh gương với đèn chiếu ở đâu ta?_ Sau những thắc mắc đó, mọi thứ diễn ra thật tự nhiên như nước chảy mây trôi, việc lái xe thật dễ dàng hơn không biết bao nhiêu lần so với lần đầu cầm lái.

Nguyên do cho sự việc trên là chiếc xe mới sẽ vận hành giống _gần hết_ chiếc xe cũ. Cả 2 chiếc xe đều có những thứ cơ bản cho việc lái xe, và các thứ đó hầu hết đều ở cùng một vị trí

Một vài thứ nho nhỏ sẽ được thay đổi, hoặc thêm chí có thêm vài tính năng mới, nhưng chúng ta hầu hết sẽ không dùng chúng vào lần đầu tiên, thậm chí lần thứ 2\. Dần dần sau cùng chúng ta mới học sử dụng các tính năng mới, mà chỉ là các tính năng mà chúng ta quan tâm thôi.

Việc học lập trình cũng tương tự như học lái xe vậy. Lần đầu tiên bao giờ cũng là lần khó khăn nhất. Nhưng khi bạn đã quen rồi, thì những lần sau sẽ trở nên dễ dàng hơn rất nhiều.

Mỗi khi bạn bắt đầu việc học một ngôn ngữ mới, sẽ có một số câu hỏi bạn sẽ thường tự hỏi mình như là : _Làm thế nào để tạo một module? Làm thế nào để tìm kiếm trong 1 mảng? Tham số cho hàm thay thế chuỗi là gì? _

Bạn hoàn toàn tự tin rằng mình sẽ sử đụng được ngôn ngữ mới này, bởi vì nó gợi nhớ lại cho bạn những kỉ niệm, hiểu biết với ngôn ngữ cũ, cùng với một vài điều mới mẻ với hy vọng rằng làm cho cuộc đời của bạn trở nên đẹp đẽ hơn.

## Đến con tàu vũ trụ đầu tiên

![](https://viblo.asia/uploads/9615ce9c-8664-4c1e-9d96-6caa8505233f.png)

Giờ hãy thử tưởng tượng rằng bạn đã lái hàng tá xe ô tô trong cuộc đời, rồi đến một ngày bạn được đặt vào khoang điều khiển của một chiếc **Tàu không gian**. Lúc này bạn bỗng trở nên hoang mang, không biết rằng liệu những kinh nghiệm lái xe có giúp ích được gì cho mình không. Bạn cảm giác như mình đang bắt đầu lại từ con số 0 tròn trĩnh. (_Chúng ta là lập trình viên, chúng ta đếm từ số 0_)

Bạn có thể bắt đầu việc luyện tập với cảm giác rằng mọi thứ sẽ trở nên rất khác ở trong không gian, và cách vận hành con tàu khác hoàn toàn này sẽ rất khác so với việc lái xe trên mặt đất.

Tuy nhiên thì các định luật vật lý đều không thay đổi. Chỉ khác ở chỗ cách bạn di chuyển trong cùng một vũ trụ mà thôi.

Và với việc học _Functional Programming_ (lập trình hàm) cũng tương tự như vậy. Bạn dự đoán, cảm giác rằng mọi thứ sẽ rất khác. Khác đến nỗi mà khiến cho những kinh nghiệm, kiến thức đã từng có được sẽ bị xóa sổ, không quay lại được như xưa nữa. Và mọi thứ sẽ được mở đầu bằng câu nói kinh điển dưới đây.

## Quên tất cả những thứ đã biết

![](https://viblo.asia/uploads/d98cb0e0-584a-4e8c-a1ef-81d967045010.png)
Mọi người rất thích câu nói sau đây, và nó cũng khá đúng trong hầu hết các trường hợp: **Học lập trình hàm (FP) cũng giống như bắt đầu lại mọi thứ vậy**. Không hoàn toàn là như vậy, nhưng đó là một suy nghĩ khá hiệu quả khi tiếp xúc với FP. Có rất nhiều concepts giống nhau giữa lập trình mà bạn đã biết và FP, nhưng việc tiếp cận FP với tư tưởng rằng mình sẽ phải **học lại tất cả mọi thứ** thường tỏ ra hiệu quả nhất.

Với cách tiếp cận chính xác, bạn sẽ có những tư tưởng, suy nghĩ đúng đắn, là những thứ sẽ giúp bạn không bỏ cuộc khi việc học hành trở nên khó khăn.

Bạn sẽ phải xác định rằng có rất nhiều thứ mà bạn đã từng học và làm quen trên con đường làm lâp trình viên từ trước đến giờ, khi đến với FP, sẽ biến mất hoặc không thể sử dụng được nữa.

Liên hệ với việc lái xe, bạn có thể quen với việc dùng số lùi để đậu xe. Tuy nhiên một con tùa không gian sẽ _không có số lùi_. Có thể bạn sẽ nghĩ rằng : _CÁI GÌ CƠ? KHÔNG CÓ SỐ LÙi!?! TÔI LÁI TÀU THẾ QUÁI NÀO KHI KHÔNG CÓ SỐ LÙI BÂY GIỜ?!_

Thực tế là tàu không gian có thể di chuyển trong không gian 3 chiều (ô tô là 2 chiều), nên sẽ không cần số lùi. Khi bạn nắm rõ cách hoạt động của tàu không gian, bạn sẽ không cần phải sử dụng số lùi thêm một lần nào nữa. Và rồi bạn sẽ thấy rằng mấy cái xe thật là cùi =)) Với FP cũng vậy, tuy nhiên:

> Học FP sẽ mất thời gian. Vì thế hãy kiên nhẫn

Và giờ chúng ta cùng đến với miền đất hứa của **Functional Programming**, bỏ qua vùng đất lạnh lẽo, nhàm chán của _Imperative Programming_ đã quá quen thuộc.

Những gì dược viêt tiếp theo đây là một series bài viết giới thiệu các Concepts của FP với mục đích giúp người đọc làm quen trước khi đi vào bất kì ngôn ngữ lập trình FP nào. Hoặc nếu bạn đã sử dụng FP rồi, thì đây sẽ là bài viết giúp bạn hiểu rõ hơn những việc mình đang làm .

Và mong các bạn không vội vàng. Hãy dành thời gian đọc những gì tôi sắp viết sau đây, cũng như dành thời gian để hiểu những đoạn code ví dụ. Bạn có thể tạm dừng sau mỗi đoạn để kiến thức ngấm hoàn toàn vào người, sau đó hãy quay lại và tiếp tục.

Điều quan trọng nhất là **kiến thức của bạn**.

## Concept 1: Purity - Sự thuần khiết

![](https://viblo.asia/uploads/7e82f09d-32b1-41fb-9a78-6715833a744f.png)

Khi những lập trình viên FP nói về Purity, đó là khi họ muốn đề cập đến _Pure Function_ .

_Pure Function_ là những hàm hết sức đơn giản, chỉ thao tác dựa trên tham số đầu vào.

Đây là một ví dụ về một hàm được gọi là _Pure_ trong Javascript :

```
var z = 10;
function add(x, y) {
    return x + y;
}

```

Bạn có thể nhận thấy rằng hàm `add` không hề đụng vào biến `z`. Hàm đó không đọc giá trị của biến `z`, cũng như không thay đổi giá trị biến `z`. Nó chỉ đơn giản là đọc 2 tham số `x` và `y`, là 2 tham số đầu vào, rồi trả về giá trị là tổng của 2 tham số đó.

Hàm `add`, vì lý do đó, được gọi là `Pure Function`. Nếu hàm `add` có bất kỳ xử lý nào liên quan đến biến `z`, hàm đó sẽ không còn là `pure` nữa.

Chúng ta cùng tham khảo một hàm khác:

```
function justTen() {
    return 10;
}

```

Nếu hàm `justTen` là pure, thì nó chỉ có thể trả về một giá trị duy nhất, cố định.

Nguyên nhân là vì hàm này không có bất kì một tham số nào. Và để đảm bảo nó là `pure function`, hàm này sẽ không thể truy cập bất kì giá trị nào ngoài các tham số của nó. Ở đây không có tham số nào, nên giá trị trả về của hàm này lúc nào cũng là một giá trị cố định.

Và `pure function` mà không có tham số nào để thực hiện thì có vẻ hơi vô nghĩa, và chúng ta nên thay thế hàm `justTen` bằng một hằng số (constant) thì tốt hơn.

> Hầu hết các Pure Function đều có ít nhất một tham số.

Tiếp theo chúng ta đến với một hàm khác:

```
function addNoReturn(x, y) {
    var z = x + y
}

```

Dễ dàng nhận thấy rằng hàm `addNoReturn` không có giá trị trả về. Hàm này chỉ đơn giản là xử lý việc cộng 2 tham số `x` và `y` rồi lưu vào biến `z`, nhưng không trả về giá trị tông.
Đây mặc dù vẫn là một `pure function` khi nó chỉ xử lý các tham số của chính mình. Nó thực hiện việc cộng 2 input, nhưng vì không trả về bất cứ giá trị gì, nên nó vô dụng (vì chúng ta không có cách nào lấy được giá trị đã được xử lý).

> Một Pure Function chỉ có giá trị sử dụng khi có giá trị trả về.

Và giờ chúng ta quay lại hàm `add` lúc đầu một lần nữa :

```
function add(x, y) {
    return x + y;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // still prints 3
console.log(add(1, 2)); // WILL ALWAYS print 3

```

Có thể thấy rằng việc thực hiện `add(1,2)` luôn trả về giá trị `3`. Không phải là một điều gì quá ngạc nhiên, nhưng điều này chỉ có thể thực hiện nếu hàm đó là `pure function`. Nếu hàm `add` sử dụng bất kì một biến nào ở bên ngoài, thì bạn sẽ _không bao giờ dự đoán được kết quả trả về_

> Pure Function sẽ luôn trả về cùng output với cùng input, bất kể có thực hiện bao nhiêu lần.

Vì `pure function` sẽ không tác động đến các biến nằm ngoài chúng, nên các hàm sau sẽ được coi là _impure_ (không thuần khiết =)) ):

```
writeFile(fileName);
updateDatabaseTable(sqlCmd);
sendAjaxRequest(ajaxRequest);
openSocket(ipAddress);

```

Tất cả các hàm này đều có một đặc tính chung được gọi là _Side Effects_ (tác dụng phụ). Khi bạn gọi và thực thi chúng, các hàm này sẽ thay đổi file, cập nhật cơ sử dữ liệu, gửi data về phía server hoặc gọi hệ điều hành để lấy socket. Chúng làm nhiều thứ hơn là chỉ thao tác với tham số đầu vào và trả về output. Vì thế, bạn có thể _không bao giờ_ dự đoán được giá trị mà những hàm này sẽ trả về.

> Pure Function đảm bảo việc hàm sẽ không có Side Effects.

Trong các ngôn ngữ _Imperative Language_ như là Javascript, Java, hay C#, Side Effects xuất hiện **ở khắp mọi nơi**. Điều này khiến cho việc debug rất khó vì biến có thể được thay đổi ở **bất kỳ đâu** trong chương trình. Vì thế khi có một lỗi xảy ra do một biến thay đổi thành giá trị không muốn muốn, bạn sẽ phải tìm ở đâu? Khắp mọi ngóc ngách? Điều đó thật không tốt chút nào.

Đến đây, có thể bạn sẽ thắc mắc rằng: _VẬY LÀM THẾ QUÁI NÀO MÀ TÔI CÓ THỂ LÀM VIỆC CHỈ VỚI PURE FUNCTION CHỨ?!_

Trong FP, Pure Function không phải là thứ duy nhất mà bạn sẽ vieests.

FP không thể loại trừ hoàn toàn Side Effects, mà chỉ có thể cô lập chúng. Vì các phần mềm phải giao tiếp, thao tác với thế giới thực, nên một số thành phần bắt buộc phải _impure_. Mục tiêu của FP là tối thiểu hóa hết mức có thể số lượng _impure code_ và tách biệt chúng hoàn toàn khỏi các phần khác của chương trình.

## Concept 2 - Immutability : Sự bất biến

![](https://viblo.asia/uploads/97ab72fe-c5c3-4eea-9a5f-43199c09da63.jpeg)

Bạn còn nhớ lần đầu nhìn thấy dòng code kiểu như này chứ :

```
var x = 1;
x = x + 1;

```

Khi đó, hẳn là người nào đó dạy bạn lâp trình đã nói rằng : _Hãy quên những gì đã học ở môn Toán đi? Vì trong toán học, x không bao giờ bằng x+1 được cả_

Nhưng trong các ngỗn ngữ _Imperative Programming_, các câu lệnh trên có nghĩa là, lấy giá trị hiện tại của biến `x`, cộng nó thêm 1 và gán kết quả trả về vào lại biến `x`.

Tuy nhiên sang đến FP, `x = x + 1` lại trở thành _không đúng, không được phép_. Và bạn sẽ phải nhớ lại những gì mà bạn đã bị bắt phải quên trước đó về toán học. Hmm...

> Trong Functional Programming không có khái niệm về biến (variable)

Để lưu trữ các giá trị, khái niệm _biến (variable)_ vẫn được sử dụng, nhưng các biến này _đều là hằng số (constant)_, tức là nếu biến `x` đã lưu một giá trị nào đó (là 1 chẳng hạn), thì giá trị của biến `x` sẽ không thay đổi, vẫn giữ nguyên là 1 như ban đầu được set (và chúng ta gọi là _biến hằng số - constant variable_)

Nếu bạn đang lo lắng về bộ nhớ, thì bạn có thể an tâm khi trong FP, `x` thường chỉ là biến cục nên thời gian tồn tại thường rất ngắn. Tuy nhiên trong suốt thời gian tồn tại, giá chị của `x` là bất biến.

Đây là một ví dụ về _biến hằng số_ trong Elm, một ngôn ngữ thuần FP cho lập trình Web:

```
addOneToSum y z =
    let
        x = 1
    in
        x + y + z

```

Nếu bạn không quen với syntax dạng `ML-Style` , hãy để tôi giải thích. Hàm `addOneToSum` nhận 2 tham số là `y` và `z`.

Trong block của `let`, biến `x` được gán với giá trị 1, tức là `x` sẽ giữ giá trị đó trong suốt phần đời của nó. Vòng đời của `x` sẽ kết thúc khi hàm kết thúc chạy, cụ thể hơn là sau khi block `let` được thực hiện.

Bên trong block `in`, các dòng lệnh có thể chứa và tham chiếu đến các giá trị được định nghĩa trông phần block `let`, ở đây là `x`. Kết quả của việc tính toán `x + y + z` được xử lý và trả về, cụ thể hơn ở đây là `1 + y + z` sẽ được tính toán trả về, vì `x = 1`.

Và bạn có thể thấy bối rối mà thắc mắc rằng : _TÔI LÀM TRÌNH KIỂU MÉO GÌ KHI MÀ KHÔNG CÓ BIẾN SỐ ĐÂY?!_

Hãy bình tĩnh và nghĩ đến thời điểm mà bạn muốn thay đổi giá trị của biến số. Sẽ có 2 trường hợp cơ bản nhảy ra trong đầu bạn : Thay đổi biến số chứa nhiều giá trị (vd như thay đổi một/nhiều thuộc tính của một đối tượng hoặc bản ghi) và thay đổi biến số chứa một giá trị (vd như bộ đếm trong vòng lặp).

FP xử lý việc thay đổi các giá trị trong một bản ghi bằng cách tạo ra một bản sao của bản ghi với dữ liệu được cập nhật. FP xử lý trường hợp thay đổi giá trị này bằng cách: không copy lại tất cả các thành phần của bản ghi, mà sử dụng các cấu trúc dữ liệu để thực hiện việc này một cách hiệu quả nhất.

Về việc xử lý trường hợp thay đổi biến số chứa một giá trị, FP cũng làm tương tự như trên, cũng bằng cách tạo ra một bản sao của biến số đó.

Và sẽ **KHÔNG** có vòng lặp trong FP đâu.

_ĐẦU TIÊN THÌ KHÔNG CÓ BIẾN, VÀ GIỜ THÌ KHÔNG CÓ VÒNG LẶP?! GHÉT RỒI ĐẤY_

Bình tình nào. Không phải là chúng ta không thể tạo ra các vòng lặp trong FP (tôi không chơi chữ đâu nhé), mà chỉ đơn giản là chúng ta sẽ không có các cấu trúc lặp như là **for, while, do, repeat, ...** thôi.

> Functional Programming sử dụng đệ quy cho việc lặp.

Dưới đây là 2 cách thực hiện vòng lặp trong Javascript:

```
// simple loop construct
var acc = 0;
for (var i = 1; i <= 10; ++i)
    acc += i;
console.log(acc); // prints 55
// without loop construct or variables (recursion)
function sumRange(start, end, acc) {
    if (start > end)
        return acc;
    return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // prints 55

```

Bạn có thể thấy rằng, bằng việc sử dụng đệ quy, chúng ta có thể thực hiện được đúng như những gì mà vòng lặp `for` phía trên đã thực hiện. Với việc sử dụng hàm `sumRange` gọi lại chính nó sau mỗi lần chạy với tham số `start` mới (`start + 1`) và tham số `acc` mới (`acc + start`). Hàm này không hề thay đổi các giá trị mới. Thay vào đó nó sử dụng các giá trị mới được tính toán từ các giá trị cũ.

Thật không may, việc này khá là khó để có thể nhìn thấy rõ ràng trong Javascript, kể cả bạn đã bỏ ra chút thời gian để nghiên cứu về nó, bởi 2 lý do sau đây. Thứ nhất là do syntax trong Javascript khá là khó nhìn và thứ hai, là bạn có thể không quen với tư duy suy nghĩ theo đệ quy.

Nếu sử dụng Elm, việc đọc sẽ trở nên dễ dàng hơn, và do đó, dễ hiểu hơn đối với bạn:

```
sumRange start end acc =
    if start > end then
        acc
    else
        sumRange (start + 1) end (acc + start)

```

Đây là kết quả đoạn code trên thực hiện:

```
sumRange 1 10 0 =      -- sumRange (1 + 1)  10 (0 + 1)
sumRange 2 10 1 =      -- sumRange (2 + 1)  10 (1 + 2)
sumRange 3 10 3 =      -- sumRange (3 + 1)  10 (3 + 3)
sumRange 4 10 6 =      -- sumRange (4 + 1)  10 (6 + 4)
sumRange 5 10 10 =     -- sumRange (5 + 1)  10 (10 + 5)
sumRange 6 10 15 =     -- sumRange (6 + 1)  10 (15 + 6)
sumRange 7 10 21 =     -- sumRange (7 + 1)  10 (21 + 7)
sumRange 8 10 28 =     -- sumRange (8 + 1)  10 (28 + 8)
sumRange 9 10 36 =     -- sumRange (9 + 1)  10 (36 + 9)
sumRange 10 10 45 =    -- sumRange (10 + 1) 10 (45 + 10)
sumRange 11 10 55 =    -- 11 > 10 => 55
55

```

Bạn có thể cho rằng vòng lặp `for` sẽ dễ hiểu hơn. Trong khi vấn đề này vẫn đang được tranh cãi khá là nhiều, mà có thể nguyên nhân chủ yếu là do _sự quen thuộc_, thì có một sự thật là các vòng lặp `for` cần đến khả năng biến đổi của hàm số, mà điều này được cho là không tốt trong FP.

Tôi sẽ không giải thích chi tiết những lợi ít của tính bất biến trong bài viết này, nhưng bạn có thể xem phần _Global Mutate State_ trong bài viết [Vì sao Lập trình viên cần có giới hạn](https://medium.com/@cscalfani/why-programmers-need-limits-3d96e1a0a6db) để biết thêm chi tiết.

Một lợi ích rõ ràng của tính bất biến, đó là nếu bạn phải truy cập đến một giá trị bất kỳ trong chương trình của bạn, bạn chỉ có thể có quyền đọc nó, và điều đó tương đương với việc không ai có thể thay đổi giá trị của nó. Kể cả chính bạn. Và do đó sẽ tránh được những thay đổi không mong muốn.

Và nếu chương trình của bạn hỗ trợ đa luồng (multi-threaded), thì sẽ không có bất kỳ một thread nào có thể khiến bạn đau đầu. Giá trị được set sẽ là hằng số, và nếu bất kì một thread nào muốn thay đổi nó, thread đó sẽ phải tạo một giá trị mới từ cái cũ.

Quay trở lại những năm 90, tôi đã từng viết một Game Engine cho trò chơi [Creature Crunch](https://www.youtube.com/watch?v=uIOYSjBRORM) , và nguyên nhân gây ra nhiều bug nhất chính là các vấn đề liên quan đến xử lý đa luồng. Tôi ước gì mình đã biết về Tính bất biến lúc đó. Mà thực ra điều tôi quan tâm nhất khi ấy là sự khác nhau giữa tốc độ đọc 2x và 4x của ổ đĩa CD-ROM sẽ ảnh hưởng thế nào đến hiệu năng chạy game.

> Tính bất biến tạo ra các dòng code đơn giản hơn và an toàn hơn

## Đầu của tôi!!!!

Tạm thời đến đây thôi là đủ.

Trong các phần sau của bài viết này, tôi sẽ nói về các vấn đề như là _High-order Function, Functional Composition, Curring_, v..v...

Nếu bạn muốn tham gia vào cộng đồng các nhà phát triển web muốn học và giúp đỡ lẫn nhau về FP trong Elm, mời các bạn tham gia Group Facebook sau: [Learn Elm Programming](https://www.facebook.com/groups/learnelm/)

Và đây là Twitter của tác giả : [@cscalfani](https://twitter.com/cscalfani)
]]></description>
            <link>https://hungvn.com/blog/tro-thanh-functional-programmer-phan-1</link>
            <guid isPermaLink="true">https://hungvn.com/blog/tro-thanh-functional-programmer-phan-1</guid>
            <pubDate>Wed, 23 Aug 2017 23:19:26 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giải thích về Value và Reference trong Javascript]]></title>
            <description><![CDATA[
Dùng một cái nhìn đơn giản của bộ nhớ máy tính giải thích điều này

Javascript có 5 kiểu dữ liệu được thông qua **_value_**: `Boolean`, `null`, `undefined`, `String`, và `Number`. Chúng ta sẽ gọi chung là **primitive types**.

Javascript có 5 kiểu dữ liệu được thông qua **_reference_**: `Array`, `Function`, và `Object`. Về mặt kỹ thuật đó là Objects, vì vậy chúng ta sẽ đề cập đến chúng chung chung như **Objects**.

### Primitives (Nguyên thủy)

Nếu một kiểu nguyên thủy được gán cho một biến, chúng ta có thể nghĩ rằng biến đó _chứa đựng_ giá trị nguyên thủy.

```javascript
var x = 10;
var y = "abc";
var z = null;
```

`x` _chứa đựng_ `10`. `y` _chứa đựng_ `'abc'`. Để củng cố ý tưởng này, chúng tôi sẽ cung cấp một hình ảnh về những gì các biến này và các giá trị tương ứng giống như trong bộ nhớ.

![](https://cdn-images-1.medium.com/max/1600/1*PdKLlT7zUrmDBZUOBsZh7w.png)

Khi chúng ta gán các biến này cho các biến khác sử dụng dấu `=`, Chúng ta **copy** giá trị cho biến mới. Chúng được sao chép theo giá trị.

```javascript
var x = 10;
var y = "abc";
var a = x;
var b = y;
console.log(x, y, a, b); // -> 10, 'abc', 10, 'abc'
```

Cả `a` và `x` bây giờ chứa `10`. Cả `b` và `y` bây giờ chứa `'abc'`. Chúng là tách biệt, vì các giá trị được sao chép.

![](https://cdn-images-1.medium.com/max/1600/1*MZ3AcwELYZ2ONYFg3LiTXQ.png)

Khi thay đổi một biến nó không thay đổi cái khác. Hãy suy nghĩ là các biến như không có mối quan hệ với nhau.

```javascript
var x = 10;
var y = "abc";
var a = x;
var b = y;

a = 5;
b = "def";
console.log(x, y, a, b); // -> 10, 'abc', 5, 'def'
```

### Objects

This will feel confusing, but bear with me and read through it. Once you get through it, it’ll seem easy.

Variables that are assigned a non-primitive value are given a _reference_ to that value. That reference points to the object’s location in memory. The variables don’t actually contain the value.

Objects are created at some location in your computer’s memory. When we write `arr = []`, we’ve created an array in memory. What the variable `arr` receives is the address, the location, of that array.

Let’s pretend that `address` is a new data type that is passed by value, just like `number` or `string`. An `address` points to the location, in memory, of a value that is passed by reference. Just like a string is denoted by quotation marks (`''` or `""`), an `address` will be denoted by arrow brackets, `<>`.

When we assign and use a reference-type variable, what we write and see is:

```javascript
1) var arr = [];
2) arr.push(1);
```

A representation of lines 1 and 2 above in memory is:

1.

![](https://cdn-images-1.medium.com/max/1600/1*h1aXuPwCyhu6GKwgeFMLDw.png)

2.

![](https://cdn-images-1.medium.com/max/1600/1*HaemMnuU05EW1b3BZPubIg.png)

Notice that the value, the address, contained by the variable `arr` is static. The array in memory is what changes. When we use `arr` to do something, such as pushing a value, the Javascript engine goes to the location of `arr` in memory and works with the information stored there.

#### Assigning by Reference

When a reference type value, an object, is copied to another variable using `=`, the address of that value is what’s actually copied over as if it were a primitive. **Objects are copied by reference** instead of by value.

```javascript
var reference = [1];
var refCopy = reference;
```

The code above looks like this in memory.

![](https://cdn-images-1.medium.com/max/1600/1*d2W3ulHbHRGrFQ-c1SG5gA.png)

Each variable now contains a reference to the _same array_. That means that if we alter `reference`, `refCopy` will see those changes:

```javascript
reference.push(2);
console.log(reference, refCopy); // -> [1, 2], [1, 2]
```

![](https://cdn-images-1.medium.com/max/1600/1*RFrFRXIperg0yTwXauc97w.png)

We’ve pushed `2` into the array in memory. When we use `reference` and `refCopy`, we’re pointing to that same array.

#### Reassigning a Reference

Reassigning a reference variable replaces the old reference.

```javascript
var obj = { first: "reference" };
```

In memory:

![](https://cdn-images-1.medium.com/max/1600/1*PWGp9d2zZ_QGg18HXBSq9Q.png)

When we have a second line:

```javascript
var obj = { first: "reference" };
obj = { second: "ref2" };
```

The address stored in `obj` changes. The first object is still present in memory, and so is the next object:

![](https://cdn-images-1.medium.com/max/1600/1*1h73Wn9IyaiXbhxhmJZmYA.png)

When there are no references to an object remaining, as we see for the address `#234` above, the Javascript engine can perform garbage collection. This just means that the programmer has lost all references to the object and can’t use the object any more, so the engine can go ahead and safely delete it from memory. In this case, the object `{ first: 'reference' }` is no longer accessible and is available to the engine for garbage collection.

### == and ===

When the equality operators, `==` and `===`, are used on reference-type variables, they check the reference. If the variables contain a reference to the same item, the comparison will result in `true`.

```javascript
var arrRef = [’Hi!’];
var arrRef2 = arrRef;console.log(arrRef === arrRef2); // -> true
```

If they’re distinct objects, even if they contain identical properties, the comparison will result in `false`.

```javascript
var arr1 = ["Hi!"];
var arr2 = ["Hi!"];
console.log(arr1 === arr2); // -> false
```

If we have two distinct objects and want to see if their properties are the same, the easiest way to do so is to turn them both into strings and then compare the strings. When the equality operators are comparing primitives, they simply check if the values are the same.

```javascript
var arr1str = JSON.stringify(arr1);
var arr2str = JSON.stringify(arr2);
console.log(arr1str === arr2str); // true
```

Another option would be to recursively loop through the objects and make sure each of the properties are the same.

### Passing Parameters through Functions

When we pass primitive values into a function, the function copies the values into its parameters. It’s effectively the same as using `=`.

```javascript
var hundred = 100;
var two = 2;
function multiply(x, y) {
  // PAUSE
  return x * y;
}
var twoHundred = multiply(hundred, two);
```

In the example above, we give `hundred` the value `100`. When we pass it into `multiply`, the variable `x` gets that value, `100`. The value is copied over as if we used an `=` assignment. Again, the value of `hundred` is not affected. Here is a snapshot of what the memory looks like right at the PAUSE comment line in `multiply`.

![](https://cdn-images-1.medium.com/max/1600/1*3AYcflNTwTTGTgCul0DgBw.png)

#### Pure Functions

We refer to functions that don’t affect anything in the outside scope as _pure functions_. As long as a function only takes primitive values as parameters and doesn’t use any variables in its surrounding scope, it is automatically pure, as it can’t affect anything in the outside scope. All variables created inside are garbage-collected as soon as the function returns.

A function that takes in an Object, however, can mutate the state of its surrounding scope. If a function takes in an array reference and alters the array that it points to, perhaps by pushing to it, variables in the surrounding scope that reference that array see that change. After the function returns, the changes it makes persist in the outer scope. This can cause undesired side effects that can be difficult to track down.

Many native array functions, including `Array.map` and `Array.filter`, are therefore written as pure functions. They take in an array reference and internally, they copy the array and work with the copy instead of the original. This makes it so the original is untouched, the outer scope is unaffected, and we’re returned a reference to a brand new array.

Let’s go into an example of a pure vs. impure function.

```javascript
function changeAgeImpure(person) {
  person.age = 25;
  return person;
}
var alex = {
  name: "Alex",
  age: 30,
};

var changedAlex = changeAgeImpure(alex);
console.log(alex); // -> { name: 'Alex', age: 25 }
console.log(changedAlex); // -> { name: 'Alex', age: 25 }
```

This impure function takes in an object and changes the property `age` on that object to be 25\. Because it acts on the reference it was given, it directly changes the object `alex`. Note that when it returns the `person` object, it is returning the exact same object that was passed in. `alex` and `alexChanged` contain the same reference. It’s redundant to return the `person` variable and to store the reference in a new variable.

Let’s look at a pure function.

```javascript
function changeAgePure(person) {
  var newPersonObj = JSON.parse(JSON.stringify(person));
  newPersonObj.age = 25;
  return newPersonObj;
}
var alex = {
  name: "Alex",
  age: 30,
};

var alexChanged = changeAgePure(alex);
console.log(alex); // -> { name: 'Alex', age: 30 }
console.log(alexChanged); // -> { name: 'Alex', age: 25 }
```

In this function, we use `JSON.stringify` to transform the object we’re passed into a string, and then parse it back into an object with `JSON.parse`. By performing this transformation and storing the result in a new variable, we’ve created a new object. There are other ways to do the same thing such as looping through the original object and assigning each of its properties to a new object, but this way is simplest. The new object has the same properties as the original but it is a distinctly separate object in memory.

When we change the `age` property on this new object, the original is unaffected. This function is now pure. It can’t affect any object outside its own scope, not even the object that was passed in. The new object needs to be returned and stored in a new variable or else it gets garbage collected once the function completes, as the object is no longer in scope.

#### Test Yourself

Value vs. reference is a concept often tested in coding interviews. Try to figure out for yourself what’s logged here.

```javascript
function changeAgeAndReference(person) {
  person.age = 25;
  person = {
    name: "John",
    age: 50,
  };

  return person;
}
var personObj1 = {
  name: "Alex",
  age: 30,
};

var personObj2 = changeAgeAndReference(personObj1);
console.log(personObj1); // -> ?
console.log(personObj2); // -> ?
```

The function first changes the property `age` on the original object it was passed in. It then reassigns the variable to a brand new object and returns that object. Here’s what the two objects are logged out.

```javascript
console.log(personObj1); // -> { name: 'Alex', age: 25 }
console.log(personObj2); // -> { name: 'John', age: 50 }
```

Remember that assignment through function parameters is essentially the same as assignment with `=`. The variable `person` in the function contains a reference to the `personObj1` object, so initially it acts directly on that object. Once we reassign `person` to a new object, it stops affecting the original.

This reassignment does not change the object that `personObj1` points to in the outer scope. `person` has a new reference because it was reassigned but this reassignment doesn’t change `personObj1`.

An equivalent piece of code to the above block would be:

```javascript
var personObj1 = {
  name: "Alex",
  age: 30,
};
var person = personObj1;
person.age = 25;

person = {
  name: "john",
  age: 50,
};

var personObj2 = person;
console.log(personObj1); // -> { name: 'Alex', age: 25 }
console.log(personObj2); // -> { name: 'John', age: '50' }
```

The only difference is that when we use the function, `person` is no longer in scope once the function ends.

#### Kết thúc. Bắt đầu viết code nào.
]]></description>
            <link>https://hungvn.com/blog/explaining-value-vs-reference-in-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/explaining-value-vs-reference-in-javascript</guid>
            <pubDate>Mon, 21 Aug 2017 19:32:28 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Thực hành tối ưu những ứng dụng React]]></title>
            <description><![CDATA[
React có thể chậm. Ý tôi là, bất kỳ ứng dụng React với kích thước trung bình có thể có vẻ chậm. Nhưng trước khi bạn bắt đầu tìm kiếm các phương án thay thế, bạn nên biết rằng bất kỳ ứng dụng Angular hay Ember cỡ trung bình nào cũng chậm.

Tin vui là: Nếu bạn quan tâm đến hiệu suất, **nó khá dễ dàng để làm bất kỳ ứng dụng React trở nên siêu nhanh** ⚡.️ _Đây là cách._

![](https://cdn-images-1.medium.com/max/1600/1*WK96fqAKMrDMBjXB9yNAhg.jpeg)

### Measuring React Performance

What do I mean by “slow”? Let’s take an example:

I’m working on an open-source project called [admin-on-rest](https://github.com/marmelab/admin-on-rest), which leverages [material-ui](http://www.material-ui.com/#/) and [Redux](http://redux.js.org/) to provide an admin GUI for any REST API. This application has a datagrid page, displaying a list of records in a table. When the user changes the sort order, or goes to the next page, or filters the result, the interface isn’t as responsive as I would expect.

The following screencast shows the refresh slowed down five times:

![](https://cdn-images-1.medium.com/max/1600/1*k1biR4XU_ckJzO-ywq2KHQ.gif)

To see what’s happening, I append a `?react_perf` to the URL. This enables [Component Profiling](https://facebook.github.io/react/blog/2016/11/16/react-v15.4.0.html#profiling-components-with-chrome-timeline) since React 15.4\. I wait for the initial datagrid to load. Then I open the Chrome Developer Tools on the Timeline tab, hit the “Record” button, and click on a table header to update the sort order.

Once the data refreshes, I hit the “Record” button again to stop recording, and Chrome displays a yellow flamegraph with a “User Timing” label.

![](https://cdn-images-1.medium.com/max/1600/1*ebhLMlVC1rSBdkmMdqnRmw.png)

If you’ve never seen a flamegraph, it can look intimidating, but it’s actually very easy to use. This “User Timing” graph shows the time passed in each of your components. It hides the time spend inside React internals (you can’t optimize this time anyway), so it lets you focus on optimizing your app.

The Timeline displays screenshots of the window at various stages, this lets me zoom in to the moment I clicked on the table header:

![](https://cdn-images-1.medium.com/max/1600/1*TgP1MXMp-ArO8axt8hPT0Q.png)

It seems that my app rerenders the `<List>` component just after clicking on the sort button, _before_ even fetching the REST data. And this takes more than 500ms. The app just updates the sort icon in the table header, and displays a grey overlay on the datagrid to show that the data is being fetched.

To put it otherwise, the app takes half a second to provide visual feedback to a click. Half a second is definitely perceivable — UI experts say that [users perceive an interface change as instantaneous when it’s below 100ms](https://www.nngroup.com/articles/website-response-times/). A change slower than that is what I mean by “slow”.

### Why Did You Update?

In the flamegraph above, you can see many tiny pits. That’s not a good sign. It means that many components are rerendered. The flamegraph shows that the `<Datagrid>` update takes the most time. Why did the app rerender the entire datagrid before fetching new data? _Let’s dig down._

Understanding the causes of a rerender often implies adding `console.log()` statements in `render()` functions. For functional components, you can use the following one-liner Higher-Order Component (HOC):

```javascript
// in src/log.js
const log = BaseComponent => props => {
   console.log(`Rendering ${BaseComponent.name}`);
   return <BaseComponent {…props} />;
}
export default log;// in src/MyComponent.js
import log from ‘./log’;
export default log(MyComponent);
```

> **Tip**: Another React performance tool worth mentioning is [why-did-you-update](https://github.com/garbles/why-did-you-update). This npm package patches React to emit console warnings whenever a component rerenders with identical props. Caveats: The output is verbose, and it doesn’t work on functional components.

In the example, when the user clicks on a header column, the app emits an action, which changes the state: the list sort order (`currentSort`) is updated. This state change triggers the rerendering of the `<List>` page, which in turn rerenders the entire `<Datagrid>` component. We want the datagrid header to be immediately rendered to show the sort icon change as a feedback to user action.

What makes a React app slow is usually not a single slow component (that would translate in the flamegraph as one large pit). **What makes a React app slow is, most of the time, useless rerenders of many components.**

You may have read that the React VirtualDom is super fast. That’s true, but in a medium size app, a full redraw can easily render hundreds of components. Even the fastest VirtualDom templating engine can’t make that in less than 16ms.

### Cutting Components To Optimize Them

Here is the `<Datagrid>` component `render()` method:

```javascript
// in Datagrid.js
render() {
    const {
        resource,
        children,
        ids,
        data,
        currentSort
    } = this.props;
    return (
        <table>
            <thead>
                <tr>
                    {Children.map(children, (field, index) =>
                        <DatagridHeaderCell
                            key={index}
                            field={field}
                            currentSort={currentSort}
                            updateSort={this.updateSort}
                        />
                    )}
                </tr>
            </thead>
            <tbody>
                {ids.map(id => (
                    <tr key={id}>
                        {Children.map(children, (field, index) =>
                            <DatagridCell
                                record={data[id]}
                                key={`${id}-${index}`}
                                field={field}
                                resource={resource}
                            />
                        )}
                    </tr>
                ))}
            </tbody>
        </table>
    );
}
```

This seems like a very simple implementation of a datagrid, yet it is _very inefficient_. Each `<DatagridCell>` call renders at least two or three components. As you can see in the initial interface screencast, the list has 7 columns, 11 rows, that means 7*11*3 = 231 components rerended. When only the `currentSort` changes, it’s a waste of time. Even though React doesn’t update the real DOM if the rerendered VirtualDom is unchanged, it takes about 500ms to process all the components.

In order to avoid a useless rendering of the table body, I must first _*extract*_ it:

```javascript
// in Datagrid.js
render() {
    const {
        resource,
        children,
        ids,
        data,
        currentSort
    } = this.props;
    return (
        <table>
            <thead>
                <tr>
                    {React.Children.map(children, (field, index) =>
                        <DatagridHeaderCell
                            key={index}
                            field={field}
                            currentSort={currentSort}
                            updateSort={this.updateSort}
                        />
                    )}
                </tr>
            </thead>
            <DatagridBody resource={resource} ids={ids} data={data}>
                {children}
            </DatagridBody>
            </table>
        );
    );
}
```

I created a new `<DatagridBody>` component by extracting the table body logic:

```javascript
// in DatagridBody.js
import React, { Children } from "react";

const DatagridBody = ({ resource, ids, data, children }) => (
  <tbody>
    {ids.map(id => (
      <tr key={id}>
        {Children.map(children, (field, index) => (
          <DatagridCell
            record={data[id]}
            key={`${id}-${index}`}
            field={field}
            resource={resource}
          />
        ))}
      </tr>
    ))}
  </tbody>
);
export default DatagridBody;
```

Extracting the table body has no effect on performance, but it reveals the path to optimization. Large, general purpose components are hard to optimize. Small, single-responsibility components are much easier to deal with.

### `shouldComponentUpdate`

The [React documentation](https://facebook.github.io/react/docs/react-component.html#shouldcomponentupdate) is very clear about the way to avoid useless rerenders: `shouldComponentUpdate()`. By default, React _always renders_ a component to the virtual DOM. In other terms, it’s your job as a developer to check that the props of a component didn’t change and skip rendering altogether in that case.

In the case of the `<DatagridBody>` component above, there should be no rerender of the body unless the props have changed.

So the component should be completed as follows:

```javascript
import React, { Children, Component } from "react";

class DatagridBody extends Component {
  shouldComponentUpdate(nextProps) {
    return nextProps.ids !== this.props.ids || nextProps.data !== this.props.data;
  }
  render() {
    const { resource, ids, data, children } = this.props;
    return (
      <tbody>
        {ids.map(id => (
          <tr key={id}>
            {Children.map(children, (field, index) => (
              <DatagridCell
                record={data[id]}
                key={`${id}-${index}`}
                field={field}
                resource={resource}
              />
            ))}
          </tr>
        ))}
      </tbody>
    );
  }
}
export default DatagridBody;
```

> **Tip**: As an alternative to implementing `shouldComponentUpdate()` manually, I could inherit from React’s `PureComponent` instead of `Component`. This would compare all props using strict equality (`===`) and rerender only if _any_ of the props change. But I know that `resource` and `children` cannot change in that context, so I don’t need to check for their equality.

With this optimization, the rerendering of the `<Datagrid>` component after clicking on a table header skips the table body and its 231 components entirely. This reduces the update time from 500ms to 60ms. That’s a net performance improvement of more than 400ms!

![](https://cdn-images-1.medium.com/max/1600/1*RN8utWqsOiVZlZeMK09-5Q.png)

> **Tip**: Don’t get fooled by the flamegraph width, it’s zoomed even more than the previous flamegraph. This one is definitely better!

The `shouldComponentUpdate` optimization has removed a lot of pits in the graph, and reduced the overall rendering time. I can use the same trick to avoid even more rerenders (e.g. to avoid rendering the sidebar, the action buttons, the table headers that didn’t change, the pagination). After about an hour of work, the entire page renders just 100ms after clicking on a header column. That’s fast enough — even if there is still room for optimization.

Adding a `shouldComponentUpdate` method may seem cumbersome, but if you care about performance, most of the components you write should end up with one.

Don’t do it everywhere — executing `shouldComponentUpdate` on simple components is sometimes slower than just rendering the component. Don’t do that too early in the life of an application either — this would be premature optimization. But as your apps grow, and you can detect performance bottlenecks in your components, add `shouldComponentUpdate` logic to remain fast.

### Recompose

I’m not very happy with the previous change on `<DatagridBody>`: because of `shouldComponentUpdate`, I had to transform a simple, functional component to a class-based component. This adds more lines of code, and every line of code has a cost — to write, to debug, and to maintain.

Fortunately, you can implement the `shouldComponentUpdate` logic in a higher-order component (HOC) thanks to [recompose](https://github.com/acdlite/recompose). It’s a functional utility belt for React, providing for instance the `pure()` HOC:

```javascript
// in DatagridBody.js
import React, { Children } from "react";

import pure from "recompose/pure";

const DatagridBody = ({ resource, ids, data, children }) => (
  <tbody>
    {ids.map(id => (
      <tr key={id}>
        {Children.map(children, (field, index) => (
          <DatagridCell
            record={data[id]}
            key={`${id}-${index}`}
            field={field}
            resource={resource}
          />
        ))}
      </tr>
    ))}
  </tbody>
);
export default pure(DatagridBody);
```

The only difference between this code and the initial implementation is the last line: I export `pure(DatagridBody)` instead of `DatagridBody`. `pure` is like `PureComponent`, but without the extra class boilerplate.

I can even be more specific and target only the props that I know may change, using recompose’s `shouldUpdate()` instead of `pure()`:

```javascript
// in DatagridBody.js
import React, { Children } from 'react';
import shouldUpdate from ‘recompose/shouldUpdate’;
const DatagridBody = ({ resource, ids, data, children }) => (
    ...
);
const checkPropsChange = (props, nextProps) =>
 (nextProps.ids !== props.ids ||
  nextProps.data !== props.data);
export default shouldUpdate(checkPropsChange)(DatagridBody);
```

The `checkPropsChange` function is pure, and I can even export it for unit tests.

The recompose library offers more performance HOCs, like `onlyUpdateForKeys()`, which does exactly the type of check I did in my own `checkPropsChange`:

```javascript
// in DatagridBody.js
import React, { Children } from 'react';
import onlyUpdateForKeys from ‘recompose/onlyUpdateForKeys’;
const DatagridBody = ({ resource, ids, data, children }) => (
    ...
);
export default onlyUpdateForKeys([‘ids’, ‘data’])(DatagridBody);
```

I warmly recommend recompose. Beyond performance optimization, it helps you extract data fetching logic, HOC composition, and props manipulation in a functional and testable way.

### Redux

If you’re using [Redux](http://redux.js.org/) to manage application state _(which I also recommend)_, then connected components are already pure. No need to add another HOC.

Just remember that if only one of the props change, then the connected component rerenders — this includes all its children, too. So even if you use Redux for page components, you should use `pure()` or `shouldUpdate()` for components further down in the render tree.

Also, beware that Redux does the props comparison using strict equality. Since Redux connects the state to a component’s props, if you mutate an object in the state, Redux props comparison will miss it. That’s why you must use **immutability** in your reducers.

For instance, in admin-on-rest, clicking on a table header dispatches a `SET_SORT` action. The reducer listening to that action must pay attention to _replace_ objects in the state, not _update_ them:

```javascript
// in listReducer.js
export const SORT_ASC = "ASC";
export const SORT_DESC = "DESC";
const initialState = {
  sort: "id",
  order: SORT_DESC,
  page: 1,
  perPage: 25,
  filter: {},
};

export default (previousState = initialState, { type, payload }) => {
  switch (type) {
    case SET_SORT:
      if (payload === previousState.sort) {
        // inverse sort order
        return {
          ...previousState,
          order: oppositeOrder(previousState.order),
          page: 1,
        };
      }
      // replace sort field_
      return {
        ...previousState,
        sort: payload,
        order: SORT_ASC,
        page: 1,
      };
    // ...
    default:
      return previousState;
  }
};
```

With this reducer, when Redux checks for changes using triple equal, it finds that the state object is different, and rerenders the datagrid. But had we mutated the state, Redux would have missed the state change, and skipped rerendering by mistake:

```javascript
// don't do this at home
export default (previousState = initialState, { type, payload }) => {
  switch (type) {
    case SET_SORT:
      if (payload === previousState.sort) {
        // never do this
        previousState.order = oppositeOrder(previousState.order);
        return previousState;
      }
      // never do that either
      previousState.sort = payload;
      previousState.order = SORT_ASC;
      previousState.page = 1;
      return previousState;
    // ...
    default:
      return previousState;
  }
};
```

To write immutable reducers, other developers like to use [immutable.js](https://facebook.github.io/immutable-js/), also from Facebook. I find it unnecessary, since ES6 destructuring makes it easy to selectively replace a component properties. Besides, Immutable is heavy (60kB), so think twice before you add it to your project dependencies.

### Reselect

To prevent useless renders in (Redux) connected components, you must also make sure that the `mapStateToProps` function doesn’t return new objects each time it is called.

Take for instance the `<List>` component in admin-on-rest. It grabs the list of records for the current resource (e.g. posts, comments, etc) from the state using the following code:

```javascript
// in List.js
import React from 'react';
import { connect } from 'react-redux';
const List = (props) => ...
const mapStateToProps = (state, props) => {
    const resourceState = state.admin[props.resource];
    return {
        ids: resourceState.list.ids,
        data: Object.keys(resourceState.data)
            .filter(id => resourceState.list.ids.includes(id))
            .map(id => resourceState.data[id])
            .reduce((data, record) => {
                data[record.id] = record;
                return data;
            }, {}),
    };
};
export default connect(mapStateToProps)(List);
```

The state contains an array of all the previously fetched records, indexed by resource. For instance, `state.admin.posts.data` contains the list of posts:

```javascript
{
   23: { id: 23, title: “Hello, World”, /* … */ },
   45: { id: 45, title: “Lorem Ipsum”, /* … */ },
   67: { id: 67, title: “Sic dolor amet”, /* … */ },
}
```

The `mapStateToProps` function filters this state object to return only the records actually displayed in the list. Something like:

```javascript
{
    23: { id: 23, title: “Hello, World”, /* … */ },
    67: { id: 67, title: “Sic dolor amet”, /* … */ },
}
```

The problem is that each time `mapStateToProps` runs, it returns a new object, even if the underlying objects didn’t change. As a consequence, the `<List>` component rerenders every time something in the state changes — while id should only change if the date or ids change.

[Reselect](https://github.com/reactjs/reselect) solves this problem by using memoization. Instead of computing the props directly in `mapStateToProps`, you use a _selector_ from reselect, which returns the same output if the input didn’t change.

```javascript
import React from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect'
const List = (props) => ...
const idsSelector = (state, props) =>
    state.admin[props.resource].ids
const dataSelector = (state, props) =>
    state.admin[props.resource].data
const filteredDataSelector = createSelector(
  idsSelector,
  dataSelector
  (ids, data) => Object.keys(data)
      .filter(id => ids.includes(id))
      .map(id => data[id])
      .reduce((data, record) => {
          data[record.id] = record;
          return data;
      }, {})
)
const mapStateToProps = (state, props) => {
    const resourceState = state.admin[props.resource];
    return {
        ids: idsSelector(state, props),
        data: filteredDataSelector(state, props),
    };
};
export default connect(mapStateToProps)(List);
```

Now the `<List>` component will only rerender if a subset of the state changes.

As for recompose, reselect selectors are pure functions, easy to test and compose. It’s a great way to code your selectors for Redux connected components.

### Beware of Object Literals in JSX

Once your components become more “pure”, you start detecting bad patterns that lead to useless rerenders. The most common is the usage of object literals in JSX, which I like to call “**The infamous** `\{\{`”. Let me give you an example:

```javascript
import React from "react";

import MyTableComponent from "./MyTableComponent";

const Datagrid = props => <MyTableComponent style={{ marginTop: 10 }}>...</MyTableComponent>;
```

The `style` prop of the `<MyTableComponent>` component gets a new value every time the `<Datagrid>` component is rendered. So even if `<MyTableComponent>` is pure, it will be rendered every time `<Datagrid>` is rendered. In fact, each time you pass an object literal as prop to a child component, you break purity. The solution is simple:

```javascript
import React from "react";

import MyTableComponent from "./MyTableComponent";

const tableStyle = { marginTop: 10 };
const Datagrid = props => <MyTableComponent style={tableStyle}>...</MyTableComponent>;
```

This looks very basic, but I’ve seen this mistake so many times that I’ve developed a sense for detecting the infamous `\{\{` in JSX. I routinely replace it with constants.

Another usual suspect for hijacking pure components is `React.cloneElement()`. If you pass a prop by value as second parameter, the cloned element will receive new props at every render.

```javascript
// bad
const MyComponent = (props) => <div>{React.cloneElement(Foo, { bar: 1 })}</div>;

// good
const additionalProps = { bar: 1 };
const MyComponent = (props) => (
  <div>{React.cloneElement(Foo, additionalProps)}</div>
);
```

This has bitten me a couple times with [material-ui](http://www.material-ui.com/#/), for instance with the following code:

```javascript
import { CreateButton, RefreshButton } from "admin-on-rest";
import { CardActions } from "material-ui/Card";

const Toolbar = ({ basePath, refresh }) => (
  <CardActions>
    <CreateButton basePath={basePath} />
    <RefreshButton refresh={refresh} />
  </CardActions>
);
export default Toolbar;
```

Although `<CreateButton>` is pure, it was rendered every time `<Toolbar>` was rendered. That’s because material-ui’s `<CardActions>` adds a special style to its first child to accommodate for margins — and it does so with an object literal. So `<CreateButton>` received a different `style` prop every time. I solved it using recompose’s `onlyUpdateForKeys()` HOC.

```javascript
// in Toolbar.js
import onlyUpdateForKeys from 'recompose/onlyUpdateForKeys';
const Toolbar = ({ basePath, refresh }) => (
    ...
);
export default onlyUpdateForKeys(['basePath', 'refresh'])(Toolbar);
```

### Conclusion

There are many other things you should do to keep your React app fast (using keys, lazy loading heavy routes, the `react-addons-perf` package, using ServiceWorkers to cache app state, going isomorphic, etc), but implementing `shouldComponentUpdate` correctly is the first step — and the most rewarding.

React isn’t fast by default, but it offers all the tools to be fast whatever the size of the application.

This may seem counterintuitive, especially since many frameworks offering an alternative to React claim themselves as n times faster. But React puts developer experience before performance. That’s the reason why developing large apps with React is such a pleasant experience, without bad surprises, and a constant implementation rate.

Just remember to profile your app every once in a while, and dedicate some time to add a few `pure()` calls where it’s needed. Don’t do it first, or spend too much time to over optimize each and every component — except if you’re on mobile. And remember to test on various devices to get a good impression of your app’s responsiveness from a user’s point of view.

![](https://cdn-images-1.medium.com/max/1600/1*WK96fqAKMrDMBjXB9yNAhg.jpeg)

**If you want to read more about React performance optimization, here is a list of great articles on the subject:**

- [React Rally: Animated — React Performance Toolbox](https://speakerdeck.com/vjeux/react-rally-animated-react-performance-toolbox): A fabulous slide deck by Christopher Chedeau (Vjeux), one of the React Native developers. He’s French, by the way.
- [Progressive Web Apps with React.js: Part 2 — Page Load Performance](https://medium.com/@addyosmani/progressive-web-apps-with-react-js-part-2-page-load-performance-33b932d97cf2#.zhzfe1iuc) by Addy Osmany, who works at Google and writes a lot of blog posts about web performance
- [Optimizing the Performance of Your React Application](https://auth0.com/blog/optimizing-react/) focuses on the `react-addons-perf` package to profile React apps precisely
- [React Higher Order Components in depth](https://medium.com/@franleplant/react-higher-order-components-in-depth-cf9032ee6c3e#.km5882wi8), interesting for the introduction of Render Hijacking
- [A Deep Dive into React Perf Debugging](http://benchling.engineering/deep-dive-react-perf-debugging/) describes a step-by-step debugging session with Chrome dev Tools
- [Making React reactive: the pursuit of high performing, easily maintainable React apps](https://www.mendix.com/tech-blog/making-react-reactive-pursuit-high-performing-easily-maintainable-react-apps/) on using Observables to avoid rerenders

![](https://cdn-images-1.medium.com/max/1600/1*WK96fqAKMrDMBjXB9yNAhg.jpeg)
]]></description>
            <link>https://hungvn.com/blog/optimizing-react-apps-in-practice</link>
            <guid isPermaLink="true">https://hungvn.com/blog/optimizing-react-apps-in-practice</guid>
            <pubDate>Mon, 21 Aug 2017 19:21:55 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Use const Until You Have to Use let]]></title>
            <description><![CDATA[
Aloha, web surfer. So perhaps you’re a `let` fan who came here to see what was up. Or maybe you’re a beginner, just moving out of `var` town and into the wild west that is ES6 variable declaration. Whatever your experience level may be, I hope this article provides valuable insights and leaves you with a solid rule of thumb for instantiating variables in Javascript. My other hope is that, upon finishing this article, you can confidently part ways with `var` – it is time.

### Once Upon A Time…

…in a specification authored somewhere in California…

…a keyword for variable instantiation was created and called `var`.

If you remember your first day learning Javascript, it probably involved `var`. This little keyword was our only option for declaring variables in Javascript for a long time. In fact, every web site and application that used Javascript between it’s inception in 1995 and the release of ECMAScript 2015 (ES6) used `var` and only `var` to create variables. (Someone fact check me on this statement, but I think it’s accurate.)

The `var` keyword is no longer relevant, but in order to truly understand our present, we must understand our past.

Some important things to know about variables created with the `var` keyword:

```
1) They are function scoped
2) Their declarations get hoisted
3) They can be declared without a value

```

#### 1 “They are function scoped”

This means that `var` creates a variable that only exists inside of the function where it was declared.

_(Unless it was not declared inside a function. In that case, it exists ~everywhere~ 😲. More on this in fact #3.)_

Here’s a code snippet that illustrates the behavior of a function scoped variable:

```javascript
function logA() {
  var a = 2;
  console.log(a); // inside of `logA()`, `a` exists with value 2
}

console.log(a); // ReferenceError! Outside of logA(), `a` is not defined.
```

I think it’s worth clarifying that when I say “inside of” `logA()`, I mean “between `logA()`’s curly brackets”.

#### 2 “Their declarations get hoisted” 🏋

Variable hoisting basically boils down to the fact that a variable declared with `var` can be instantiated _after_ it gets used.

This code…

```javascript
function logB() {
  b = 2; // using b to hold the number 2
  console.log(b); // using b to print 2 in the console

  var b; // instantiating b 🤔
}
```

…will get transformed into something like this code…

```javascript
function logB() {
  var b; // instantiation is hoisted to the top of logB()'s scope

  b = 2;
  console.log(b);
}
```

…at _compile_ time (yes, [Javascript gets compiled](https://github.com/getify/You-Dont-Know-JS/blob/31e1d4ff600d88cc2ce243903ab8a3a9d15cce15/scope%20%26%20closures/ch1.md)). That’s why it doesn’t matter (to the browser) where we instantiate our variables – the declarations get to skip the line every time.

There’s a dark side to the way `var` gets hoisted, though. Javascript’s compiler can be a bit _too_ helpful in some situations.

If we use a variable within a function but don’t instantiate the variable in that function, the compiler will look for a `var` in the parent function scope. If it doesn’t find it there, it will keep looking all the way up the scope chain until it gets to the _global_ scope. If it _still_ doesn’t see a `var` declaration up there, it will just go ahead and _make one for you_, as demonstrated in this snippet:

```javascript
function logC() {
  c = 2;
  console.log(c); // 2
}
// c is not instantiated in this program, yet it just works...
```

Yikes.

I guess this could be convenient sometimes when messing around in a REPL or something…

But for the most part, this is bananas. `"use strict";` prevents this and should be included at the top of any ES5 script.

#### 3 “They can be declared without a value”

You may have seen someone do something along these lines before:

```javascript
// declare all my variables at the top of the script
var a, b, c;

// use them down here
a = 1;
b = 2;
c = a + b;
```

Put a pin in this because it becomes important later.

### Times Have Changed

The three facets of `var` that I just covered come together to create an extremely flexible variable declaration mechanism. While flexibility itself is not a bad thing and having only one variable instantiation keyword means a little more flexibility is necessary, `var` is simply doing too much. Function scope isn’t a problem, but reassigning variables is so-so and should only be used for `for` loops and times when it’s completely unavoidable (and when it’s unavoidable, it probably means we have bigger fish to fry). The same goes for declaring variables without values. Lastly, being allowed to use a variable whether we declared it or not is silly.

So, in order to address these drawbacks of `var` and save us developers from the pitfalls these “helpful” features can cause, the ES6 specification introduced two new variable keywords: `const` and `let`.

Remember, the primary goal of this post is to show that it’s time to ditch `var`. Times have changed and `var` doesn’t make the cut.

### Let me explain…

In 2015, Javascript’s variable declaration family grew to include `let`, which deviates significantly from `var` in that it is _block_ scoped. This basically means that we now have two units of scope available:

#### 1 Functions

```javascript
function() {
  let i = 'aye'; // `i` is scoped to this function
  console.log(i); // "aye"
}
console.log(i); // ReferenceError

```

#### 2 Blocks

```javascript
{
  let i = "oi"; // `i` is scoped to this block
  console.log(i); // "oi"
}
console.log(i); // ReferenceError
```

The `let` keyword has another helpful constraint: the variable cannot be accessed _before_ its declaration (`let` [does get hoisted](https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6) though).

One thing `let` shares with `var` is that it can be used to declare a variable without an initial value. Like in the example above, we could have done

```javascript
{
  let i;
  i = "oi";
}
```

and it would’ve worked.

#### Bookmarks for `let` 👓

- [Are Let / Const Hoisted?](https://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6)
- [YDKJS Blocks As Scopes](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md#blocks-as-scopes)
- [YDKJS Let](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md#let)
- [YDKJS Garbage Collection](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md#garbage-collection)
- [YDKJS Let loops](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md#let-loops)

### Const stop, won’t stop

Okay, `const` is my favorite variable declaration keyword in Javascript. I default to `const` over `let` and never use `var`. As a rule, I always use `const` unless I _have_ to use `let`.

Remember how variables declared with `var` can be instantiated with empty values? This type of instantiation is allowed with `let`, too. It is not so with `const`. Oh no, `const` requires that you provide a value up front. Otherwise, it will turn its nose up at you and refuse to create a variable, _“If you don’t know what’s going in the variable, monsieur/madame, then why do you need it at all?”_ – this is good.

But there’s more! `const` goes one step further and ensures that the variable cannot be reassigned [**note:** this does not mean the variable is _immutable_]. For example,

```javascript
const a = "ay";
a = 2; // TypeError: Assignment to constant variable.
```

Comparing `const` to `var`:

1 `const` is block scoped, `var` is function scoped. 2 `const` has to be instantiated _with_ a value, `var` does not 3 `const` cannot be reassigned, `var` can 4 `const` cannot be accessed prior to instantiation, `var` can

So basically `const` is the strictest variable instantiation tool we have at our disposal. The constraints it provides protect us from several possible errors, making the development process smoother.

### Exceptions: When to use `let`

While I recommend defaulting to `const`, some situations demand the use of `let`.

Here is a quote by Eric Elliot from a [great article](https://medium.com/javascript-scene/javascript-es6-var-let-or-const-ba58b8dcde75) he wrote about the three keywords:

```javascript
`let`, is a signal that the variable may be reassigned, such as a counter in a loop, or a value swap in an algorithm. It also signals that the variable will be used only in the block it’s defined in, which is not always the entire containing function.

```

In other words, `for` loops and mathematical algorithms are the only times we would need to reach for `let`. Other than that, `const` is the strongest, safest bet.

### Use const until you have to use let

I hope this article helped you on your quest to understand `let` and `const` and how they differ from `var`. I also hope you can comfortably ditch `var` and use `const` until you have to use `let`. I’m still learning myself and there are certainly gaps in this article. Feel free to correct me when I’m wrong or bring missing information to light.
]]></description>
            <link>https://hungvn.com/blog/use-const-until-you-have-to-use-let</link>
            <guid isPermaLink="true">https://hungvn.com/blog/use-const-until-you-have-to-use-let</guid>
            <pubDate>Mon, 21 Aug 2017 18:44:18 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to use Memoize to cache JavaScript function results and speed up your code]]></title>
            <description><![CDATA[
Functions are an integral part of programming. They help add **modularity** and **reusability** to our code.

It’s quite common to divide our program into chunks using functions which we can call later to perform some useful action.

Sometimes, a function can become expensive to call multiple times (say, a function to calculate the [factorial](https://en.wikipedia.org/wiki/Factorial) of a number). But there’s a way we can optimize such functions and make them execute much faster: **caching**.

For example, let’s say we have a `function` to return the factorial of a number:

```javascript
function factorial(n) {
  // Calculations: n * (n-1) * (n-2) * ... (2) * (1)
  return factorial;
}
```

Great, now let’s find `factorial(50)`. The computer will perform calculations and return us the final answer, sweet!

When that’s done, let’s find `factorial(51)`. The computer again performs a number of calculations and gets us the result, but you might have noticed that we’re already repeating a number of steps that could have been avoided. An optimized way would be:

```javascript
factorial(51) = factorial(50) * 51
```

But our `function` performs the calculations from scratch every time it’s called:

```javascript
factorial(51) = 51 * 50 * 49 * ... * 2 * 1
```

Wouldn’t it be cool if somehow our `factorial` function could remember the values from its previous calculations and use them to speed up the execution?

In comes **memoization**, a way for our `function` to remember (cache) the results. Now that you’ve a basic understanding of what we’re trying to achieve, here’s a formal definition:

> [**Memoization**](https://en.wikipedia.org/wiki/Memoization) is an optimization technique used primarily to speed up computer programs by **storing the results of expensive function calls** and returning the cached result when the same inputs occur again

**Memoizing** in simple terms means **memorizing** or storing in memory. A memoized function is usually faster because if the function is called subsequently with the previous value(s), then instead of executing the function, we would be fetching the result from the cache.

Here’s what a simple memoized function might look like _(and here’s a_ [_CodePen_](https://codepen.io/divyanshu013/pen/xdQPvp?editors=0011) _in case you want to interact with it)_:

```javascript
// a simple function to add something
const add = n => n + 10;
add(9);

// a simple memoized function to add something
const memoizedAdd = () => {
  let cache = {};
  return n => {
    if (n in cache) {
      console.log("Fetching from cache");
      return cache[n];
    } else {
      console.log("Calculating result");
      let result = n + 10;
      cache[n] = result;
      return result;
    }
  };
};

// returned function from memoizedAdd
const newAdd = memoizedAdd();
console.log(newAdd(9)); // calculated
console.log(newAdd(9)); // cached
```

### Memoization takeaways

Some takeaways from the above code are:

- `memoizedAdd` returns a `function` which is invoked later. This is possible because in JavaScript, functions are first class objects which lets us use them as [higher order functions](http://eloquentjavascript.net/05_higher_order.html#h_xxCc98lOBK) and return another function.
- `cache` can remember its _values_ since the returned function has a [closure](https://developer.mozilla.org/en/docs/Web/JavaScript/Closures) over it.
- It’s essential that the memoized function is [pure](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976). A pure function will return the same output for a particular input no mater how many times it’s called, which makes the `cache` work as expected.

### Writing your own `memoize` function

The previous code works fine but what if we wanted to turn any function into a memoized function?

Here’s how to write your own memoize function ([codepen](https://codepen.io/divyanshu013/pen/zwMPdK?editors=0011#code-area)):

```javascript
// a simple pure function to get a value adding 10
const add = n => n + 10;
console.log("Simple call", add(3));

// a simple memoize function that takes in a function
// and returns a memoized function
const memoize = fn => {
  let cache = {};
  return (...args) => {
    let n = args[0]; // just taking one argument here
    if (n in cache) {
      console.log("Fetching from cache");
      return cache[n];
    } else {
      console.log("Calculating result");
      let result = fn(n);
      cache[n] = result;
      return result;
    }
  };
};

// creating a memoized function for the 'add' pure function
const memoizedAdd = memoize(add);
console.log(memoizedAdd(3)); // calculated
console.log(memoizedAdd(3)); // cached
console.log(memoizedAdd(4)); // calculated
console.log(memoizedAdd(4)); // cached
```

Now that’s great! This simple `memoize` function will wrap any simple `function` into a memoized equivalent. The code works fine for simple functions and it can be easily tweaked to handle any number of `arguments` as per your needs. Another alternative is to make use of some de-facto libraries such as:

- [Lodash](https://lodash.com/docs/4.17.4#memoize)’s `_.memoize(func, [resolver])`
- ES7 `@memoize` [decorators](https://babeljs.io/docs/plugins/transform-decorators/) from [decko](https://github.com/developit/decko#memoize)

### Memoizing recursive functions

If you try passing in a recursive function to the `memoize` function above or `_.memoize` from Lodash, the results won’t be as expected since the recursive function on its subsequent calls will end up calling itself instead of the memoized function thereby making no use of the `cache`.

Just make sure that your recursive function is calling the memoized function. Here’s how you can tweak a textbook [factorial](https://en.wikipedia.org/wiki/Factorial) example ([codepen](https://codepen.io/divyanshu013/pen/JNevOm)):

```javascript
// same memoize function from before
const memoize = fn => {
  let cache = {};
  return (...args) => {
    let n = args[0];
    if (n in cache) {
      console.log("Fetching from cache", n);
      return cache[n];
    } else {
      console.log("Calculating result", n);
      let result = fn(n);
      cache[n] = result;
      return result;
    }
  };
};

const factorial = memoize(x => {
  if (x === 0) {
    return 1;
  } else {
    return x * factorial(x - 1);
  }
});

console.log(factorial(5)); // calculated
console.log(factorial(6)); // calculated for 6 and cached for 5
```

A few points to note from this code:

- The `factorial` function is recursively calling a memoized version of itself.
- The memoized function is caching the values of previous factorials which significantly improves calculations since they can be reused `factorial(6) = 6 * factorial(5)`

### Is memoization same as caching?

Yes, kind of. Memoization is actually a specific type of caching. While caching can refer in general to any storing technique (like [HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching)) for future use, memoizing specifically involves _caching_ the return values of a `function`.

### When to memoize your functions

Although it might look like memoization can be used with all functions, it actually has limited use cases:

- In order to memoize a function, it should be pure so that return values are the same for same inputs every time
- Memoizing is a trade-off between added space and added speed and thus only significant for functions having a limited input range so that cached values can be made use of more frequently
- It might look like you should memoize your API calls however it isn’t necessary because the browser automatically caches them for you. See [HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) for more detail
- The best use case I found for memoized functions is **for heavy computational functions** which can significantly improve performance (factorial and fibonacci are not really good real world examples)
- If you’re into React/Redux you can check out [reselect](https://github.com/reactjs/reselect#creating-a-memoized-selector) which uses a _memoized selector_ to ensure that calculations only happen when a change happens in a related part of the state tree.

#### Further reading

The following links can be useful if you would like to know more about some of the topics from this article in more detail:

- [Higher order functions](http://eloquentjavascript.net/05_higher_order.html#h_xxCc98lOBK) in JavaScript
- [Closures](https://developer.mozilla.org/en/docs/Web/JavaScript/Closures) in JavaScript
- [Pure functions](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976)
- Lodash’s `_.memoize` [docs](https://lodash.com/docs/4.17.4#memoize) and [source code](https://github.com/lodash/lodash/blob/4.17.4/lodash.js#L10554-L10572)
- More memoization examples [here](https://www.sitepoint.com/implementing-memoization-in-javascript/) and [here](http://inlehmansterms.net/2015/03/01/javascript-memoization/)
- [reactjs/reselect](https://github.com/reactjs/reselect)

I hope this article was useful for you, and you’ve gained a better understanding of memoization in JavaScript.
]]></description>
            <link>https://hungvn.com/blog/how-to-use-memoize-to-cache-javascript-function-results</link>
            <guid isPermaLink="true">https://hungvn.com/blog/how-to-use-memoize-to-cache-javascript-function-results</guid>
            <pubDate>Mon, 21 Aug 2017 14:58:54 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[3 Reasons why I stopped using React.setState]]></title>
            <description><![CDATA[
Since a few months I’ve stopped using React’s _setState_ on all my new React components. Don’t get me wrong, I didn’t stop having local component state, I just stopped using React to manage it. And it’s been delightful!

Using _setState_ is tricky for beginners. Even experienced React programmers easily introduce subtle bugs when using React’s own state mechanism, like this:

![](https://cdn-images-1.medium.com/max/1600/1*v2qbGqdV8wM1G4ixs7woEw.gif)Bug introduced by forgetting that React state is asynchronous; the log is always one item behind

The excellent Reacts [docs](https://facebook.github.io/react/docs/component-api.html) sum up everything that could go wrong when using _setState_:

![](https://cdn-images-1.medium.com/max/1600/1*OtKvlJDJPjbSVM6o-yjL_Q.png)

To summarize, there are 3 issues when using _setState:_

#### 1\. setState is asynchronous

Many devs don’t realize this initially, but setState is _asynchronous._ If you set some state, than take a look at it, you will still see the old state.This is the most tricky part of setState. setState calls don’t look asynchronous, and naively calling setState introduces very subtle bugs. The next gist demonstrates that nicely:

<Gist id="bd5bdff6c3488d6abcb3a1a90f9bcce1" />

At first glance this might look fine. Two event handlers and a utility function that fire the _onSelect_ event if provided. However, this _Select_ component has a bug that is nicely demonstrated in the GIF above. _onSelect_ is always fired with the previous value of _state.selection_, because _setState_ hasn’t done it’s job _yet_ when the _fireOnSelect_ helperis invoked. I think the least React could do here is rename the method to _scheduleState_ or make the callback required.

> This bug is easily fixed, the tricky part is realizing it’s there.

#### 2\. setState causes unnecessary renders

The second issue with _setState_ is that it always triggers a re-render. Often those re-renders are unnecessary. You can use the [_printWasted_](https://facebook.github.io/react/docs/perf.html#perf.printwastedmeasurements) method from the React performance tools to find out when this happens. But roughly speaking there are several reasons why a re-render may be unnecessary:

- The new state is actually the same as the previous one. This can often be addressed by implementing _shouldComponentUpdate_. You may already be using a (pure render) library to solve this for you.
- Sometimes the changed state is relevant for the rendering, but not under all circumstances. For example when some data is only conditionally visible.
- Thirdly, as pointed out in Aria Buckles’ [talk at React Europe 2015](https://youtu.be/2Qu-Ulrsfl8?t=12m09s), sometimes instance state is not relevant for the rendering at all! This is often householding state related to managing event listeners, timer ID’s etc.

#### 3\. setState is not sufficient to capture all component state

Following the last point above, not all component state should be stored and updated using _setState_. More complex components often have administration that is needed by lifecycle hooks to manage timers, network requests, events etc. Managing those with _setState_ not only causes unnecessary renders, but also causes related lifecycle hooks to be triggered again, leading to weird situations.

### Managing local component state with MobX

(Surprise, surprise) At [Mendix](http://www.mendix.com) we already rely on MobX to manage all our stores. However, we were still using React’s own state mechanism for local component state. Recently, we switched to managing local component state with MobX as well. That looks like this:

<Gist id="67ab0a5ac4ee3df577d394273e71bc33" />

For completeness sake:

![](https://cdn-images-1.medium.com/max/1600/1*LPl8MGfkPyWGtRERQdw_3w.gif)No unexpected bugs when using a state mechanism that is synchronous

The above code snippet is not only more concise, MobX also addresses all of the setState related issues:

Changes to the state are immediately reflected in the local component state. This makes our logic simpler and code reuse easier. You don’t have to compensate for the fact that the state might not have been updated yet.

MobX determines at runtime which observables are relevant for rendering. So observables that are temporarily irrelevant for the rendering, won’t cause a re-rendering. Until they are relevant again. For this reason, there are also no rendering penalties (or lifecycle issues) when marking fields as _@observable_ that are not relevant for rendering at all.

So renderable and non-renderable state is treated uniformly. In addition, state stored in our components now works the same as state stored in any of our stores. This makes it trivial to refactor components, and move local component state into a separate store or vice versa. Which is demonstrated in this [egghead](https://egghead.io/lessons/javascript-mobx-and-react-intro-syncing-the-ui-with-the-app-state-using-observable-and-observer) tutorial.

> MobX effectively turns your components into small stores

Furthermore, rookie mistakes like assigning values directly to the _state_ object cannot be made anymore when using observables for state. Oh, and don’t worry about implementing _shouldComponentUpdate_ or _PureRenderMixin,_ MobX already takes care of that as well. Finally, you might be wondering, what if I want to wait until _setState_ has finished? Well, you can still use the \_compentDidUpdate l_ifecycle hook for that.

#### Sounds cool! How do I get started with MobX?

Pretty simple, follow the [10 minute interactive introduction](https://mobxjs.github.io/mobx/getting-started.html) or watch the aforementioned video. You can simply take a single component from your code base, slap _@observer_ on it and introduce some _@observable_ properties. You don’t even have to replace your existing _setState_ calls, they continue to work while using MobX. Although, within a few minutes you might find them so convoluted that you will replace them anyway :). (Oh, and if you don’t like decorators, no worries, it works with [good ol’ ES5 as well](https://github.com/mobxjs/mobx/blob/gh-pages/docs/best/syntax.md#react-components)).

#### TL;DR:

I’ve stopped using React to manage local component state. I use MobX instead. Now React is truly “just the view” :). MobX now manages both local component state and state in stores. It is concise, synchronous, efficient and uniform. From experience, I’ve learned that MobX is even easier to explain to React beginners than React’s own _setState._ It keeps our components clean and simple.

- [JSBin](http://jsbin.com/yelazuvamo/edit?js,console,output) using _setState_ for state management
- [JSBin](http://jsbin.com/sofezamavi/1/edit?js,console,output) using _MobX observables_ for state management
]]></description>
            <link>https://hungvn.com/blog/3-reasons-why-i-stopped-using-react-setstate</link>
            <guid isPermaLink="true">https://hungvn.com/blog/3-reasons-why-i-stopped-using-react-setstate</guid>
            <pubDate>Mon, 21 Aug 2017 14:43:25 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Our Best Practices for Writing React Components]]></title>
            <description><![CDATA[
When I first started writing React, I remember seeing many different approaches to writing components, varying greatly from tutorial to tutorial. Though the framework has matured considerably since then, there doesn't seem to yet be a firm 'right' way of doing things.

Over the past year at [MuseFind](https://musefind.com/), our team has written a lot of React components. We've gradually refined our approach until we're happy with it.

This guide represents our suggested best practices. We hope it will be useful, whether you're a beginner or experienced.

Before we get started, a couple of notes:

- We use ES6 and ES7 syntax.
- If you're not sure of the distinction between presentational and container components, we recommend you [read this first](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.kuvqndiqq).
- Please let us know in the comments if you have any suggestions, questions, or feedback.

### Class Based Components

Class based components are stateful and/or contain methods. We try to use them as sparingly as possible, but they have their place.

Let's incrementally build our component, line by line.

#### Importing CSS

```javascript
import React, { Component } from "react";

import { observer } from "mobx-react";

import ExpandableForm from "./ExpandableForm";
import "./styles/ProfileContainer.css";
```

I like [CSS in JavaScript](https://medium.freecodecamp.com/a-5-minute-intro-to-styled-components-41f40eb7cd55), I do — in theory. But it's still a new idea, and a mature solution hasn't emerged. Until then, we import a CSS file to each component.

We also separate our dependency imports from local imports by a newline.

#### Initializing State

```javascript
import React, { Component } from 'react'
import { observer } from 'mobx-react'

import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'

export default class ProfileContainer extends Component {
  state = { expanded: false }
```

You can also use the older approach of initializing state in the constructor. More on that [here](http://stackoverflow.com/questions/35662932/react-constructor-es6-vs-es7). We prefer the cleaner way.

We also make sure to export our class as the default.

#### propTypes and defaultProps

```javascript
import React, { Component } from 'react'
import { observer } from 'mobx-react'
import { string, object } from 'prop-types'

import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'

export default class ProfileContainer extends Component {
  state = { expanded: false }
  static propTypes = {
    model: object.isRequired,
    title: string
  }
  static defaultProps = {
    model: {
      id: 0
    },
    title: 'Your Name'
  }
```

propTypes and defaultProps are static properties, declared as high as possible within the component code. They should be immediately visible to other devs reading the file, since they serve as documentation.

If using React 15.3.0 or higher, use the [prop-types](https://github.com/reactjs/prop-types) package instead of React.PropTypes — nicely destructured, of course.

All your components should have propTypes.

#### Methods

```javascript
import React, { Component } from 'react'
import { observer } from 'mobx-react'
import { string, object } from 'prop-types'

import ExpandableForm from './ExpandableForm'
import './styles/ProfileContainer.css'

export default class ProfileContainer extends Component {
  state = { expanded: false }

  static propTypes = {
    model: object.isRequired,
    title: string
  }

  static defaultProps = {
    model: {
      id: 0
    },
    title: 'Your Name'
  }

  handleSubmit = (e) => {
    e.preventDefault()
    this.props.model.save()
  }

  handleNameChange = (e) => {
    this.props.model.changeName(e.target.value)
  }

  handleExpand = (e) => {
    e.preventDefault()
    this.setState({ expanded: !this.state.expanded })
  }
```

With class components, when you pass methods to subcomponents, you have to ensure that they have the right _this_ when they're called. This is usually achieved by passing _this.handleSubmit.bind(this)_ to the subcomponent.

We think this approach is cleaner and easier, maintaining the correct context automatically via the ES6 arrow function.

#### **Passing setState a Function**

In the above example, we do this:

```javascript
this.setState({ expanded: !this.state.expanded });
```

Here's the dirty secret about setState — it's actually asynchronous. React batches state changes for performance reasons, so the state may not change immediately after setState is called.

That means you should not rely on the current state when calling setState — since you can't be sure what that state will be!

Here's the solution — pass a function to setState, with the previous state as an argument.

```javascript
this.setState(prevState => ({ expanded: !prevState.expanded }));
```

(Thanks to [Austin Wood](https://medium.com/@indiesquidge) for his help with this section).

#### Destructuring Props

```javascript
import React, { Component } from "react";

import { observer } from "mobx-react";
import { string, object } from "prop-types";

import ExpandableForm from "./ExpandableForm";
import "./styles/ProfileContainer.css";

export default class ProfileContainer extends Component {
  state = { expanded: false };
  static propTypes = {
    model: object.isRequired,
    title: string,
  };

  static defaultProps = {
    model: {
      id: 0,
    },
    title: "Your Name",
  };

  handleSubmit = e => {
    e.preventDefault();
    this.props.model.save();
  };

  handleNameChange = e => {
    this.props.model.changeName(e.target.value);
  };

  handleExpand = e => {
    e.preventDefault();
    this.setState(prevState => ({ expanded: !prevState.expanded }));
  };

  render() {
    const { model, title } = this.props;
    return (
      <ExpandableForm
        onSubmit={this.handleSubmit}
        expanded={this.state.expanded}
        onExpand={this.handleExpand}
      >
        <div>
          <h1>{title}</h1>
          <input
            type="text"
            value={model.name}
            onChange={this.handleNameChange}
            placeholder="Your Name"
          />
        </div>
      </ExpandableForm>
    );
  }
}
```

Components with many props should have each prop on a newline, like above.

#### Decorators

```javascript
@observer
export default class ProfileContainer extends Component {
```

If you're using something like [mobx](https://github.com/mobxjs/mobx), you can decorate your class components like so — which is the same as passing the component into a function.

[Decorators](http://javascript.info/tutorial/decorators) are flexible and readable way of modifying component functionality. We use them extensively, with mobx and our own [mobx-models](https://github.com/musefind/mobx-models) library.

If you don't want to use decorators, do the following:

```javascript
class ProfileContainer extends Component {
  // Component code
}

export default observer(ProfileContainer);
```

#### Closures

Avoid passing new closures to subcomponents, like so:

```javascript
<input
  type="text"
  value={model.name}
  // onChange={(e) => { model.name = e.target.value }}
  // ^Not this. Use the below:
  onChange={this.handleChange}
  placeholder="Your Name"
/>
```

Here's why: every time the parent component renders, a new function is created and passed to the input.

If the input were a React component, this would automatically trigger it to re-render, regardless of whether its other props have actually changed.

Reconciliation is the most expensive part of React. Don't make it harder than it needs to be! Plus, passing a class method is easier to read, debug, and change.

Here's our full component:

<Gist id="70e436951dfeeb82dfdd4aa6d2541dce" />

### Functional Components

These components have no state and no methods. They're pure, and easy to reason about. Use them as often as possible.

#### propTypes

```javascript
import React from "react";

import { observer } from "mobx-react";
import { func, bool } from "prop-types";

import "./styles/Form.css";

ExpandableForm.propTypes = {
  onSubmit: func.isRequired,
  expanded: bool,
};

// Component declaration
```

Here, we assign the propTypes before the component declaration, so they are immediately visible. We're able to do this because of JavaScript function hoisting.

#### Destructuring Props and defaultProps

```javascript
import React from "react";

import { observer } from "mobx-react";
import { func, bool } from "prop-types";

import "./styles/Form.css";

ExpandableForm.propTypes = {
  onSubmit: func.isRequired,
  expanded: bool,
  onExpand: func.isRequired,
};

function ExpandableForm(props) {
  const formStyle = props.expanded ? { height: "auto" } : { height: 0 };
  return (
    <form style={formStyle} onSubmit={props.onSubmit}>
      {props.children}
      <button onClick={props.onExpand}>Expand</button>
    </form>
  );
}
```

Our component is a function, which takes its props as its argument. We can expand them like so:

```javascript
import React from "react";

import { observer } from "mobx-react";
import { func, bool } from "prop-types";

import "./styles/Form.css";

ExpandableForm.propTypes = {
  onSubmit: func.isRequired,
  expanded: bool,
  onExpand: func.isRequired,
};

function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
  const formStyle = expanded ? { height: "auto" } : { height: 0 };
  return (
    <form style={formStyle} onSubmit={onSubmit}>
      {children}
      <button onClick={onExpand}>Expand</button>
    </form>
  );
}
```

Note we can also use default arguments to act as defaultProps in a highly readable manner. If expanded is undefined, we set it to false. (A bit of a forced example, since it's a boolean, but very useful for avoiding `Cannot read <property> of undefined` errors with objects).

Avoid the following ES6 syntax:

```javascript
const ExpandableForm = ({ onExpand, expanded, children }) => {
```

Looks very modern, but the function here is actually unnamed.

This lack of name will not be a problem if your Babel is set up correctly — but if it's not, any errors will show up as occurring in `<<anonymous>>` which is terrible for debugging.

Unnamed functions can also cause problems with Jest, a React testing library. Due to the potential for difficult-to-understand bugs (and the lack of real benefit) we recommend using _function_ instead of _const._

#### Wrapping

Since you can't use decorators with functional components, you simply pass it the function in as an argument:

```javascript
import React from "react";

import { observer } from "mobx-react";
import { func, bool } from "prop-types";

import "./styles/Form.css";

ExpandableForm.propTypes = {
  onSubmit: func.isRequired,
  expanded: bool,
  onExpand: func.isRequired,
};

function ExpandableForm({ onExpand, expanded = false, children, onSubmit }) {
  const formStyle = expanded ? { height: "auto" } : { height: 0 };
  return (
    <form style={formStyle} onSubmit={onSubmit}>
      {children}
      <button onClick={onExpand}>Expand</button>
    </form>
  );
}

export default observer(ExpandableForm);
```

Here's our full component:

<Gist id="19d4ade69b1a3978730b104558fb5308" />

### Conditionals in JSX

Chances are you're going to do a lot of conditional rendering. Here's what you want to avoid:

![](https://cdn-images-1.medium.com/max/1600/1*4zdSbYcOXTVchgSJqtk0Ig.png)Actual code I wrote in my early days at MuseFind… forgive me

No, nested ternaries are not a good idea.

There are some libraries that solve this problem ([JSX-Control Statements](https://github.com/AlexGilleran/jsx-control-statements)), but rather than introduce another dependency, we settled on this approach for complex conditions:

![](https://cdn-images-1.medium.com/max/1600/1*IVFlMaSGKqHISJueTC26sw.png)A refactored version of the above.

Use curly braces wrapping an [IIFE](http://stackoverflow.com/questions/8228281/what-is-the-function-construct-in-javascript), and then put your if statements inside, returning whatever you want to render. Note that IIFE's like this can cause a performance hit, but in most cases it will not be significant enough to warrant losing the readability factor.

**Update:** Many commenters have recommended extracting this logic to a subcomponent that conditionally returns different buttons based on props. They're right — splitting up your components as much as possible is always a good call. But keep the IIFE approach in mind as a fallback for quick conditionals.

Also, when you only want to render an element on one condition, instead of doing this…

```javascript
{
  isTrue ? <p>True!</p> : <none />;
}
```

… use short-circuit evaluation:

```javascript
{
  isTrue && <p>True!</p>;
}
```

### Conclusion

Was this article useful? Please click the green heart below, or follow me and our publication for more.

Have any feedback? Leave a comment below.

Thanks for reading!
]]></description>
            <link>https://hungvn.com/blog/our-best-practices-for-writing-react-components</link>
            <guid isPermaLink="true">https://hungvn.com/blog/our-best-practices-for-writing-react-components</guid>
            <pubDate>Sun, 20 Aug 2017 23:06:29 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Nodejs là gì]]></title>
            <description><![CDATA[
Trong bài viết giới thiệu về asynchronous, event-driven và non-blocking I/O, mình có treo tên Nodejs lên trên tiêu đề nhưng thật ra bài viết ấy lại không đả động đến Nodejs được bao nhiêu. Nó chỉ giới thiệu ý nghĩa của các khái niệm trên trong ngữ cảnh mà Nodejs sử dụng. Lần này là một bài viết chân thật về Nodejs. Hãy cùng nhau trả lời một câu hỏi mang tính bản thể luận về Nodejs: Bản chất của Nodejs là gì?

Trong bài viết giới thiệu về asynchronous, event-driven và non-blocking I/O, mình có treo tên Nodejs lên trên tiêu đề nhưng thật ra bài viết ấy lại không đả động đến Nodejs được bao nhiêu. Nó chỉ giới thiệu ý nghĩa của các khái niệm trên trong ngữ cảnh mà Nodejs sử dụng. Lần này là một bài viết chân thật về Nodejs. Hãy cùng nhau trả lời một câu hỏi mang tính bản thể luận về Nodejs: Bản chất của Nodejs là gì?

> Node.js is a JavaScript `runtime` built on Chrome’s V8 JavaScript `Engine`.

JavaScript thì dễ hiểu rồi (Thật ra Chrome cũng dễ hiểu), nhưng còn `Runtime` với `Engine` là gì? Mối quan hệ giữa chúng như thế nào?

`JavaScript Engine` có thể được định nghĩa một cách đơn giản như sau: Một chương trình hoặc thư viện thực thi mã JavaScript, cung cấp các cơ chế khởi tạo object, gọi function,… Có thể đơn giản là một `interpreter` hoặc một `JIT compiler` to bytecode.

Tất nhiên, vì cả bài viết này chỉ nhằm nhiệm vụ trả lời Nodejs là gì, mà biết được JavaScript Engine là gì tức là đã xong 50% vấn đề, nên ta sẽ giải thích lại, một cách phức tạp và dài dòng hơn, bắt đầu từ những khái niệm cơ bản hơn như `Interpreter` và `Compiler`.

# Interpreter và Compiler

- **Interpreter** (của ngôn ngữ A): Một thành phần có chức năng trực tiếp thực thi một đoạn code (được viết bằng ngôn ngữ A). Có thể coi CPU như một interpreter của tập chỉ lệnh tương ứng. Ngày nay, interpreter thường hiểu theo ý nghĩa trực tiếp một chương trình từ source code mà không qua chuyển đổi thành machine code.
- **Compiler**: Dịch từ ngôn ngữ A sang ngôn ngữ B sao cho khi thực thi thu được kết quả tương đương. Thường được sử dụng để dịch source code từ ngôn ngữ bậc cao A sang ngôn ngữ B có bậc thấp hơn dễ dàng `interprete` hơn, và tất nhiên ngôn ngữ dễ interprete nhất là machine code.

Thời gian cần để compile thường không phải là nhỏ, nhất là khi cần tối ưu hoá kết quả. Để giảm thiểu thời gian compile, có một cách (đánh đổi bởi tốc độ thực thi sau khi compile) là không dịch trực tiếp source code ra machine code mà dịch sang một ngôn ngữ trung gian và sử dụng interpreter cho ngôn ngữ trung gian này, thường gọi là `bytecode`, với đặc điểm là thời gian compile từ ngôn ngữ nguồn sang bytecode nhanh hơn sang machine code, tốc độ thực thi nhanh hơn việc trực tiếp interprete source code, mặc dù chậm hơn machine code.

Từ `interpreter` và `bytecode` trong định nghĩa về JavaScript Engine đã rõ ràng, vậy còn `JIT compiler`?

Để có một cái nhìn về `JIT compiler`, chúng ta cần xem xét nó trong một mối quan hệ biện chứng giữa nó và một khái niệm khác: `AOT compiler`.

`Ahead-of-Time` (AOT) và `Just-in-Time` (JIT) compilation: Từ `time` được nhắc đến ở đây là `runtime`. AOT dịch toàn bộ source code trước khi bắt đầu chạy chương trình, JIT thì trái lại compile source code trong thời gian chạy. Triết lý của JIT compilation là thay vì phải chờ compiler dịch toàn bộ source, việc có thể mất nhiều thời gian, ta dịch từng phần mà ta cần dùng trước rồi bắt đầu chạy với chúng ngay lập tức.

Interpreter và compiler có thể kết hợp trở thành `engine` của một ngôn ngữ theo 1 trong 2 cách:

- **AOT kết hợp interpreter:** Source code được compile toàn bộ thành machine code hoặc bytecode trước khi khởi chạy chương trình, sau đó sử dụng một interpreter để thực thi. Ví dụ Python được AOT compiler dịch thành cpython bytecode trong chớp nhoáng và cpython được chạy trên interpreter.
- **JIT kết hợp interpreter:** Thực tế là full compiled code chạy nhanh hơn nhưng tốn nhiều thời gian trước khi bắt đầu chạy, trực tiếp interprete source code thì có thể bắt đầu chạy ngay nhưng tốc độ thực thi chậm. Giải pháp trung hoà là sử dụng interpreter để khởi chạy nhanh chóng source code, rồi dùng JIT compiler để dịch và thay thế source code bằng compiled code sau khi đã dịch xong.

# V8 Engine

`V8` là một open source JavaScript engine viết bằng `C++`, phát triển bởi Google như là một phần trong dự án `Chromium`, phát hành lần đầu cùng với phiên bản đầu tiên của trình duyêt Chrome. V8 compile trực tiếp JavaScript thành `native machine code` thay vì sử dụng interpreting bytecode theo cách truyền thống.

Nodejs được xây dựng lần đầu trên V8 do tốc độ thực thi đáng kinh ngạc so với các JavaScript Engine trước đó, đủ sức đảm đương một hệ thống yêu cầu hiệu năng cao trên `server-side`. Ngày nay thì các Engine của các hãng khác cũng đã bắt kịp V8 rồi, vừa rồi Nodejs cũng đã phát hành một phiên bản sử dụng `Chakra Engine `của Microsoft tại [https://github.com/nodejs/node-chakracore](https://github.com/nodejs/node-chakracore), nhưng có lẽ khi nhắc đến Nodejs thì ta chỉ cần giới thiệu về V8 là đủ.

`V8 Engine` được Google lựa chọn quả thật là một cái tên mang nhiều cảm xúc, gợi lên hình ảnh về những động cơ ô tô mạnh mẽ, sản sinh công suất lớn từ thiết kế 8 xy-lanh sắp xếp hình chữ V mà hiếm khi nào có tổng dung tích dưới 3.0 L, thậm chí lên đến hơn 8.0 L, ví như động cơ của chiếc Audi R8 trong hình dưới.

![19694591288_6fe46defe8_o](http://sotatek.com/wp-content/uploads/2016/11/19694591288_6fe46defe8_o.jpg)

Khá chắc là các kỹ sư của Google cũng rất mê xe, bởi họ tiếp tục đặt tên cho các thành phần trong động cơ V8 của mình là `Crankshaft`, `TuborFan` và `Ignition`, các thành phần kỹ thuật của động cơ đốt trong hiện đại mà chúng ta sẽ bắt gặp trong phần sau của bài viết.

Lan man vậy thôi, bây giờ, ba yếu tố then chốt tạo nên hiệu năng cao của V8 là:

- `Fast Property Access`
- `Dynamic Machine Code Generation`
- `Efficient Garbage Collection`

### Fast Property Access

JavaScript là một `dynamic programming language`, có nghĩa, các `property` có thể được thêm, bớt, thay đổi trong thời gian chạy. Hầu hết các JavaScript Engine sử dụng một cấu trúc dữ liệu dạng `dictionary` để lưu giữ các property trong object, mỗi truy cập đến property yêu cầu một `dictionary dynamic lookup` để tìm ra vị trí của property trong memory, chậm hơn cách truy cập trực tiếp đến property trong các `class-based` language truyền thống.

Để tránh dynamic lookup, V8 tự động ngầm tạo một `hidden class` cho mỗi object, biến object trong JavaScript thành class-based. Mỗi khi object được thêm property, V8 `tạo mới` một hidden class và object chuyển hidden class của nó sang class mới này.

![map_trans_c](http://sotatek.com/wp-content/uploads/2016/11/map_trans_c.png)

_Nguồn ảnh: v8project.blogspot.com_

Kể từ khi object trong JavaScript trở thành class-based, một kỹ thuật compiler optimization kinh điển trở nên khả thi và được đưa vào V8, `Inline Caching`, giúp tăng lực cho JavaScript lên thậm chí vài chục lần với long runtime.

### Dynamic Machine Code Generation

V8 dịch trực tiếp JavaScript source code sang native machine code, cho tốc độ interprete cao, đồng thời có khả năng linh động `tối ưu hoá` (và tái tối ưu) compiled code trong thời gian chạy dựa trên các dữ liệu thu thập được từ profiler.

V8 có 2 compiler, ban đầu, tất cả source code của bạn sẽ được phân tích cú pháp, chuyển thành `AST` rồi đẩy vào `Full-Codegen Compiler`, nơi sẽ cho ra phiên bản machine code đầu tiên của chương trình.

**Full-Codegen Compiler:** Nhiệm vụ là chuyển source code của bạn thành machine code `nhanh nhất` có thể, khỏi optimize gì luôn. Nó cũng thêm vào một ít `type-feedback code` thu thập thông tin để phục vụ công việc optimize code sau này. Compiler không tiến hành bất cứ phân tích và không biết gì về kiểu dữ liệu trong source code tại thời điểm này.

Để gia tăng hiệu năng, V8 tiếp tục theo dõi chương trình trong runtime bằng một `profiler`, một thành phần trong kiến trúc của V8, sẽ thu thập thông tin và tìm xem function nào là `hot function`, tức được dùng đi dùng lại rất nhiều lần, đó là thời điểm cần tiến hành optimize cho một compiled code tốt hơn. Và đó là thời điểm `Crankshaft` vào cuộc.

**Optimizing compiler:** `Crankshaft` (và mới đây là `TuborFan` được thêm vào) đưa ra những dự đoán về function dựa vào những thông tin thu được từ profiler, re-compile và thay thế phần code chưa được optimize bằng cách sử dụng `on-stack replacement` (OSR).

Nếu những giả định là sai lầm, ví dụ nó cho rằng `a`, `b` sẽ luôn là `number` trong phép tính `a + b` ở đâu đó, và sử dụng thẳng phép cộng 2 số ở đây thay vì lần nào cũng phải kiểm tra kiểu và sử dụng `+` operator thích hợp, mà bất chợt `b` lại nhận kiểu là `string`, thì nó chỉ đơn giản là `de-optimizing` và tái sử dụng phần code chưa optimize.

Đây là cách V8 đối xử với source code của chúng ta:

![ignitionpipeline](http://sotatek.com/wp-content/uploads/2016/11/ignitionpipeline.png)

_Nguồn ảnh: v8project.blogspot.com_

Trong năm 2016, một interpreter mang tên `Ingition` được thêm vào V8 với mục đích giảm thiểu chiếm dụng bộ nhớ trên những hệ thống có memory nhỏ như Android.

### Efficient Garbage Collection

`Garbage collector` của V8, được quảng cáo là một stop-the-world, generational, accurate, garbage collector làm nhiệm vụ thu hồi memory đối với những object không còn được process sử dụng một cách rất hiệu quả. Còn nó hiệu quả như thế nào, tại sao hay thậm chí nó có thật sự hiệu quả hơn các engine khác hay không thì mình cũng không rõ.

Ban đầu, JavaScript được thiết kế để thực hiện một số nhiệm vụ nhỏ nhoi và ngắn ngủi, ví dụ như đặt một `event listener` cho một element trên browser, engine lúc ấy chỉ đơn giản là một interpreter đọc và thực thi JavaScript source code. Dần dần, theo thời gian, chúng ta yêu cầu nhiều hơn từ nó.

Ứng dụng đầu tiên giao phó những nhiệm vụ nặng nề cho JavaScript là `Google Map`. Từ đây người ta nhận ra sự cần thiết của một JavaScript nhanh hơn, trong một runtime dài hơi hơn.

JIT compilation cần nhiều thời gian để khởi tạo hơn interpretation, nhưng nhanh hơn rất nhiều trong runtime dài. Với những web application dùng nhiều JavaScript của mình, Google đã dành nhiều công sức để thúc đẩy các trình duyệt cải thiện hiệu suất của JavaScript, và V8 ra đời như một kết quả.

Giờ đây, một process JavaScript chạy càng lâu, càng được optimize và càng sở hữu hiệu năng cao hơn, mọi người cảm thấy nó đã khả thi để xuất hiện trong một môi trường khắc nghiệt hơn là trên web browser, `server-side`.

# JavaScript Runtime

Được giới thiệu là một JavaScript `Runtime`, Nodejs có gì khác biệt với một JavaScript `Engine`? Lấy cảm hứng từ một câu trả lời trên Stackoverflow, chúng ta có thể tạm hiểu như sau:

JavaScript chạy trên một `container` – một chương trình sẽ nhận source code của bạn và thực thi nó. Chương trình này làm hai điều:

- Phân thích source code và thực thi từng đơn vị có thể.
- Cung cấp một vài object để JavaScript có thể tương tác với thế giới bên ngoài.

Phần đầu, gọi là `Engine`. Phần còn lại, gọi là `Runtime`.

Trên thực tế, V8 implement một `ECMAScript` theo đúng chuẩn, tức là những gì ngoài chuẩn thì không có mặt trong V8.

Để tương tác với môi trường, V8 cung cấp các lớp `template` bọc ngoài các object và function viết bởi `C++`. Các C++ function này có thể làm nhiệm vụ đọc/ghi file system, thao tác networking hoặc giao tiếp với các process khác trong hệ thống. Bằng cách thiết lập một `JavaScript context` với `global scope` chứa các `JavaScript instance` tạo ra từ các template và chạy source code của chúng ta trong context này, mã của chúng ta đã sẵn sàng để giao tiếp với thế giới.

Và đó là nhiệm vụ của một `Runtime Library`: Tạo ra một runtime environment cung cấp các thư viện `built-in` dưới dạng các biến global để mã của bạn có thể sử dụng trong thời gian chạy, đón nhận source code như là một `argument` và thực thi nó trong context đã tạo.

Với `browser runtime environment` như Chrome, context mà Chrome cung cấp cho V8 bao gồm các biến global như `window`, `console`, `DOM object`, `XMLHttpRequest` và timer `setTimeout()`.

Tất cả những thứ ấy đến từ Chrome, không phải từ bản thân V8. Thay vào đó, V8 cung cấp các built-in object chuẩn, có mặt trong mọi environment của JavaScript, được miêu tả trong `ECMAScript Standard`, bao gồm các kiểu dữ liệu, operator, một số object và function đặc biệt như các value property (`Infinity`, `NaN`, `null`, `undefined`), `Object`, `Function`, `Boolean`, `String`, `Number`, `Map`, `Set`, `Array`, `parseInt()`, `eval()`,…

Rời xa thế giới browser, rời xa DOM, Nodejs mang đến cho chúng ta nhiều built-in library hơn như `fs` để giao tiếp với file system, `http` và `https` cho networking, `tls`, `tty`, `cluster`, `os`,… Vấn đề là không phải lúc nào ta cũng cần tất cả những thứ này, việc tạo một context mang quá nhiều global variable không cần thiết như vậy rõ ràng không phải là một cách làm hay.

Nodejs bởi vậy nhóm nhiều chức năng vào các module khác nhau và thực hiện một cơ chế `module loading` thông qua từ khoá `require` và `exports`, cho phép tạo ra những context linh động hơn. Tất nhiên, cơ chế này được implement bằng C/C++.

Đó là diễn giải đằng sau lời giới thiệu runtime built on Chrome’s V8 JavaScript Engine của Nodejs, và đó là cách mã JavaScript của bạn thao tác với các `low-level API`, theo một cách `đồng bộ` (synchronous). V8 chạy mã của bạn trong một single thread, tuần tự từng lệnh một, sử dụng một cấu trúc để quản lý các active subroutine gọi là `call stack`.

# Call Stack và Event Loop

Call stack không phải là một điều gì đó mới mẻ, thực tế chúng ta luôn luôn phải sử dụng nó để đảm bảm chương trình thực thi một cách đúng đắn, chẳng qua trong các ngôn ngữ bậc cao, việc cung cấp một call stack được ẩn đi và tự động hoá. Nếu push quá nhiều stack frame vào và tiêu tốn hết không gian được cấp cho call stack, chúng ta sẽ đối diện với `Stackoverflow` huyền thoại.

Câu chuyện về call stack của JavaScript có lẽ chúng ta đều đã được nghe kể rất nhiều lần. Ta đều biết rằng stack frame được push mỗi khi một hàm được gọi, và được pop với lệnh return. Sau khi lần lượt xử lý hết các lệnh trong chương trình, call stack trở nên rỗng ruột, một phép màu mang tên `event loop` sẽ nhặt các hàm callback trong một tạo vật gọi là `event queue` (hay task queue), đẩy vào trong call stack, và V8 engine tiếp tục thực thi hàm đang nằm trong call stack này.

Đây là cách JavaScript thực hiện `asynchronous call`. Đây cũng là lý do tại sao gọi timer `setTimeout()` với đối số là 0, hàm callback của chúng ta vẫn phải chờ cho đến khi tất cả code trong chương trình thực thi xong (call stack trở thành empty) thì mới được invoke.

![Event-loop](http://sotatek.com/wp-content/uploads/2016/11/Event-loop.png)

_Nguồn ảnh: appsdev.is.ed.ac.uk_

V8 nhận event loop như là một đối số đầu vào khi khởi tạo environment, các môi trường khác nhau sẽ có event loop và API để tạo `asynchronous request`, thứ mà sẽ đẩy `callback function` của ta vào trong event queue rồi vật vờ ngồi đợi, của riêng mình.

Với Nodejs, event loop implementation của nó là `libuv`. Thiếu đi libuv, bức tranh về một Nodejs event-driven asynchronous non-blocking I/O sẽ không thể hoàn thiện. V8 thì thậm chí còn chẳng biết I/O là cái gì chứ đừng nói đến blocking hay không blocking.

Về libuv và cách nó hoạt động lại là một câu chuyện dài mà thời lượng ở đây không cho phép mình giới thiệu. Xin hẹn được chia sẻ về nó trong một bài viết khác, mà chính xác ra thì là bài viết này:

[http://sotatek.com/nodejs-hieu-asynchronous-event-drivent-nonblocking-io/](http://sotatek.com/nodejs-hieu-asynchronous-event-drivent-nonblocking-io/)

# Tổng kết

Đến đây, có lẽ ta đã có thể tự vẽ một bức tranh khá đầy đủ về Nodejs system cho riêng mình. Còn nếu bạn lười vẽ, không sao cả, Richard Key đã vẽ cho bạn rồi đây:

![Bt5ywJrIEAAKJQt](http://sotatek.com/wp-content/uploads/2016/11/Bt5ywJrIEAAKJQt.jpg)

_Nguồn ảnh: twitter.com/BusyRich_
]]></description>
            <link>https://hungvn.com/blog/nodejs-la-gi</link>
            <guid isPermaLink="true">https://hungvn.com/blog/nodejs-la-gi</guid>
            <pubDate>Sun, 20 Aug 2017 22:56:00 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Master the JavaScript Interview]]></title>
            <description><![CDATA[
> “Master the JavaScript Interview” is a series of posts designed to prepare candidates for common questions they are likely to encounter when applying for a mid to senior-level JavaScript position. These are questions I frequently use in real interviews. Want to start from the beginning? See [“What is a Closure?”](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36#.6xq65f6f5)

> Note: This article uses ES6 examples. If you haven’t learned ES6 yet, see [“How to Learn ES6”](https://medium.com/javascript-scene/how-to-learn-es6-47d9a1ac2620).

Objects are frequently used in JavaScript, and understanding how to work with them effectively will be a huge win for your productivity. In fact, poor OO design can potentially lead to project failure, and in the worst cases, [company failures](https://medium.com/javascript-scene/inside-the-dev-team-death-spiral-6a7ea255467b).

Unlike most other languages, JavaScript’s object system is based on **prototypes, not classes**. Unfortunately, most JavaScript developers don’t understand JavaScript’s object system, or how to put it to best use. Others do understand it, but want it to behave more like class based systems. The result is that JavaScript’s object system has a confusing split personality, which means that JavaScript developers need to know a bit about **both prototypes and classes**.

#### What’s the Difference Between Class & Prototypal Inheritance?

This can be a tricky question, and you’ll probably need to defend your answer with follow-up Q&A, so pay special attention to learning the differences, and how to apply the knowledge to write better code.

**Class Inheritance:** **_A class is like a blueprint — a description of the object to be created._** Classes inherit from classes and **create subclass relationships**: hierarchical class taxonomies.

Instances are typically instantiated via constructor functions with the _`new`_ keyword. Class inheritance may or may not use the _`class`_ keyword from ES6\. Classes as you may know them from languages like Java don’t technically exist in JavaScript. Constructor functions are used, instead. The ES6 _`class`_ keyword desugars to a constructor function:

```javascript
class Foo {}
typeof Foo; // 'function'
```

In JavaScript, class inheritance is implemented on top of prototypal inheritance, but _that does not mean that it does the same thing:_

JavaScript’s class inheritance uses the prototype chain to wire the child _`Constructor.prototype`_ to the parent _`Constructor.prototype`_ for delegation. Usually, the _`super()`_ constructor is also called. Those steps form **single-ancestor parent/child hierarchies** and **_create the tightest coupling available in OO design._**

> “Classes inherit from classes and **create subclass relationships**: hierarchical class taxonomies.”

**Prototypal Inheritance:** **_A prototype is a working object instance._** Objects inherit directly from other objects.

Instances may be composed from many different source objects, allowing for easy selective inheritance and a flat [[Prototype]] delegation hierarchy. In other words, **class taxonomies are not an automatic side-effect of prototypal OO**: _a critical distinction._

Instances are typically instantiated via factory functions, object literals, or _`Object.create()`_.

> **_“A prototype is a working object instance._** Objects inherit directly from other objects.”

#### Why Does this Matter?

Inheritance is fundamentally a code reuse mechanism: A way for different kinds of objects to share code. The way that you share code matters because if you get it wrong, **it can create a lot of problems,** specifically:

**Class inheritance creates parent/child object taxonomies as a side-effect**.

Those taxonomies are virtually impossible to get right for all new use cases, and widespread use of a base class leads to **the fragile base class problem,** which makes them difficult to fix when you get them wrong.In fact, class inheritance causes many well known problems in OO design:

- **The tight coupling problem** (class inheritance is the tightest coupling available in oo design), which leads to the next one…
- **The fragile base class problem**
- **Inflexible hierarchy problem** (eventually, all evolving hierarchies are wrong for new uses)
- **The duplication by necessity problem** (due to inflexible hierarchies, new use cases are often shoe-horned in by duplicating, rather than adapting existing code)
- **The Gorilla/banana problem** (What you wanted was a banana, but what you got was a gorilla holding the banana, and the entire jungle)

I discuss some of the issues in more depth in my talk, “Classical Inheritance is Obsolete: How to Think in Prototypal OO”:

<YouTube id="lKCCZTUx0sI" />

The solution to all of these problems is to favor object composition over class inheritance.

> “Favor object composition over class inheritance.”
> ~ The Gang of Four, [“Design Patterns: Elements of Reusable Object Oriented Software”](http://www.amazon.com/gp/product/0201633612?ie=UTF8&camp=213733&creative=393185&creativeASIN=0201633612&linkCode=shr&tag=eejs-20&linkId=WMUILDJNIUXY4NSH)

Summed up nicely here:

<YouTube id="wfMtDGfHWpA" />

#### Is All Inheritance Bad?

When people say “favor composition over inheritance” that is short for “favor composition over **class** inheritance” (the original quote from “Design Patterns” by the Gang of Four). This is common knowledge in OO design because **class inheritance has many flaws** and causes many problems. Often people leave off the word **class** when they talk about class inheritance, which makes it sound like _all inheritance_ is bad — but it’s not.

There are actually several different kinds of inheritance, and most of them are great.

#### Three Different Kinds of Prototypal Inheritance

Before we dive into the other kinds of inheritance, let’s take a closer look at what I mean by **class inheritance**:

<Gist id="b668ce0ad1ab540df915" />

You can [experiment with this example on Codepen](http://codepen.io/ericelliott/pen/pgdPOb?editors=001).

_`BassAmp`_ inherits from _`GuitarAmp`_, and _`ChannelStrip`_ inherits from _`BassAmp`_ & _`GuitarAmp`._ This is an example of how OO design goes wrong. A channel strip isn’t actually a type of guitar amp, and doesn’t actually need a cabinet at all. A better option would be to create a new base class that both the amps and the channel strip inherits from, but even that has limitations.

Eventually, the new shared base class strategy breaks down, too.

There’s a better way. You can inherit just the stuff you really need using object composition:

<Gist id="fed0fd7a0d3388b06402" />

[Experiment with this on CodePen](http://codepen.io/ericelliott/pen/XXzadQ?editors=001).

If you look carefully, you might see that we’re being much more specific about which objects get which properties because with composition, **_we can_**. It wasn’t really an option with class inheritance. When you inherit from a class, you get everything, _even if you don’t want it._

At this point, you may be thinking to yourself, “that’s nice, but where are the prototypes?”

To understand that, you have to understand that there are three different kinds of prototypal OO.

**Concatenative inheritance:** The process of inheriting features directly from one object to another by copying the source objects properties. In JavaScript, source prototypes are commonly referred to as **mixins.** Since ES6, this feature has a convenience utility in JavaScript called _`Object.assign()`_. Prior to ES6, this was commonly done with Underscore/Lodash’s _`.extend()`_ jQuery’s _`$.extend()`,_ and so on… The composition example above uses concatenative inheritance.

**Prototype delegation:** In JavaScript, an object may have a link to a prototype for **delegation**. If a property is not found on the object, the lookup is **delegated** to the **delegate prototype,** which may have a link to its own delegate prototype, and so on up the chain until you arrive at _`Object.prototype`_, which is the root delegate. This is the prototype that gets hooked up when you attach to a _`Constructor.prototype`_ and instantiate with _`new`._ You can also use _`Object.create()`_ for this purpose, and even mix this technique with concatenation in order to flatten multiple prototypes to a single delegate, or extend the object instance after creation.

**Functional inheritance:** In JavaScript, any function can create an object. When that function is not a constructor (or _`class`_), it’s called a **factory function**. Functional inheritance works by producing an object from a factory, and extending the produced object by assigning properties to it directly (using concatenative inheritance). Douglas Crockford coined the term, but functional inheritance has been in common use in JavaScript for a long time.

As you’re probably starting to realize, **concatenative inheritance is the secret sauce that enables object composition in JavaScript**, which makes both prototype delegation and functional inheritance a lot more interesting.

When most people think of prototypal OO in JavaScript, _they think of prototype delegation._ By now you should see that they’re missing out on a lot. Delegate prototypes aren’t the great alternative to class inheritance — **object composition is**.

#### **Why Composition is Immune to the Fragile Base Class Problem**

To understand the fragile base class problem and why it doesn’t apply to composition, first you have to understand how it happens:

1.  _`A`_ is the base class
2.  _`B`_ inherits from _`A`_
3.  _`C`_ inherits from _`B`_
4.  _`D`_ inherits from _`B`_

_`C`_ calls _`super`_, which runs code in _`B`_. _`B`_ calls _`super`_ which runs code in _`A`_.

_`A`_ and _`B`_ contain unrelated features needed by both _`C`_ & _`D`_. _`D`_ is a new use case, and needs _slightly different_ behavior in _`A`_’s init code than _`C`_ needs. So the newbie dev goes and tweaks _`A`_’s init code. _`_**_C`_ breaks because it depends on the existing behavior**, and _`D`_ starts working.

What we have here are features spread out between _`A`_ and _`B`_ that _`C`_ and _`D`_ need to use in various ways. _`C`_ and _`D`_ don’t use every feature of _`A`_ and _`B`_… they just want to inherit some stuff that’s already defined in _`A`_ and _`B`_. But by inheriting and calling _`super`,_ **you don’t get to be selective about what you inherit**. You inherit everything:

> “…the problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. **You wanted a banana but what you got was a gorilla holding the banana** and the entire jungle.” ~ Joe Armstrong — [“Coders at Work”](http://www.amazon.com/gp/product/1430219483?ie=UTF8&camp=213733&creative=393185&creativeASIN=1430219483&linkCode=shr&tag=eejs-20&linkId=3MNWRRZU3C4Q4BDN)

**With Composition**
Imagine you have features instead of classes:

```javascript
(feat1, feat2, feat3, feat4);
```

_`C`_ needs _`feat1`_ and _`feat3`_, _`D`_ needs _`feat1`, `feat2`, `feat4`_:

```javascript
const C = compose(feat1, feat3);
const D = compose(feat1, feat2, feat4);
```

Now, imagine you discover that _`D`_ needs **slightly different** behavior from _`feat1`_. It doesn’t actually need to change _`feat1`_, instead, **you can make a customized version of _`feat1`_** and use that, instead. You can still inherit the existing behaviors from _`feat2`_ and _`feat4`_ with no changes:

```javascript
const D = compose(custom1, feat2, feat4);
```

And _`_**_C`_ remains unaffected**.

The reason this is not possible with class inheritance is because **when you use class inheritance, you buy into the whole existing class taxonomy.**

If you want to adapt a little for a new use-case, you either end up duplicating parts of the existing taxonomy (the duplication by necessity problem), or you refactor everything that depends on the existing taxonomy to adapt the taxonomy to the new use case due to **the fragile base class problem**.

Composition is immune to both.

#### You Think You Know Prototypes, but…

If you were taught to build classes or constructor functions and inherit from those, what you were taught was **not prototypal inheritance**. You were taught how to **mimic class inheritance using prototypes**. See [“Common Misconceptions About Inheritance in JavaScript”](https://medium.com/javascript-scene/common-misconceptions-about-inheritance-in-javascript-d5d9bab29b0a#.khem2m91q).

In JavaScript, class inheritance piggybacks on top of the very rich, flexible prototypal inheritance features built into the language a long time ago, but when you use class inheritance — even the ES6+ _`class`_ inheritance built on top of prototypes, you’re not using the full power & flexibility of prototypal OO. In fact, you’re painting yourself into corners and **opting into all of the class inheritance problems**.

> Using class inheritance in JavaScript is like driving your new Tesla Model S to the dealer and trading it in for a rusted out 1983 Ford Pinto.

#### Stamps: Composable Factory Functions

Most of the time, composition is achieved using factory functions: functions which exist to create object instances. What if there was a standard that makes factory functions composable? There is. It’s called [The Stamp Specification](https://github.com/stampit-org/stamp-specification).

#### Explore the Series

- [What is a Closure?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-closure-b2f0d2152b36#.ecfskj935)
- [What is the Difference Between Class and Prototypal Inheritance?](https://medium.com/javascript-scene/master-the-javascript-interview-what-s-the-difference-between-class-prototypal-inheritance-e4cd0a7562e9#.h96dymht1)
- [What is a Pure Function?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976#.4256pjcfq)
- [What is Function Composition?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-function-composition-20dfb109a1a0#.i84zm53fb)
- [What is Functional Programming?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-functional-programming-7f218c68b3a0#.jddz30xy3)
- [What is a Promise?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261#.aa7ubggsy)
- [Soft Skills](https://medium.com/javascript-scene/master-the-javascript-interview-soft-skills-a8a5fb02c466)

---

### Level Up Your Skills with Live 1:1 Mentorship

DevAnywhere is the fastest way to level up to advanced JavaScript skills:

- Live lessons
- Flexible hours
- 1:1 mentorship
- Build real production apps

[![](https://cdn-images-1.medium.com/max/1600/1*pskrI-ZjRX_Y0I0zZqVTcQ.png)](https://devanywhere.io/)[https://devanywhere.io/](https://devanywhere.io/)
]]></description>
            <link>https://hungvn.com/blog/master-the-javascript-interview</link>
            <guid isPermaLink="true">https://hungvn.com/blog/master-the-javascript-interview</guid>
            <pubDate>Sun, 20 Aug 2017 22:36:07 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Giải thích keyword 'new' trong Javascript]]></title>
            <description><![CDATA[
![](https://cdn-images-1.medium.com/max/2000/1*5_r4-hkl9k9ERVyPI56x1Q.png)

#### Normal Function Call

To explain what `new` does, let’s start with just a normal function, called without `new`. We want to write a function that will create “person” objects. It’ll give these objects `name` and `age` properties based on parameters that it takes in.

```javascript
function personFn(name, age) {
  var personObj = {};
  personObj.name = name;
  personObj.age = age;

  return personObj;
}
var alex = personFn("Alex", 30);
// -> { name: 'Alex', age: 30 }
```

Simple enough. We create an object, add the properties to it, and return it at the end.

#### `new`

![](https://cdn-images-1.medium.com/max/1600/1*HFlvxchL2IMFERwQsQClRw.png)Object-oriented programming

Let’s create a function that does the same thing, but we want it to be invoked using `new`. This function will create the same object as the one above. Common practice is to make functions that are meant to be invoked with `new` start with a capital letter. These functions are also referred to as **constructors**.

```javascript
function PersonConstructor(name, age) {
  this.name = name;
  this.age = age;
}
var alex = new PersonConstructor("Alex", 30);
// -> { name: 'Alex', age: 30 }
```

Invoking `personFn` normally and invoking `PersonConstructor` with `new` both result in the same object being created. What’s going on?

The `new` keyword invokes a function in a special way. It adds some implicit code that we don’t see. Let’s expand the above function to show everything that’s happening. The commented lines are pseudocode representing functionality that is implicitly added by the JS engine when using `new`.

```javascript
function PersonConstructor(name, age) {
  // this = {};
  // this.__proto__ = PersonConstructor.prototype;
  // Set up logic such that: if
  // there is a return statement
  // in the function body that
  // returns anything EXCEPT an
  // object, array, or function:
  //     return 'this' (the newly
  //     constructed object)
  //     instead of that item at
  //     the return statement;
  this.name = name;
  this.age = age;
  // return this;
}
```

Let’s break it down. `new`:

1.  Creates a new object and binds it to the `this` keyword.
2.  Sets the object’s internal [[[Prototype]]](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto), [property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto), [\_\_proto\_\_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto), to be the prototype of the constructing function. This also makes it so the [constructor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor) of the new object is prototypically inherited.
3.  Sets up logic such that if a variable of any type other than `object`, `array`, or `function` is returned in the function body, return `this`, the newly constructed object, instead of what the function says to return.
4.  At the end of the function, returns `this` if there is no return statement in the function body.

Let’s show that these statements are valid, one by one.

```javascript
function Demo() {
  console.log(this);
  this.value = 5;
  return 10;
}
/*1*/ var demo = new Demo(); // -> {}
/*2*/ console.log(demo.__proto__ === Demo.prototype); // -> true
console.log(demo.constructor === Demo); // -> true
/*3*/ console.log(demo); // -> { value: 5 }
function SecondDemo() {
  this.val = "2nd demo";
}
/*4*/ console.log(new SecondDemo()); // -> { val: '2nd demo' }
```

If you aren’t familiar with constructors or prototypes, don’t worry about it too much. You’ll run into them as you continue to learn Javascript. For now, just understand that the new object implicitly returned by the constructor function will be able to inherit properties and methods.

#### Calling a non-constructor with new

What happens if we invoke a normal function like `personFn` using `new`? Nothing special. The same rules apply. in the case of `personFn`, we see nothing explicitly happening.

```javascript
var alex = new personFn("Alex", 30);
// -> { name: 'Alex', age: 30 }
```

Why? Let’s add our implicit code in to `personFn`.

```javascript
function personFn(name, age) {
  // this = {};
  // this.constructor = PersonConstructor;
  // this.__proto__ = PersonConstructor.prototype;
  // Set up logic such that: if
  // there is a return statement
  // in the function body that
  // returns anything EXCEPT an
  // object, array, or function:
  //     return this (the newly
  //     constructed object)
  //     instead of that item at
  //     the return statement;
  var personObj = {};
  personObj.name = name;
  personObj.age = age;

  return personObj;

  // return this;
}
```

The implicit code is still added in:

- It binds `this` to a new object and sets its constructor and prototype.
- It adds logic that will return `this` instead of a non-object.
- It adds an implicit `return this` statement at the end.

This doesn’t affect our code, since we don’t use the `this` keyword in our code. We also explicitly return an object, `personObj`, so the returning logic and the `return this` line have no use. Effectively, using `new` to invoke our function here has no effect on the output. If we were using `this` or if we weren’t returning an object, the function would have different effects when invoked with and without `new`.

#### That’s it. Go write some code.
]]></description>
            <link>https://hungvn.com/blog/giai-thich-keyword-new-trong-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/giai-thich-keyword-new-trong-javascript</guid>
            <pubDate>Sun, 20 Aug 2017 22:21:52 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[A Jade Tutorial for Beginners]]></title>
            <description><![CDATA[
Jade is an elegant templating engine, primarily used for server-side templating in NodeJS. In plain words, Jade gives you a powerful new way to write markup, with a number of **advantages over plain HTML**.

For example, take a look at this movie card in HTML:

```html
<div>
  <h1>Ocean's Eleven</h1>
  <ul>
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
  <p>Danny Ocean and his eleven accomplices plan to rob three Las Vegas casinos simultaneously.</p>
</div>
```

This is what the same markup looks like in Jade:

```pug
div
  h1 Ocean's Eleven
  ul
    li Comedy
    li Thriller
  p.
    Danny Ocean and his eleven accomplices plan to rob
    three Las Vegas casinos simultaneously.
```

The Jade version is elegant and concise. But it’s not just about the beautiful syntax. Jade has some really neat features, allowing you to write modular and reusable markup. Before we get into these powerful features, let’s do a quick overview of the basics.

## The Basics

I’m going to highlight three basic features in Jade

- Simple tags
- Adding attributes to the tags
- Blocks of text

If you want to try this out as we go along, you can use [CodePen](http://codepen.io/) and choose Jade as your HTML preprocessor or use the [online compiler on the official Jade page](http://jade-lang.com/demo/) to compile your Jade to HTML.

## Simple Tags

As you might have noticed earlier, there are no “closing” tags in Jade. Instead, Jade uses indentation (i.e. white space) to determine how tags are nested.

```pug
div
  p Hello!
  p World!
```

In the example above, since the paragraph tags are indented, they will end up inside the `div` tag. Simple!

```html
<div>
  <p>Hello!</p>
  <p>World!</p>
</div>
```

Jade compiles this accurately by treating the first word on each line as a tag, while subsequent words on that line are treated as text inside the tag.

[View this example on CodePen](http://codepen.io/SitePoint/pen/PZLgaN/)

## Attributes

All this is great, but how do we add attributes to our tags? Quite simple really. Let’s go back to our first example and toss in some classes and a poster image.

```pug
div(class="movie-card", id="oceans-11")
  h1(class="movie-title") Ocean's 11
  img(src="/img/oceans-11.png", class="movie-poster")
  ul(class="genre-list")
    li Comedy
    li Thriller
```

Pretty neat right?

```html
<div class="movie-card" id="oceans-11">
  <h1 class="movie-title">Ocean's 11</h1>
  <img src="/img/oceans-11.png" class="movie-poster" />
  <ul class="genre-list">
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
</div>
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/pgYBZd)

But it doesn’t stop here. Jade provides special shorthand for IDs and classes, further simplifying our markup using a familiar notation:

```pug
div.movie-card#oceans-11
  h1.movie-title Ocean's 11
  img.movie-poster(src="/img/oceans-11.png")
  ul.genre-list
    li Comedy
    li Thriller
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/VeRNEZ)

As you can see, Jade uses the same syntax as that which we’re already familiar with when writing CSS selectors, making it even easier to spot classes.

## Blocks of Text

Let’s say you have a paragraph tag and you want to place a large block of text in it. Jade treats the first word of every line as an HTML tag – so what do you do?

You might have noticed an innocent period in the first code example in this article. Adding a period (full stop) after your tag indicates that everything inside that tag is text and Jade stops treating the first word on each line as an HTML tag.

```
div
  p How are you?
  p.
    I'm fine thank you.
    And you? I heard you fell into a lake?
    That's rather unfortunate. I hate it when my shoes get wet.
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/XXGQxP)

And just to drive home the point, if I were to remove the period after the `p` tag in this example, the compiled HTML would treat the “I” in the word “I’m” as an opening tag (in this case, it would be the `<i>` tag).

## Powerful Features

Now that we’ve covered the basics, let’s take a peek at some powerful features that will make your markup smarter. We’ll look at the following features in remainder of this tutorial:

- Loops
- JavaScript
- Interpolation
- Mixins

## Using JavaScript in Jade

Jade is implemented with JavaScript, so it’s super-easy to use JavaScript in Jade. Here’s an example.

```pug
- var x = 5;
div
  ul
    - for (var i=1; i<=x; i++) {
      li Hello
    - }
```

What did we just do here?! By starting a line with a hyphen, we indicate to the Jade compiler that we want to start using JavaScript and it just works as we would expect. Here’s what you get when you compile the Jade code above to HTML:

```html
<div>
  <ul>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
    <li>Hello</li>
  </ul>
</div>
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/eJXoQK)

We use a hyphen when the code doesn’t directly add output. If we want to use JavaScript to output something in Jade, we use `=`. Let’s tweak the code above to show a serial number.

```pug
- var x = 5;
div
  ul
    - for (var i=1; i<=x; i++) {
      li= i + ". Hello"
    - }
```

And voilà, we now have serial numbers:

```html
<div>
  <ul>
    <li>1\. Hello</li>
    <li>2\. Hello</li>
    <li>3\. Hello</li>
    <li>4\. Hello</li>
    <li>5\. Hello</li>
  </ul>
</div>
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/YwgMdz)

Of course, in this case, an ordered list would be much more appropriate, but you get the point. Now, if you’re worried about XSS and HTML escaping, [read the docs for more info](http://jade-lang.com/reference/code/).

## Loops

Jade provides an excellent looping syntax so that you don’t need to resort to JavaScript. Let’s loop over an array:

```pug
- var droids = ["R2D2", "C3PO", "BB8"];
div
  h1 Famous Droids from Star Wars
  for name in droids
    div.card
      h2= name
```

And this will compile as follows:

```html
<div>
  <h1>Famous Droids from Star Wars</h1>
  <div class="card">
    <h2>R2D2</h2>
  </div>
  <div class="card">
    <h2>C3PO</h2>
  </div>
  <div class="card">
    <h2>BB8</h2>
  </div>
</div>
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/ZQPNxZ)

You can iterate over objects and use `while` loops too. [Check out the docs for more](http://jade-lang.com/reference/iteration/).

## Interpolation

It can get annoying to mix JavaScript into text like this `p= "Hi there, " + profileName + ". How are you doing?"`. Does Jade have an elegant solution for this? You bet.

```pug
- var profileName = "Danny Ocean";
div
  p Hi there, #{profileName}. How are you doing?
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/LGaorZ)

Isn’t that neat?

## Mixins

Mixins are like functions. They take parameters as input and give markup as output. Mixins are defined using the `mixin` keyword.

```pug
mixin thumbnail(imageName, caption)
  div.thumbnail
    img(src="/img/#{imageName}.jpg")
    h4.image-caption= caption
```

Once the mixin is defined, you can call the mixin with the `+` syntax.

```pug
+thumbnail("oceans-eleven", "Danny Ocean makes an elevator pitch.")
+thumbnail("pirates", "Introducing Captain Jack Sparrow!")
```

Which will output HTML like this:

```html
<div class="thumbnail">
  <img src="/img/oceans-eleven.jpg" />
  <h4 class="image-caption">Danny Ocean makes an elevator pitch.</h4>
</div>
<div class="thumbnail">
  <img src="/img/pirates.jpg" />
  <h4 class="image-caption">Introducing Captain Jack Sparrow!</h4>
</div>
```

## Putting It All Together

Let’s put together everything we’ve learned so far. Say we have a nice array of movies, with each item containing the movie’s title, the cast (a sub-array), the rating, the genre, a link to the IMDB page and the image path for the movie’s poster. The array will look something like this (white space added for readability):

```javascript
- var movieList = [
  {
    title: "Ocean's Eleven",
    cast: ["Julia Roberts", "George Clooney", "Brad Pitt", "Andy Garcia"],
    genres: ["Comedy", "Thriller"],
    posterImage: "/img/oceans-eleven",
    imdbURL: "http://www.imdb.com/title/tt0240772/",
    rating: 7
  }
  // etc...
];
```

We have 10 movies and we want to build nice movie cards for each of them. Initially, we don’t plan to use the IMDB link. If a movie is rated above 5, we give it a thumbs up, otherwise, we give it a thumbs down. We’ll use all the nice features of Jade to write some modular code to do the following:

1.  Create a mixin for a movie card
    - Iterate through the cast list and display the actors. We’ll do the same with genres.
    - Check the rating and decide whether to display a thumbs up or a thumbs down.
2.  Iterate through the movie list and use the mixin to create one card per movie.

So let’s create the mixin first.

```pug
mixin movie-card(movie)
  div.movie-card
    h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
      each actor in movie.cast
        li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre
```

There’s a lot going on up there, but I’m sure it looks familiar – we’ve covered all this in this tutorial. Now, we just need to use our mixin in a loop:

```pug
for movie in movieList
  +movie-card(movie)
```

That’s it. Is that elegant or what? Here’s the final code.

```pug
- var movieList = [
  {
    title: "Ocean's Eleven",
    cast: ["Julia Roberts", "George Clooney", "Brad Pitt", "Andy Garcia"],
    genres: ["Comedy", "Thriller"],
    posterImage: "/img/oceans-eleven",
    imdbURL: "http://www.imdb.com/title/tt0240772/",
    rating: 9.2
  },
  {
    title: "Pirates of the Caribbean",
    cast: ["Johnny Depp", "Keira Knightley", "Orlando Bloom"],
    genres: ["Adventure", "Comedy"],
    posterImage: "/img/pirates-caribbean",
    imdbURL: "http://www.imdb.com/title/tt0325980/",
    rating: 9.7
  }
];

mixin movie-card(movie)
  div.movie-card
    h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
    each actor in movie.cast
      li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre

for movie in movieList
  +movie-card(movie)
```

And here’s the compiled HTML:

```html
<div class="movie-card">
  <h2 class="movie-title">Ocean's Eleven</h2>
  <img src="/img/oceans-eleven" class="movie-poster" />
  <h3>Cast</h3>
  <ul class="cast">
    <li>Julia Roberts</li>
    <li>George Clooney</li>
    <li>Brad Pitt</li>
    <li>Andy Garcia</li>
  </ul>
  <div class="rating">
    <img src="img/thumbs-up" />
  </div>
  <ul class="genre">
    <li>Comedy</li>
    <li>Thriller</li>
  </ul>
</div>
<div class="movie-card">
  <h2 class="movie-title">Pirates of the Carribean</h2>
  <img src="/img/pirates-caribbean" class="movie-poster" />
  <h3>Cast</h3>
  <ul class="cast">
    <li>Johnny Depp</li>
    <li>Keira Knightley</li>
    <li>Orlando Bloom</li>
  </ul>
  <div class="rating">
    <img src="img/thumbs-up" />
  </div>
  <ul class="genre">
    <li>Adventure</li>
    <li>Comedy</li>
  </ul>
</div>
```

But wait a minute. What if we now want to go to the movie’s IMDB page when we click on a movie’s title? We can add one line: `a(href=movie.imdbURL)` to the mixin.

```pug
mixin movie-card(movie)
  div.movie-card
    a(href=movie.imdbURL)
      h2.movie-title= movie.title
    img.movie-poster(src=movie.posterImage)
    h3 Cast
    ul.cast
    each actor in movie.cast
      li= actor
    div.rating
      if movie.rating > 5
        img(src="img/thumbs-up")
      else
        img(src="img/thumbs-down")
    ul.genre
      each genre in movie.genres
        li= genre
```

[View this example on CodePen](http://codepen.io/SitePoint/pen/Bjbgpv)

## Conclusion

We went from knowing nothing about Jade to building some beautiful modular movie cards. There’s a lot more to Jade, but I’ve glossed over some concepts to keep things simple. So I hope this tutorial piqued your curiosity [to learn more](http://jade-lang.com/reference/).

**Important note: As some of you might already know, [Jade has been renamed to Pug](https://github.com/pugjs/jade/issues/2184) due to a software trademark claim. In the future, articles on Jade will use the new name “Pug” or “PugJS”.**
]]></description>
            <link>https://hungvn.com/blog/a-jade-tutorial-for-beginners</link>
            <guid isPermaLink="true">https://hungvn.com/blog/a-jade-tutorial-for-beginners</guid>
            <pubDate>Sun, 20 Aug 2017 21:57:13 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Reducing CSS bundle size with webpack]]></title>
            <description><![CDATA[
Đầu năm nay tôi đã build 1 ứng dụng tên là [GO2CINEMA](https://go2cinema.com/), 1 ứng dụng nhỏ gọn, nhanh nhẹ, bảo mật, giúp người dùng book vé xem phim ở Anh. Trong thời gian build ứng dụng này, tôi đã bị ám ảnh với việc tối ưu hóa tốc độ render.

Tôi đã giải quyết việc pre-render HTML bằng [usus](https://github.com/gajus/usus). usus sẽ render HTML SPA (Single Page Application) và sử dụng [inline CSS](https://medium.com/@gajus/pre-rendering-spa-for-seo-and-improved-perceived-page-loading-speed-47075aa16d24). Tuy nhiên tôi không thích việc nhét đến 70kB dung lượng vào mỗi tài liệu HTML, nhất là khi phần lớn dung lượng đó là để chứa tên class CSS.

## Google xử lý như thế nào?

Đã bao giờ bạn tò mò về source code của [Google](https://www.google.com/) chưa? Nếu rồi, hẳn bạn sẽ nhận ra tên class CSS chỉ đơn giản là vài ký tự. Bạn có thắc mắc tại sao lại thế không?

![https://cdn-images-1.medium.com/max/800/1*mGuDYFM56iyLi1MgZPC8bw.png](https://cdn-images-1.medium.com/max/800/1*mGuDYFM56iyLi1MgZPC8bw.png)

## Sự thiếu sót của CSS minifier

Có 1 thứ duy nhất minifier không thể làm được: đó là thay đổi tên của selector. Lý do là vì minifier CSS không điều khiển được các HTML output. Trong lúc đó, các CSS name có thể rất dài.

Nếu bạn sử dụng CSS module, CSS module sẽ có xu hướng thêm các tên cho stylesheet, local identifier và các hash ngẫu nhiên. Dạng của tên class sẽ được định nghĩa bởi css-loader [localIdentName](https://github.com/webpack-contrib/css-loader), config như sau: `[name]___[local]___[hash:base64:5`. Do đó, tên class sẽ được sinh ra có dạng giống thế: `.MovieView___movie-title___yvKVV`; trong trường hợp bạn muốn mô tả kĩ hơn, tên class có thể còn dài nữa: `.MovieView___movie-description-with-summary-paragraph___yvKVV`

## Thay đổi tên class CSS ngay thời điểm biên dịch

Nếu bạn sử dụng [webpack](https://webpack.js.org/) và [babel-plugin-react-css-module](https://github.com/gajus/babel-plugin-react-css-modules) thì bạn không cần lo lắng thêm về vấn đề này nữa. Bạn có thể thay đổi tên class ngay thời điểm biên dịch bằng cách sử dụng css-loader [getLocalIdent](https://github.com/webpack-contrib/css-loader) và babel-plugin-react-css-modules [generateScopedName](https://github.com/gajus/babel-plugin-react-css-modules#configuration).

```javascript
const generateScopedName = (localName: string, resourcePath: string) => {
  const componentName = resourcePath.split("/").slice(-2, -1);
  return componentName + "_" + localName;
};
```

Có 1 điều khá tuyệt về `generateScopedName` đó là instance của function này có thể được sử dụng trong quá trình build của babel và webpack.

```javascript
/**
 * @file Webpack configuration.
 */
const path = require("path");

const generateScopedName = (localName, resourcePath) => {
  const componentName = resourcePath.split("/").slice(-2, -1);

  return componentName + "_" + localName;
};

module.exports = {
  module: {
    rules: [
      {
        include: path.resolve(__dirname, "../app"),
        loader: "babel-loader",
        options: {
          babelrc: false,
          extends: path.resolve(__dirname, "../app/webpack.production.babelrc"),
          plugins: [
            [
              "react-css-modules",
              {
                context: common.context,
                filetypes: {
                  ".scss": {
                    syntax: "postcss-scss",
                  },
                },
                generateScopedName,
                webpackHotModuleReloading: false,
              },
            ],
          ],
        },
        test: /\.js$/,
      },
      {
        test: /\.scss$/,
        use: [
          {
            loader: "css-loader",
            options: {
              camelCase: true,
              getLocalIdent: (context, localIdentName, localName) => {
                return generateScopedName(localName, context.resourcePath);
              },
              importLoaders: 1,
              minimize: true,
              modules: true,
            },
          },
          "resolve-url-loader",
        ],
      },
    ],
  },
  output: {
    filename: "[name].[chunkhash].js",
    path: path.join(__dirname, "./.dist"),
    publicPath: "/static/",
  },
  stats: "minimal",
};
```

## Đặt tên ngắn

May mắn rằng `babel-plugin-react-css-modules` và `css-loader` sử dụng cùng 1 logic để sinh ra tên class CSS. Nhờ đó ta có thể thay đổi tên class bất cứ khi nào cần thiết, thậm chí các hash ngẫu nhiên. Cá nhân tôi thì lại muốn tên class ngắn nhất có thể.

Để làm được điều này, tôi sẽ tạo 1 class name index và sử dụng module [incstr](https://github.com/grabantot/incstr) để sinh ra các ID tăng dần cho mỗi bản ghi.

```javascript
const incstr = require("incstr");

const createUniqueIdGenerator = () => {
  const index = {};

  const generateNextId = incstr.idGenerator({
    // Removed "d" letter to avoid accidental "ad" construct.
    // @see https://medium.com/@mbrevda/just-make-sure-ad-isnt-being-used-as-a-class-name-prefix-or-you-might-suffer-the-wrath-of-the-558d65502793
    alphabet: "abcefghijklmnopqrstuvwxyz0123456789",
  });

  return name => {
    if (index[name]) {
      return index[name];
    }

    let nextId;

    do {
      // Class name cannot start with a number.
      nextId = generateNextId();
    } while (/^[0-9]/.test(nextId));

    index[name] = generateNextId();

    return index[name];
  };
};

const uniqueIdGenerator = createUniqueIdGenerator();

const generateScopedName = (localName, resourcePath) => {
  const componentName = resourcePath.split("/").slice(-2, -1);

  return uniqueIdGenerator(componentName) + "_" + uniqueIdGenerator(localName);
};
```

Việc này sẽ đảm bảo được tên class sẽ đủ ngắn và duy nhất trong cả ứng dụng. Bây giờ thay vì là những cái tên dài ngoằng như `.MovieView___movie-title___yvKVV` và `.MovieView___movie-description-with-summary-paragraph___yvKVV`, tên class đã trở thành `.a_a`, `.b_a`.

**_Nhờ đó mà kích thước file bundle css của [GO2CINEMA](https://go2cinema.com/) đã giảm từ 140kB xuống còn 53kB_**.

## Sử dụng Scope Isolation để giảm kích thước file bundle

Có 1 lý do cho việc tôi sử dụng `_` trong tên class, chia tách tên các component với tên các local identifier, điều này rất hữu ích cho quá trình minify.

[csso](https://github.com/css/csso) (CSS minifier) có những thiết lập về [scope](https://github.com/css/csso#scopes). Scope sẽ định nghĩa các danh sách tên class CSS để sử dụng với 1 số markup, ví dụ các selector từ các scope khác nhau sẽ không nối với các element giống nhau. Việc này sẽ giúp cho việc optimize chủ động hơn.

Dưới đây là code sử dụng [csso-webpack-plugin](https://github.com/zoobestik/csso-webpack-plugin) để tiền xử lý file bundle CSS:

```javascript
const getScopes = ast => {
  const scopes = {};

  const getModuleID = className => {
    const tokens = className.split("_")[0];

    if (tokens.length !== 2) {
      return "default";
    }

    return tokens[0];
  };

  csso.syntax.walk(ast, node => {
    if (node.type === "ClassSelector") {
      const moduleId = getModuleID(node.name);

      if (moduleId) {
        if (!scopes[moduleId]) {
          scopes[moduleId] = [];
        }

        if (!scopes[moduleId].includes(node.name)) {
          scopes[moduleId].push(node.name);
        }
      }
    }
  });

  return Object.values(scopes);
};
```

**_Quá trình này tiếp tục giảm kích thước file bundle CSS của [GO2CINEMA](https://go2cinema.com/) từ 53kB còn 47kB._**

## Kết luận

Hẳn sẽ có những ý kiến trái chiều nói rằng việc minify này hoàn toàn có thể dùng thuật toán nén. Với GO2CINEMA, fle bundle CSS sau khi được nén bằng thuật toán [Brotli](https://en.wikipedia.org/wiki/Brotli) thì kích thước của nó chỉ ít hơn 1kB so với cách minify file bundle bỏ-tên-class tôi đã trình bày trên.

Mặt khác, cài đặt quá trình minify có thể xem như là 1 khoản đầu tư dài hạn. Ngoài việc giảm kích thước file cần parse, nó còn có những lợi ích khác nữa, ví dụ như ngăn chặn việc tên class CSS không bị nối với các selector của [blocklist](https://gist.github.com/spyesx/42fe84c0ef757d1c38a4) ad-blocker chẳng hạn.

Bạn có thể xem demo của minification này được sử dụng với các phim trên GO2CINEMA:

- [https://go2cinema.com/movies/wonder-woman-2017-1305237](https://go2cinema.com/movies/wonder-woman-2017-1305237)
- [https://go2cinema.com/venues/odeon-oxford-magdalen-st-1001053](https://go2cinema.com/venues/odeon-oxford-magdalen-st-1001053)
]]></description>
            <link>https://hungvn.com/blog/reducing-css-bundle-size-with-webpack</link>
            <guid isPermaLink="true">https://hungvn.com/blog/reducing-css-bundle-size-with-webpack</guid>
            <pubDate>Sun, 20 Aug 2017 15:41:31 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[How to Create a Reddit Clone Using React and Firebase]]></title>
            <description><![CDATA[
![An inventor placing a FireBase heart into a robot creation](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1500496188eddit_clone_using_Create_React_App_and_FirebaseA.jpg-01.png)

[React](https://facebook.github.io/react/) is an awesome JavaScript library for building user interfaces. Since the publishing of [Create React App](https://github.com/facebookincubator/create-react-app), it has become very easy to scaffold a barebones React application.

In this article, we will be using [Firebase](https://firebase.google.com/) along with Create React App to build an app which will function similar to [Reddit](https://www.reddit.com/). It will allow the user to submit a new link which can then be voted on.

Here’s a [live demo](https://sitepoint-editors.github.io/reddit-clone/) of what we’ll be building.

## Why Firebase?

Using Firebase will make it very easy for us to show real-time data to the user. Once a user votes on a link, the feedback will be instantaneous. Firebase’s Realtime Database will help us in developing this feature. Also, it will help us to understand how to bootstrap a React application with Firebase.

## Why React?

React is particularly known for creating user interfaces using a component architecture. Each component can contain internal [state](https://facebook.github.io/react/docs/state-and-lifecycle.html) or be passed data as [props](https://facebook.github.io/react/docs/components-and-props.html). State and props are the two most important concepts in React. These two things help us determine the state of our application at any point in time. If you are not familiar with these terms, please head over to the [React docs](https://facebook.github.io/react/docs/hello-world.html) first.

> **Note:** You can also use a state container like [Redux](http://redux.js.org/) or [MobX](https://mobx.js.org/), but for the sake of simplicity, we won’t be using one for this tutorial.

The whole project is [available on Github](https://github.com/sitepoint-editors/reddit-clone).

By the way, for a high-quality, in-depth introduction to React, you can’t go past Canadian full-stack developer Wes Bos. [Try his course](https://ReactForBeginners.com/friend/SITEPOINT), and use the coupon code ‘SITEPOINT’ to get 25% off and to help support SitePoint.

## Setting up the project

Let’s walk through the steps to set up our project structure and any necessary dependencies.

### Installing create-react-app

If you haven’t already, you need to install **create-react-app**. To do so, you can type the following in your terminal:

```javascript
npm install -g create-react-app

```

Once you’ve installed it globally, you can use it to scaffold a React project inside any folder.

Now, let’s create a new app and call it **reddit-clone**.

```javascript
create-react-app reddit-clone

```

This will scaffold a new **create-react-app** project inside the **reddit-clone** folder. Once the bootstrapping is done, we can go inside **reddit-clone** directory and fire up the development server:

```javascript
npm start

```

At this point, you can go to [http://localhost:3000/](http://localhost:3000/) and see your app skeleton up and running.

### Structuring the app

For maintenance, I always like to separate my **containers** and **components**. Containers are the smart components which are contains the business logic of our application and manage Ajax requests. Components are simply dumb presentational components. They can have their own internal state which can be used to control the logic of that component (e.g. showing the current state of a [controlled](https://facebook.github.io/react/docs/forms.html#controlled-components) input component).

After removing the unnecessary logo and css files, this is how your app should look like now. We created a **components** folder and a **containers** folder. Let’s move _App.js_ inside the **containers/App** folder and create _registerServiceWorker.js_ inside the **utils** folder.

![Structuring the app](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1496945149structuring-the-app.png)

Your **src/containers/App/index.js** file should look like this:

```javascript
// src/containers/App/index.js
import React, { Component } from "react";

class App extends Component {
  render() {
    return <div className="App">Hello World</div>;
  }
}

export default App;
```

Your **src/index.js** file should look like this:

```javascript
// src/index.js
import React from "react";

import ReactDOM from "react-dom";

import App from "./containers/App";
import registerServiceWorker from "./utils/registerServiceWorker";

ReactDOM.render(<App />, document.getElementById("root"));
registerServiceWorker();
```

Go to your browser and if every thing works fine you will see **Hello World** on your screen.

You can check my [commit](https://github.com/sitepoint-editors/reddit-clone/commit/0653c7477298aa4a2b341397b28904f03abacfc6) on Github.

### Adding react-router

[React-router](https://github.com/ReactTraining/react-router) will help us define the routes for our app. It’s very customizable and very popular in the react ecosystem.

We will be using version **3.0.0** of **react-router**.

```javascript
npm install --save react-router@3.0.0

```

Now, add a new file _routes.js_ inside the _src_ folder with the following code:

```javascript
// routes.js
import React from "react";

import { Router, Route } from "react-router";

import App from "./containers/App";

const Routes = props => (
  <Router {...props}>
    <Route path="/" component={App}></Route>
  </Router>
);

export default Routes;
```

The `Router` component wraps all the `Route` components. Based on the `path` prop of the `Route` component, the component passed to the `component` prop, will be rendered on the page. Here, we are setting up the root URL (`/`) to load our `App` component using the `Router` component.

```
<Router {...props}>
  <Route path="/" component={ <div>Hello World!</div> }>
  </Route>
</Router>

```

The above code is also valid. For the path `/`, the `<div>Hello World!</div>` will be mounted.

Now, we need to call our **routes.js** file from our **src/index.js** file. The file should have the following content:

```javascript
// src/index.js
import React from "react";

import ReactDOM from "react-dom";
import { browserHistory } from "react-router";

import App from "./containers/App";
import Routes from "./routes";
import registerServiceWorker from "./utils/registerServiceWorker";

ReactDOM.render(<Routes history={browserHistory} />, document.getElementById("root"));

registerServiceWorker();
```

Basically, we are mounting our `Router` component from our **routes.js** file. We pass in the `history` prop to it so that the routes know how to handle [history tracking](https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/history.md#history).

You can check my [commit](https://github.com/sitepoint-editors/reddit-clone/commit/80929148bc71d1e16e7fde09fd34469bce142113) on Github.

### Adding Firebase

If you don’t have a [Firebase](https://firebase.google.com/) account, create one now (it’s free!) by going to their website. After you’re done creating a new account, log into your account and go to the [console](https://console.firebase.google.com/) page and click on **Add project**.

Enter the name of your project (I’ll call mine **reddit-clone**), choose your country, and click on the **Create project** button.

Now, before we proceed we need to change the **rules** for the database since, by default, Firebase expects the user to be authenticated to be able to read and write data. If you select your project and click on the **Database** tab on the left, you will be able to see your database. You need to click on the **Rules** tab on the top that will redirect us to a screen which will have the following data:

```json
{
  "rules": {
    ".read": "auth != null",
    ".write": "auth != null"
  }
}
```

We need to change this to the following:

```json
{
  "rules": {
    ".read": "auth === null",
    ".write": "auth === null"
  }
}
```

This will let users update the database without logging in. If we implemented a flow in which we had authentication before making updates to the database, then we would need the default rules provided by Firebase. To keep this application simple, we _won’t_ be doing authentication.

> **Important:** If you don’t make this modification, Firebase won’t let you update the database from your app.

Now, let’s add the `firebase` npm module to our app by running the following code:

```javascript
npm install --save firebase

```

Next, import that module in your **App/index.js** file as:

```javascript
// App/index.js
import * as firebase from "firebase";
```

When we select our project after logging into Firebase, we will get an option **Add Firebase to your web app**.

![Add Firebase to your web app](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1497022354Screen-Shot-2017-06-09-at-21.04.10.png)

If we click on that option, a modal will appear which will show us the **config** variable which we will use in our `componentWillMount` method.

![Configs](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1497022441Screen-Shot-2017-06-09-at-21.06.23.png)

Let’s create the Firebase config file. We shall call this file **firebase-config.js** and this file will contain all the configs necessary to connect our app with Firebase.

```javascript
// App/firebase-config.js

export default {
  apiKey: "AIzaSyBRExKF0cHylh_wFLcd8Vxugj0UQRpq8oc",
  authDomain: "reddit-clone-53da5.firebaseapp.com",
  databaseURL: "https://reddit-clone-53da5.firebaseio.com",
  projectId: "reddit-clone-53da5",
  storageBucket: "reddit-clone-53da5.appspot.com",
  messagingSenderId: "490290211297",
};
```

We’ll import our Firebase config into **App/index.js**.

```javascript
// App/index.js
import config from "./firebase-config";
```

We will initialize our Firebase database connection in the `constructor`.

```javascript
// App/index.js

constructor() {
  super();

  // Initialize Firebase
  firebase.initializeApp(config);
}

```

In the `componentWillMount()` lifecycle hook, we use the package `firebase` we just installed and call its `initializeApp` method and passed the `config` variable to it. This object contains all the data about our app. The `initializeApp` method will connect our application to our Firebase database so that we can read and write data.

Let’s add some data to Firebase to check if our configuration is correct. Go to the _Database_ tab and add the following structure to your database:

![Test data](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1496945151test-data.png)

Clicking on _Add_ will save the data to our database.

![Demo data](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1496945145demo-data.png)

Now, let’s add some code to our **componentWillMount** method to make the data appear on our screen.

```javascript
// App/index.js

componentWillMount() {
    ...

    let postsRef = firebase.database().ref('posts');

    let _this = this;

    postsRef.on('value', function(snapshot) {
      console.log(snapshot.val());

      _this.setState({
        posts: snapshot.val(),
        loading: false
      });
    });
  }

```

`firebase.database()` gives us a reference to the database service. Using `ref()`, we can get a specific reference from the database. For example, if we call `ref('posts')`, we will be getting the `posts` reference from our database and storing that reference in `postsRef`.

`postsRef.on('value', ...)` gives us the updated value whenever there is any change in the database. This is very useful when we need a real-time update to our user interface based on any database events.

Using `postsRef.once('value', ...)` will only give us the data once. This is useful for data that only needs to be loaded once and isn’t expected to change frequently or require active listening.

After we get the updated value in our `on()` callback, we store the values in our `posts` state.

Now, we will see the data appearing on our console.

![Sample data](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1496945147sample-data.png)

Also, we will be passing this data down to our children. So, we need to modify the `render` function of our **App/index.js** file:

```javascript
// App/index.js

render() {
  return (
    <div className="App">
      {this.props.children && React.cloneElement(this.props.children, {
        firebaseRef: firebase.database().ref('posts'),
        posts: this.state.posts,
        loading: this.state.loading
      })}
    </div>
  );
}

```

This main objective here is to make the posts data available in all our children components which will be passed through `react-router`.

We are checking if `this.props.children` exists or not and if it exists we clone that element and pass all our props to all our children. This is a very efficient way of passing props to dynamic children.

Calling [cloneElement](https://facebook.github.io/react/docs/react-api.html#cloneelement) will shallowly merge the already existing props in `this.props.children` and the props, we passed here (firebaseRef, posts and loading).

Using this technique, the `firebaseRef`, `posts` and `loading` props will be available to all routes.

You can check my [commit](https://github.com/sitepoint-editors/reddit-clone/commit/2c09fc56e503027f5c4a98306816752cee18b48c) on Github.

## Connecting The App With Firebase

Firebase can only store data as objects; [it doesn’t have any native support for arrays](https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html). We will store the data in the following format:

![Database structure](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/06/1496945143database-structure.png)

Add the data in the screenshot above manually so that you can test your views.

### Add views for all the posts

Now, we will add views to show all the posts. Create a file **src/containers/Posts/index.js** with the following content:

```javascript
// src/containers/Posts/index.js
import React, { Component } from "react";

class Posts extends Component {
  render() {
    if (this.props.loading) {
      return <div>Loading...</div>;
    }

    return (
      <div className="Posts">
        {this.props.posts.map(post => {
          return <div>{post.title}</div>;
        })}
      </div>
    );
  }
}

export default Posts;
```

Here, we are just mapping over the data and rendering it to the user interface.

Next, we need to add this to our **routes.js** file.

```javascript
// routes.js

...
<Router {...props}>
  <Route path="/" component={ App }>
    <Route path="/posts" component={ Posts } />
  </Route>
</Router>
...

```

This is because we want the posts to show up only on the **/posts** route. So, we just pass the `Posts` component to the `component` prop and `/posts` to the `path` prop of the `Route` component of react-router.

If we go to the URL [localhost:3000/posts](http://localhost:3000/posts), we will see the posts from our Firebase database.

You can check my [commit](https://github.com/sitepoint-editors/reddit-clone/commit/40591cc8e36f5e65ae477d12307dd7c0d600a38b) on Github.

### Add views to write a new post

Now, let’s create a view from where we can add a new post. Create a file **src/containers/AddPost/index.js** with the following content:

```javascript
// src/containers/AddPost/index.js
import React, { Component } from "react";

class AddPost extends Component {
  constructor() {
    super();

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  state = {
    title: "",
  };

  handleChange = e => {
    this.setState({
      title: e.target.value,
    });
  };

  handleSubmit = e => {
    e.preventDefault();

    this.props.firebaseRef.push({
      title: this.state.title,
    });

    this.setState({
      title: "",
    });
  };

  render() {
    return (
      <div className="AddPost">
        <input
          type="text"
          placeholder="Write the title of your post"
          onChange={this.handleChange}
          value={this.state.title}
        />
        <button type="submit" onClick={this.handleSubmit}>
          Submit
        </button>
      </div>
    );
  }
}

export default AddPost;
```

Here, the `handleChange` method updates our state with the value present in the input box. Now, when we click on the button, the `handleSubmit` method is triggered. The `handleSubmit` method is responsible for making the API request to write to our database. We do it using the `firebaseRef` prop which we passed to all the children.

```javascript
this.props.firebaseRef.push({
  title: this.state.title,
});
```

The above block of code sets the current value of the title to our database.

After the new post has been stored in the database, we make the input box empty again ready to add a new post.

Now, we need to add this page to our routes.

```javascript
// routes.js
import React from "react";

import { Router, Route } from "react-router";

import AddPost from "./containers/AddPost";
import App from "./containers/App";
import Posts from "./containers/Posts";

const Routes = props => (
  <Router {...props}>
    <Route path="/" component={App}>
      <Route path="/posts" component={Posts} />
      <Route path="/add-post" component={AddPost} />
    </Route>
  </Router>
);

export default Routes;
```

Here, we just added the **/add-post** route so that we can add a new post from that route. Hence, we passed the `AddPost` component to its component prop.

Also, let’s modify the `render` method of our **src/containers/Posts/index.js** file so that it can iterate over objects instead of arrays (since Firebase doesn’t store arrays).

```javascript
// src/containers/Posts/index.js

render() {
    let posts = this.props.posts;

    if (this.props.loading) {
      return (
        <div>
          Loading...
        </div>
      );
    }

    return (
      <div className="Posts">
        { Object.keys(posts).map(function(key) {
            return (
              <div key={key}>
                { posts[key].title }
              </div>
            );
        })}
      </div>
    );
  }

```

Now, if we go to [localhost:3000/add-post](http://localhost:3000/add-post), we can add a new post. After clicking on the _submit_ button, the new post will appear immediately on the [posts page](http://localhost:3000/posts).

You can check my [commit](https://github.com/sitepoint-editors/reddit-clone/commit/c83e09b46989a7fb9ec8d40d8fdadd570fb2eaec) on Github.

### Implement voting

Now, we need to allow users to vote on a post. For that, let’s modify the `render` method of our **src/containers/App/index.js**.

```javascript
// src/containers/App/index.js

render() {
  return (
    <div className="App">
      {this.props.children && React.cloneElement(this.props.children, {
        // https://github.com/ReactTraining/react-router/blob/v3/examples/passing-props-to-children/app.js#L56-L58
        firebase: firebase.database(),
        posts: this.state.posts,
        loading: this.state.loading
      })}
    </div>
  );
}

```

We changed the `firebase` prop from `firebaseRef: firebase.database().ref('posts')` to `firebase: firebase.database()` because we will be using Firebase’s [`set`](https://firebase.google.com/docs/database/web/read-and-write) method to update our voting count. In this way, if we had more Firebase refs, it would be very easy for us to handle them by using only the `firebase` prop.

Before proceeding with the voting, let’s modify the `handleSubmit` method in our **src/containers/AddPost/index.js** file a little bit:

```javascript
// src/containers/AddPost/index.js

handleSubmit = (e) => {
  ...
  this.props.firebase.ref('posts').push({
    title: this.state.title,
    upvote: 0,
    downvote: 0
  });
  ...
}

```

We renamed our `firebaseRef` prop to `firebase` prop. So, we change the `this.props.firebaseRef.push` to `this.props.firebase.ref('posts').push`.

Now, we need to modify our **src/containers/Posts/index.js** file to accomodate the voting.

The `render` method should be modified to:

```javascript
// src/containers/Posts/index.js

render() {
  let posts = this.props.posts;
  let _this = this;

  if (!posts) {
    return false;
  }

  if (this.props.loading) {
    return (
      <div>
        Loading...
      </div>
    );
  }

  return (
    <div className="Posts">
      { Object.keys(posts).map(function(key) {
          return (
            <div key={key}>
              <div>Title: { posts[key].title }</div>
              <div>Upvotes: { posts[key].upvote }</div>
              <div>Downvotes: { posts[key].downvote }</div>
              <div>
                <button
                  onClick={ _this.handleUpvote.bind(this, posts[key], key) }
                  type="button"
                >
                  Upvote
                </button>
                <button
                  onClick={ _this.handleDownvote.bind(this, posts[key], key) }
                  type="button"
                >
                  Downvote
                </button>
              </div>
            </div>
          );
      })}
    </div>
  );
}

```

When the buttons are clicked, the **upvote** or **downvote** count will be incremented in our Firebase DB. To handle that logic, we create two more methods: `handleUpvote()` and `handleDownvote()`:

```javascript
// src/containers/Posts/index.js

handleUpvote = (post, key) => {
  this.props.firebase.ref("posts/" + key).set({
    title: post.title,
    upvote: post.upvote + 1,
    downvote: post.downvote,
  });
};

handleDownvote = (post, key) => {
  this.props.firebase.ref("posts/" + key).set({
    title: post.title,
    upvote: post.upvote,
    downvote: post.downvote + 1,
  });
};
```

In these two methods, whenever a user clicks on either of the buttons, the respective count is incremented in the database and is instantly updated in the browser.

If we open two tabs with [localhost:3000/posts](http://localhost:3000/posts) and click on the voting buttons of the posts, we will see each of the tabs get updated almost instantly. This is the magic of using a real-time database like Firebase.

You can check my [commit](https://github.com/sitepoint-editors/reddit-clone/commit/54a15d22b5e18771ea6084ae70575e0fc47ed016) on Github.

In the [repository](https://github.com/sitepoint-editors/reddit-clone), I’ve added the **/posts** route to the `IndexRoute` of the application just to show the posts on [localhost:3000](http://localhost:3000/) by default. You can check that [commit](https://github.com/sitepoint-editors/reddit-clone/commit/7c621a212fe47036248c3317dedb1eb5788dce71) on Github.

## Conclusion

The end result is admittedly a bit barebones, as we didn’t try to implement any design (although [the demo](https://sitepoint-editors.github.io/reddit-clone/) has some basic styles added). We also didn’t add any authentication in order to reduce the complexity and the length of the tutorial, but obviously any real-world application would require it.

Firebase is really useful for places where you don’t want to create and maintain a separate backend application or where you want real-time data without investing too much time developing your APIs. It plays really well with React, as you can hopefully see from the article.
]]></description>
            <link>https://hungvn.com/blog/how-to-create-a-reddit-clone-using-react-and-firebase</link>
            <guid isPermaLink="true">https://hungvn.com/blog/how-to-create-a-reddit-clone-using-react-and-firebase</guid>
            <pubDate>Sun, 23 Jul 2017 16:48:27 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Using MySQL with Node.js & the mysql JavaScript Client]]></title>
            <description><![CDATA[
NoSQL databases are all the rage these days and probably the preferred back-end for Node.js applications. But you shouldn’t architect your next project based on what’s hip and trendy, rather the type of database to be used should depend on the project’s requirements. If your project involves dynamic table creation, real time inserts etc. then NoSQL is the way to go, but on the other hand, if your project deals with complex queries and transactions, then a SQL database makes much more sense.

In this tutorial, we’ll have a look at getting started with the [mysql module](https://github.com/felixge/node-mysql) — a Node.js driver for MySQL, written in JavaScript. I’ll explain how to use the module to connect to a MySQL database, perform the usual CRUD operations, before examining stored procedures and escaping user input.

> This popular tutorial was updated on **11.07.2017**. Changes include updating to ES6 syntax, addressing the fact that the node-mysql module was renamed, adding more beginner friendly instructions and adding a section on ORMs.

## Quick Start: How to Use MySQL in Node

Maybe you’ve arrived here looking for a quick leg up. If you’re just after a way to get up and running with MySQL in Node in as little time as possible, we got you covered!

Here’s how to use MySQL in Node in 5 easy steps:

1.  Create a new project: `mkdir mysql-test && cd mysql-test`
2.  Create a `package.json` file: `npm init –y`
3.  Install the mysql module: `npm install mysql –save`
4.  Create an `app.js` file and copy in the snippet below.
5.  Run the file: `node app.js`. Observe a “Connected!” message.

```
//app.js

const mysql = require('mysql');
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'database name'
});
connection.connect((err) => {
  if (err) throw err;
  console.log('Connected!');
});

```

## Installing the mysql Module

Now let’s take a closer look at each of those steps. First of all we’re using the command line to create a new directory and navigate to it. Then we’re creating a `package.json` file using the command `npm init –y`. The `-y` flag means that npm will use only defaults and not prompt you for any options.

This step also assumes that you have Node and npm installed on your system. If this is not the case, then check out this SitePoint article to find out how to do that: [Install Multiple Versions of Node.js using nvm](https://www.sitepoint.com/quick-tip-multiple-versions-node-nvm/).

After that, we’re installing the [mysql module](https://www.npmjs.com/package/mysql) from npm and saving it as a project dependency. Project dependencies (as opposed to dev-dependencies) are those packages required for the application to run. You can read [more about the differences between the two here](https://stackoverflow.com/q/22891211).

```
mkdir mysql-test
cd mysql-test
npm install mysql -y

```

If you need further help using npm, then be sure to check out [this guide](http://www.sitepoint.com/beginners-guide-node-package-manager/), or ask in [our forums](http://community.sitepoint.com/c/javascript).

## Getting Started

Before we get on to connecting to a database, it’s important that you have MySQL installed and configured on your machine. If this is not the case, please consult the [installation instructions on their home page](https://dev.mysql.com/doc/refman/5.7/en/installing.html).

The next thing we need to do is to create a database and a database table to work with. You can do this using a
graphical interface, such as [phpMyAdmin](https://www.phpmyadmin.net/), or using the command line. For this article I’ll be using a database called `sitepoint` and a table called `employees`. Here’s a dump of the database, so that you can get up and running quickly, if you wish to follow along:

```
CREATE TABLE employees (
  id int(11) NOT NULL AUTO_INCREMENT,
  name varchar(50),
  location varchar(50),
  PRIMARY KEY (id)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=5 ;

INSERT INTO employees (id, name, location) VALUES
(1, 'Jasmine', 'Australia'),
(2, 'Jay', 'India'),
(3, 'Jim', 'Germany'),
(4, 'Lesley', 'Scotland');

```

![Using MySQL with Node.js & the mysql JavaScript Client](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1499611321insert-data-into-table-phpmyadmin.png)

## Connecting to the Database

Now, let’s create a file called `app.js` in our `mysql-test` directory and see how to connect to MySQL from Node.js.

```
// app.js
const mysql = require('mysql');

// First you need to create a connection to the db
const con = mysql.createConnection({
  host: 'localhost',
  user: 'user',
  password: 'password',
});

con.connect((err) => {
  if(err){
    console.log('Error connecting to Db');
    return;
  }
  console.log('Connection established');
});

con.end((err) => {
  // The connection is terminated gracefully
  // Ensures all previously enqueued queries are still
  // before sending a COM_QUIT packet to the MySQL server.
});

```

Now open up a terminal and enter `node app.js`. Once the connection is successfully established you should be able to see the ‘Connection established’ message in the console. If something goes wrong (for example you enter the wrong password), a callback is fired, which is passed an instance of the JavaScript Error object (`err`). Try logging this to the console to see what additional useful information it contains.

### Using Grunt to Watch the Files for Changes

Running `node app.js` by hand every time we make a change to our code is going to get a bit tedious, so let’s automate that. This part isn’t necessary to follow along with the rest of the tutorial, but will certainly save you some keystrokes.

Let’s start off by installing a couple of packages:

```
npm install --save-dev grunt grunt-contrib-watch grunt-execute

```

[Grunt](http://gruntjs.com/) is the well-know JavaScript task runner, [grunt-contrib-watch](https://www.npmjs.com/package/grunt-contrib-watch) runs a pre-defined task whenever a watched file changes, and [grunt-execute](https://www.npmjs.com/package/grunt-execute) can be used to run the `node app.js` command.

Once these are installed, create a file called `Gruntfile.js` in the project root and add the following code.

```
// Gruntfile.js

module.exports = (grunt) => {
  grunt.initConfig({
    execute: {
      target: {
        src: ['app.js']
      }
    },
    watch: {
      scripts: {
        files: ['app.js'],
        tasks: ['execute'],
      },
    }
  });

  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-execute');
};

```

Now run `grunt watch` and make a change to `app.js`. Grunt should detect the change and re-run the `node app.js` command.

## Executing Queries

### Reading

Now that you know how to establish a connection to MySQL from Node.js, let’s see how to execute SQL queries. We’ll start by specifying the database name (`sitepoint`) in the `createConnection` command.

```
const con = mysql.createConnection({
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'sitepoint'
});

```

Once the connection is established we’ll use the connection variable to execute a query against the database table `employees`.

```
con.query('SELECT * FROM employees', (err,rows) => {
  if(err) throw err;

  console.log('Data received from Db:\n');
  console.log(rows);
});

```

When you run `app.js` (either using `grunt-watch` or by typing `node app.js` into your terminal), you should be able to see the data returned from database logged to the terminal.

```
[ { id: 1, name: 'Jasmine', location: 'Australia' },
  { id: 2, name: 'Jay', location: 'India' },
  { id: 3, name: 'Jim', location: 'Germany' },
  { id: 4, name: 'Lesley', location: 'Scotland' } ]

```

Data returned from the MySQL database can be parsed by simply lopping over the `rows` object.

```
rows.forEach( (row) => {
  console.log(`${row.name} is in ${row.location}`);
});

```

### Creating

You can execute an insert query against a database, like so:

```
const employee = { name: 'Winnie', location: 'Australia' };
con.query('INSERT INTO employees SET ?', employee, (err, res) => {
  if(err) throw err;

  console.log('Last insert ID:', res.insertId);
});

```

Note how we can get the ID of the inserted record using the callback parameter.

### Updating

Similarly, when executing an update query, the number of rows affected can be retrieved using `result.affectedRows`:

```
con.query(
  'UPDATE employees SET location = ? Where ID = ?',
  ['South Africa', 5],
  (err, result) => {
    if (err) throw err;

    console.log(`Changed ${result.changedRows} row(s)`);
  }
);

```

### Destroying

Same thing goes for a delete query:

```
con.query(
  'DELETE FROM employees WHERE id = ?', [5], (err, result) => {
    if (err) throw err;

    console.log(`Deleted ${result.affectedRows} row(s)`);
  }
);

```

## Advanced Use

I’d like to finish off by looking at how the mysql module handles stored procedures and the escaping of user input.

### Stored Procedures

Put simply, a stored procedure is a procedure (written in, for example, SQL) stored in a database which can be called by the database engine and connected programming languages. If you are in need of a refresher, then please check out [this excellent article](http://www.sitepoint.com/stored-procedures-mysql-php/).

Let’s create a stored procedure for our `sitepoint` database which fetches all the employee details. We’ll call it `sp_getall` . To do this, you’ll need some kind of interface to the database. I’m using [phpMyAdmin](http://www.phpmyadmin.net/home_page/index.php). Run the following query on the sitepoint database:

```
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_getall`()
BEGIN
  SELECT id, name, location FROM employees;
END

```

This will create and store the procedure in the `information_schema` database in the `ROUTINES` table.

![Stored procedure phpMyAdmin](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1499614150stored-procedure-phpmyadmin.png)

Next, establish a connection and use the connection object to call the stored procedure as shown:

```
con.query('CALL sp_getall()',function(err, rows){
  if (err) throw err;

  console.log('Data received from Db:\n');
  console.log(rows);
});

```

Save the changes and run the file. Once executed you should be able to view the data returned from the database.

```
[ [ { id: 1, name: 'Jasmine', location: 'Australia' },
    { id: 2, name: 'Jay', location: 'India' },
    { id: 3, name: 'Jim', location: 'Germany' },
    { id: 4, name: 'Lesley', location: 'Scotland' } ],
  { fieldCount: 0,
    affectedRows: 0,
    insertId: 0,
    serverStatus: 34,
    warningCount: 0,
    message: '',
    protocol41: true,
    changedRows: 0 } ]

```

Along with the data, it returns some additional information, such as the affected number of rows, `insertId` etc. You need to iterate over the 0th index of the returned data to get employee details separated from the rest of the information.

```
rows[0].forEach( (row) => {
  console.log(`${row.name} is in ${row.location}`);
});

```

Now lets consider a stored procedure which requires an input parameter.

```
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_get_employee_detail`(
  in employee_id int
)
BEGIN
  SELECT name, location FROM employees where id = employee_id;
END

```

Now we can pass the input parameter while making a call to the stored procedure:

```
con.query('CALL sp_get_employee_detail(1)', (err, rows) => {
  if(err) throw err;

  console.log('Data received from Db:\n');
  console.log(rows[0]);
});

```

Most of the time when we try to insert a record into the database, we need the last inserted ID to be returned as an out parameter. Consider the following insert stored procedure with an out parameter:

```
DELIMITER $$

CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_insert_employee`(
  out employee_id int,
  in employee_name varchar(25),
  in employee_location varchar(25)
)
BEGIN
  insert into employees(name, location)
  values(employee_name, employee_location);
  set employee_id = LAST_INSERT_ID();
END

```

To make a procedure call with an out parameter, we first need to enable multiple calls while creating the connection. So, modify the connection by setting the multiple statement execution to `true`.

```
const con = mysql.createConnection({
  host: 'localhost',
  user: 'user',
  password: 'password',
  database: 'sitepoint',
  multipleStatements: true
});

```

Next when making a call to the procedure, set an out parameter and pass it in.

```
con.query(
  "SET @employee_id = 0; CALL sp_insert_employee(@employee_id, 'Ron', 'USA'); SELECT @employee_id",
  (err, rows) => {
    if (err) throw err;

    console.log('Data received from Db:\n');
    console.log(rows);
  }
);

```

As seen in the above code, we have set an out parameter `@employee_id` and passed it while making a call to the stored procedure. Once the call has been made we need to select the out parameter to access the returned ID.

Run `app.js`. On successful execution you should be able to see the selected out parameter along with various other information. `rows[2]` should give you access to the selected out parameter.

```
[ { '@employee_id': 6 } ]

```

### Escaping User Input

In order to avoid SQL Injection attacks, you should **always** escape any data from user land before using it inside a SQL query. Let’s demonstrate why:

```
const userLandVariable = '4 ';

con.query(
  `SELECT * FROM employees WHERE id = ${userLandVariable}`,
  (err, rows) => {
    if(err) throw err;
    console.log(rows);
  }
);

```

This seems harmless enough and even returns the correct result:

```
 { id: 4, name: 'Lesley', location: 'Scotland' }

```

However, if we change the userLandVariable to this:

```
const userLandVariable = '4 OR 1=1';

```

we suddenly have access to the entire data set. If we then change it to this:

```
const userLandVariable = '4; DROP TABLE employees';

```

then we’re in proper trouble!

The good news is that help is at hand. You just have to use the [mysql.escape](https://www.npmjs.com/package/mysql#escaping-query-values) method:

```
con.query(
  `SELECT * FROM employees WHERE id = ${mysql.escape(userLandVariable)}`,
  function(err, rows){ ... }
);

```

Or by using a question mark placeholder, as we did in the examples at the beginning of the article:

```
 con.query(
  'SELECT * FROM employees WHERE id = ?',
  [userLandVariable],
  (err, rows) => { ... }
);

```

## Why Not Just USE an ORM?

As you may have noticed, a couple of people in the comments are suggesting using an ORM. Before we get into the pros and cons of this approach, let’s take a second to look at what ORMs are. The following is taken from [an answer on Stack Overflow](https://stackoverflow.com/a/1279678/1136887):

> Object-Relational Mapping (ORM) is a technique that lets you query and manipulate data from a database using an object-oriented paradigm. When talking about ORM, most people are referring to a library that implements the Object-Relational Mapping technique, hence the phrase “an ORM”.

So basically, this approach means you write your database logic in the domain-specific language of the ORM, as opposed to the vanilla approach we have been taking so far. Here’s a contrived example using [Sequelize](http://docs.sequelizejs.com/):

```
Employee.findAll().then(employees => {
  console.log(employees);
});

```

Contrasted with:

```
con.query('SELECT * FROM employees', (err,rows) => {
  if(err) throw err;

  console.log('Data received from Db:\n');
  console.log(rows);
});

```

Whether or not using an ORM makes sense for you, will depend very much on what you are working on and with whom. On the one hand, ORMS tend to make developers more productive, in part by abstracting away a large part of the SQL so that not everyone on the team needs to know how to write super efficient database specific queries. It is also easy to move to different database software, because you are developing to an abstraction.

On the other hand however, it is possible to write some really messy and inefficient SQL as a result of not understanding how the ORM does what it does. Performance is also an issue in that it’s much easier to optimize queries that don’t have to go through the ORM.

Whichever path you take is up to you, but if this is a decision you’re in the process of making, check out this Stack Overflow thread: [Why should you use an ORM?](https://stackoverflow.com/q/448684/1136887) as well as this post on SitePoint: [3 JavaScript ORMs You Might Not Know](https://www.sitepoint.com/3-javascript-orms-you-might-not-know/).

## Conclusion

In this tutorial, we’ve only scratched the surface of what the mysql client offers. For more detailed information, I would recommend reading the [official documentation](https://github.com/mysqljs/mysql). There are other options too, such as [node-mysql2](https://github.com/sidorares/node-mysql2) and [node-mysql-libmysqlclient](https://github.com/Sannis/node-mysql-libmysqlclient).
]]></description>
            <link>https://hungvn.com/blog/using-mysql-with-node-js-the-mysql-javascript-client</link>
            <guid isPermaLink="true">https://hungvn.com/blog/using-mysql-with-node-js-the-mysql-javascript-client</guid>
            <pubDate>Sun, 23 Jul 2017 16:47:48 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[10 React mini-patterns]]></title>
            <description><![CDATA[
Over the last few years, I’ve worked on a handful of decent-sized React projects, and many, many pint-sized ones. Throughout this magical journey, a number of patterns have come up that I find myself repeating again and again.

Because that’s what patterns are.

These are the sorts of things I would like to have heard about on day one. So if today is your day one with React, you’re in luck.

Or maybe you’re not. There’s only one way to find out…

It’s a long one, but it’s a listicle so you can skip the boring ones (3, 6, 8, 10).

### #1 Sending data down and up

The one thing I’d recommend to everyone new to React is to get your head around the pattern of passing information down (as objects, strings, etc.) and passing methods down to allow child components to pass information back up.

Like sending down a packet of chips and a walkie talkie to miners trapped underground.

How about a picture? The below _thing_ is the simplest form of this pattern.

![](https://cdn-images-1.medium.com/max/2000/1*J5XOQh2WKIl0NFTAMvcVbQ.png)Worth a thousand words?

Parent on the left, child on the right. You can think of the two props that connect these components as allowing information to flow in either direction between the two.

The prop called `items` is passing data down into the child component. The prop called `deleteItem` is giving the child component a way to send some information back up into the parent (“hey, delete this item”).

That’s not really a pattern.

The rest are patterns. I promise.

### #2 Fixing HTML’s inputs

One of the great things about React, and web components in general, is that you get to iron out the kinks if something in html doesn’t work the way you want.

If you think about the different elements that allow for user input (do it), you will soon see that the naming of these elements is nonsensical, bordering on reckless.

If I’m building a site that will have a lot of user inputs, one of the first things I do is fix this.

![](https://cdn-images-1.medium.com/max/1600/1*WTUJjlFOOnetc5NpbykN0w.png)

It’s not purely cosmetic though; there are more improvements to be had:

- Inputs should return a value via an `onChange` method, not a JavaScript `Event` instance, shouldn’t they?
- You can go a step further and ensure that the data type returned in `onChange` matches the type passed in. If the `typeof props.value` is `number`, then convert `e.target.value` back to a number before sending the data out again.
- A set of radio buttons is functionally the same thing as a `<select>`, right? It’s messed up to treat them in a completely different manner when the only difference is the UI. Maybe for your app it makes sense to have a single `<PickOneFromMany />` component and pass either `ui="radio"` or `ui="dropDown"`.

The point is not to do it like I do it. The point is to make them your own — you don’t need to keep working with the somewhat ass-about nature of HTML’s user input elements.

### #3 Binding labels to inputs with unique IDs

On the topic of inputs… if you care about your users, you’ll bind your `<label>` elements to your `<input>`s via an `id`/`for` combo.

But you don’t want to think of some clever and unique id for every input you define, who’s got time for that? I don’t know about you but I’ve got goat videos to watch.

(Frequent-flyer tip: if you have a screaming child on your flight, close your eyes and pretend you’re watching a video on YouTube of goats that sound like humans. Annoying becomes hilarious.)

Back to it. You _could_ generate a random ID for each input/label pair, but then your client-rendered HTML won’t match your server-rendered HTML. Checksum error! That’s no good.

So, instead you can create a little module that gives an incrementing ID, and use that in an `Input` component like so:

<Gist id="2cd13f571edda9a884107db3abd8de1b" />
Obviously it makes more sense when the input _isn’t_ inside the label.

If `getNextId()` simply increments a number every time it’s called, then when rendering on the server, the number would keep going up and up, eventually reaching infinity. So you’ll want to reset the number each time you render the app (for each network request).

You can do this at the entry point to your app, with a simple `resetId()` or whatever name you think is best.

With all that taken into account, your super-fancy module might look something like this:

<iframe
  width="700"
  height="250"
  src="/media/eaec23c7e00590dd1abf4d5f38b1f8c4?postId=c1da92f068c5"
  data-media-id="eaec23c7e00590dd1abf4d5f38b1f8c4"
  allowfullscreen=""
  frameborder="0"
></iframe>

### #4 Controlling CSS with props

When you want to apply different CSS in different instances (e.g. ‘primary’ and ‘secondary’ buttons) you can pass in props to control which CSS to apply.

This seems super simple on the surface, but let me assure you there are a lot of wrong ways to do this (I’ve tried them all!).

There are — I reckon — three distinct ways in which you can control the CSS applied to a component.

#### Using themes

For grouping a number of CSS declarations together, you can use the idea of ‘themes’, for example primary or secondary button:

`<Button theme="secondary">Hello</Button>`

Do your best to only require one theme per component.

#### Using flags

Maybe some of your buttons have rounded corners, but this doesn’t correspond directly with the themes you have defined.

In this case you can either sit your designer down and have _the consistency talk_, or create a boolean prop which might look a little something like this:

`<Button theme="secondary" rounded>Hello</Button>`

Just like HTML’s binary attributes, you don’t need to do `rounded={true}`.

#### Setting values

In some cases you might want to pass in the value of a CSS property directly (in the component you would set it as an inline style).

`<Icon width="25" height="25" type="search" />`

#### An example

Imagine you’re creating a link component. You go through your site’s designs and work out that there are three distinct themes, and that sometimes they have an underline, sometimes they don’t.

![](https://cdn-images-1.medium.com/max/1600/1*Kx1jOQONhFZPnGe72Fd4tQ.png)

Here’s how I would design that component:

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/dfb4c3dc156aa8ed845d9c112c8b1f8f?postId=c1da92f068c5"
  data-media-id="dfb4c3dc156aa8ed845d9c112c8b1f8f"
  allowfullscreen=""
  frameborder="0"
></iframe>

And the CSS…

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/4ded89adeae075da936827ddaf50c3ca?postId=c1da92f068c5"
  data-media-id="4ded89adeae075da936827ddaf50c3ca"
  allowfullscreen=""
  frameborder="0"
></iframe>

You may have noticed the awkward double negative for `link--no-underline`.

Story time: I used to think writing fewer lines of CSS was the goal, but it’s not. I’d rather have some double-negatives and multi-selector rulesets if it means the styles are applied in a nice layered way.

I’m sure I’ve said it before but the hardest thing about scaling a website is the CSS. JavaScript is easy, but with CSS you pay for your sins — once you’ve started a mess, it’s not easy to back out of.

True fact: fighting CSS specificity is the number one cause of death among web developers. If you’re on a big computer, check out the CSS for the little notification icon in medium’s top nav.

If you’re not, or you’re lazy, just guess how many CSS rules are combined to make this round circle with a number in it?

Twenty three rules.

That’s _not_ including the styles inherited from eleven other rules.

The line-height alone is overridden nine times.

![](https://cdn-images-1.medium.com/max/1600/1*lQzlIf8PPqeLUS5VOvTH4Q.png)

If line-height was a cat it would be dead by now.

This cannot be pleasant to maintain.

With React we can do better. We can thoughtfully design which classes are applied to our components. We can remove global resets and move it all inside our `Button.scss`. We can remove all reliance on specificity and ordering of files.

Side note: I dream of a day when we will be able to tell browsers that we don’t want their opinion about style at all. `::user-agent-styles: none-whatsoever;` — make it happen, vendors. [Edit: a clever chap in the comments has pointed out that `all: unset` may cure what ails me.]

### #5 The switching component

A switching component is a component that renders one of many components.

This may be a `<Page>` component that displays one of many pages. Or tabs in a tab set, or different modals in a modal component.

I used to do this with switch statements, then progressed to actually passing in the component I wanted rendered. Then moved on to exporting references to the components from the component itself (as named exports, then as properties on the component).

All terrible ideas.

The potentially-terrible approach that I have settled on is to use an object to map prop values to components.

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/96a9869514dbe2385cc84122fc6cc176?postId=c1da92f068c5"
  data-media-id="96a9869514dbe2385cc84122fc6cc176"
  allowfullscreen=""
  frameborder="0"
></iframe>

The keys of the `PAGES` object can be used in the prop types to catch dev-time errors.

Then of course we would use this like `<Page page="home" />`.

If you replace the keys `home`, `about` and `user` with `/`, `/about`, and `/user`, you’ve got yourself half a router.

(Future post idea: removing `react-router`.)

### #6 Reaching into a component

If you’re looking for an easy way to please your users, add `autofocus` to the input that they are most likely to type into when coming to a page. It really is that easy.

Perhaps you have a sign-in form and — being the UX champ that you are — you want to put that little blinking cursor in the ‘user name’ field.

But oh no, the form shows in a modal when the user clicks ‘sign in’, and the `autofocus` attribute only applies to page load.

Whatever will you do!

You’ll programmatically focus the element, that’s what. Here you may be tempted to give the input an id and type `document.getElementById('user-name-input').focus()`.

This works, but is not The Correct Way. The fewer things you have in your app that rely on two strings matching, the better.

Luckily, there is a very easy way to do this ‘properly’:

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/0891e4dcdf9fb9032c6176b9922e493b?postId=c1da92f068c5"
  data-media-id="0891e4dcdf9fb9032c6176b9922e493b"
  allowfullscreen=""
  frameborder="0"
></iframe>

Boom, an input component with a `focus()` method that focuses the HTML element.

In the parent component, we can get a reference to the Input component and call its `focus()` method.

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/3d30a05ce7156921f13a70f2552c6e84?postId=c1da92f068c5"
  data-media-id="3d30a05ce7156921f13a70f2552c6e84"
  allowfullscreen=""
  frameborder="0"
></iframe>

Note that when you use `ref` on a component, it’s a reference to the component (not the underlying element), so you have access to its methods.

### #7 Almost-components

Let’s say you’re building a component that lets you search for people. As you type, you see a list of names and photos of potential matches. Something like this.

![](https://cdn-images-1.medium.com/max/1600/1*AH_RjXx3xldF651qvef7cQ.png)

(I’m searching for political satirists because I, like _everyone_, am super interested in what other people think about politics.)

When designing this component, you may think to yourself: is each item in that list it’s own `SearchSuggestion` component? It’s really only a few lines of HTML and CSS, so maybe not? But I was once told ‘if in doubt, create another component’.

Oh my, this is quite the dilly of a pickle, isn’t it?

If I was making this, I would not have a separate component. Instead, just a `renderSearchSuggestion` method that returned the appropriate DOM for each entry. I can then generate the results like:

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/75d17b5d12aef07c1ef61a6e328ccdea?postId=c1da92f068c5"
  data-media-id="75d17b5d12aef07c1ef61a6e328ccdea"
  allowfullscreen=""
  frameborder="0"
></iframe>

If things get more complex or you want to use this component elsewhere, you should be able to copy/paste the code out into a new component.

Don’t prematurely componentize. Components aren’t like teaspoons; you _can_ have too many.

What I am not saying: “take something that you think should be a component, and make it part of the parent component.”

What I am saying: “take something that you _don’t_ think should be a component, and make it a bit more like its own component (if it can be).”

### #8 Components for formatting text

When I first started with React I thought of components as big things, a way of grouping structural chunks of DOM. But components work just as well as a way to apply formatting.

Here’s a `<Price>` component that takes a number and returns a pretty string, with or without decimals and a ‘$’ sign.

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/050f630c5f8b4e11d07b0acbfedf3a27?postId=c1da92f068c5"
  data-media-id="050f630c5f8b4e11d07b0acbfedf3a27"
  allowfullscreen=""
  frameborder="0"
></iframe>

As you can see I’m using the powerful `Intl` string formatting library, here’s a [link to their website](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString).

I should point out (before some punk does) that this is not a saving in lines of code. You could just as easily use a function to do this. (Of course components are just functions with different shaped brackets.)

It’s less code, but to my eye, not quite as nice:

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/30c70e652e0713bda8a24e1b279da38d?postId=c1da92f068c5"
  data-media-id="30c70e652e0713bda8a24e1b279da38d"
  allowfullscreen=""
  frameborder="0"
></iframe>

Note that I’m not checking that I got a valid number in any of the above. That’s because …

### #9 The store is the component’s servant

I have probably written this thousands of times:

<pre name="1d90" id="1d90" class="graf graf--pre graf-after--p">
  if (props.user.signInStatus === SIGN_IN_STATUSES.SIGNED_IN)...
</pre>

(I’ve been told that I exaggerate, like, a gazillion times.)

Quite recently I have decided that if I’m doing a check like this, I’m doing it wrong. I want to just ask “is the user signed in?”, not “is the sign in status of the user equal to signed in?”

My components have enough going on in their lives, they shouldn’t have to worry their pretty little heads over such matters. Nor should they have to worry that a price isn’t being sent as a number, or a boolean as the word ‘true’.

For you see, if the data in your store is designed to match your components, your components will be much simpler. And I’ve said it before, complexity is where the bugs hide. The less complexity you have in your components, the lower the chance of bugs.

But the complexity has to go _somewhere_, doesn’t it?

My suggestion is this:

1.  Work out the general structure of your components and the data they will require
2.  Design your store to support those requirements
3.  Do whatever you need to do to your incoming data to make it fit into the store.

For this last point, I recommend a single module that does all the massaging of incoming data (oh la la). Renaming props, casting strings to numbers, objects into arrays, date strings to date objects, whatever.

Do it all in the one place, and unit test the crap out of it.

If you’re rockin’ a react/redux setup, you might then do something like this in an action creator that fetches search results:

<iframe
  width="700"
  height="250"
  src="https://hackernoon.com/media/8ac21a8aadee41ba449483eeee941b6d?postId=c1da92f068c5"
  data-media-id="8ac21a8aadee41ba449483eeee941b6d"
  allowfullscreen=""
  frameborder="0"
></iframe>

Your components will thank you for it.

### #10 Importing components without relative paths

Wouldn’t it be sweet if instead of doing this:

<pre name="1347" id="1347" class="graf graf--pre graf-after--p">
  **import** Button **from** '../../../../Button/Button.jsx'; **import** Icon **from**
  '../../../../Icon/Icon.jsx'; **import** Footer **from** '../../Footer/Footer.jsx';
</pre>

You could just do this:

```
import {Button, Icon, Footer} from 'Components';
```

Well in _theory_ you can:

- Create a single `index.js` somewhere that exports references each of your components
- Use Webpack's `resolve.alias` to redirect `Components` to that index file

I hadn’t done this before, and planned to convert one of my existing apps for this post (then lie and tell you I totes do it all the time). But as I wrote the code I came to realise that this is a bad idea, for three reasons:

1.  It [seems to be broken](https://github.com/webpack/webpack/issues/4160#issuecomment-281236136) in Webpack 2.
2.  It’s an `eslint` error because `Components` won’t be in `node_modules`.
3.  If you use a good IDE, it will know things about your components. You will get clever warnings about not supplying required props, the ability to `cmd`/`ctrl`+click to open that component’s file. Things of that nature.
    If you do the above, your IDE will no longer know where to find that component and you’ll lose those smarts.

![](https://cdn-images-1.medium.com/max/1600/1*iYAef1TLM3P9HHCuPHp1QQ.png)Thanks, WebStorm.

Edit: [matthew hsiung](https://medium.com/@hsiungmatt) has a solution for the eslint and WebStorm issues in [this comment](https://medium.com/@hsiungmatt/great-article-917a2f6b718e#.w66jk94ao).

### Wrap up

That’s the lot of them. I’m quite sure I’ll look at this in a year and wince. Perhaps you’ll do it today. Perhaps you’ll share something that has served you well.

Oh and I’ve decided I don’t care if you click the little green heart or not. I WILL NOT BE DEFINED BY AN INTERNET METRIC.
]]></description>
            <link>https://hungvn.com/blog/10-react-mini-patterns</link>
            <guid isPermaLink="true">https://hungvn.com/blog/10-react-mini-patterns</guid>
            <pubDate>Sun, 16 Jul 2017 21:50:48 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về async và await đơn giản]]></title>
            <description><![CDATA[
### 1. Giới thiệu

Với các đặc tả JavaScript cũ, ta phải sử dụng các hàm phản hồi để xử lý các thao tác bất đồng bộ. Tuy nhiên việc này dẫn tới tình trạng [callback hell](https://stackoverflow.com/questions/25098066/what-is-callback-hell-and-how-and-why-rx-solves-it) khi ta có nhiều thao tác bất đồng bộ phải chờ nhau thực hiện. Call hell làm cho mã nguồn của ta rất rối và khó bảo trì.

```javascript
function wait(ms, cb) {
  setTimeout(cb, ms);
}

function main() {
  console.log("sắp rồi...");
  wait(2007, () => {
    console.log("chờ tí...");
    wait(2012, () => {
      console.log("thêm chút nữa thôi...");
      wait(2016, () => {
        console.log("xong rồi đấy!");
      });
    });
  });
}
```

Vì vậy, với phiên bản ES6 (ES 2016), [Promise](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/Promise) đã được đưa vào mặc định nhằm giải quyết tình trạng callback hell. Với Promise, mã nguồn của ta sẽ trông gần giống với phong cách đồng bộ, kết quả là trông dễ theo dõi và bảo trì hơn. Tuy nhiên sử dụng `Promise` lại làm phát sinh vấn đề "khá" tương tự là Promise hell ( lol! JavaScript Heo! ).

```javascript
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

function main() {
  console.log("sắp rồi...");
  wait(2007)
    .then(() => {
      console.log("chờ tí...");
      return wait(2007);
    })
    .then(() => {
      console.log("thêm chút nữa thôi...");
      return wait(2012);
    })
    .then(() => {
      console.log("thêm chút nữa thôi...");
      return wait(2016);
    })
    .then(() => {
      console.log("xong rồi đấy!");
    });
}
```

Để giải quyết vấn đề đó, ở phiên bản ES7 (ES 2017), 1 khái niệm với 2 từ khóa mới được đưa vào là hàm async (`async / await`). Hàm async cho phép ta viết các thao tác bất đồng bộ với phong cách của các mã đồng bộ. Bằng cách viết như vậy, mã nguồn của ta trông sẽ sáng sủa, dễ đọc hơn và "dễ hiểu hơn".

```javascript
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  console.log("sắp rồi...");
  await wait(2007);
  console.log("chờ tí...");
  await wait(2012);
  console.log("thêm chút nữa thôi...");
  await wait(2016);
  console.log("xong rồi đấy!");
}
```

### 2. Cách sử dụng

Để sử dụng hàm async, ta cần khai báo từ khóa `async` ngay trước từ khóa định nghĩa hàm. Tức là, với hàm định nghĩa với từ khóa `function` ta phải khai báo ngay trước `function`, với hàm mũi tên (arrow function) ta phải khai báo trước tập tham số đầu vào, với phương thức của lớp [`Class`](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Classes) thì ta phải khai báo ngay trước tên hàm.

```javascript
// regular function
async function functionName() {
  let ret = await new Google().search("JavaScript");
}

// arrow function
let arr = ["JS", "node.js"].map(async val => {
  return await new Google().search(val);
});

// Class
class Google {
  constructor() {
    this.apiKey = "...";
  }

  async search(keyword) {
    return await this.searchApi(keyword);
  }
}
```

Với từ khóa `async` này, ta có thể đợi các `Promise` (thao tác bất đồng bộ) xử lý trong hàm đó mà không tạm dùng luồng chính bằng từ khóa `await` như ví dụ trên.

Kết quả trả ra của hàm async luôn là một Promise dù bạn có gọi `await` - có xử lý bất đồng bộ hay không. Promise này sẽ ở trạng thái thành công với kết quả được trả ra với từ khóa `return` của hàm async, hoặc trạng thái thất bại với kết quả được đẩy qua từ khóa `throw` trong hàm async.

Như vậy, bản chất của hàm async chính là Promise. Nếu bạn chưa tìm hiểu về `Promise` thì nên đọc trước ở [bài viết này](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/Promise).

Với Promise, ta có thể xử lý ngoại lệ với [`catch`](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch) khá đơn giản. Tuy nhiên cũng không dễ dàng theo dõi và dễ đọc. Nhưng với hàm async, việc này cực kì đơn giản bằng từ khóa `try catch` hệt như các thao tác đồng bộ.

```javascript
//
// test.js
//
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function runner() {
  console.log("sắp rồi...");
  await wait(2007);
  console.log("chờ tí...");
  await wait(2012);
  console.log("thêm chút nữa thôi...");
  await wait(2016);
  throw new Error(2016);
}

async function main() {
  try {
    await runner();
    console.log("xong rồi đấy!");
  } catch (e) {
    console.log(`có vấn đề tại ${e}`);
  }
}

// Node v7
// `$ node --harmony-async-await test.js`
// Console: ... có vấn đề tại 2016
```

Ngon! Rõ ràng là mã nguồn sử dụng `async/await` trông đơn giản, dễ theo dõi, "dễ hiểu" hơn và giải quyết được tình trạng callback - promise hell. Tuy nhiên, việc sử dụng nó cũng không phải lúc nào cũng đơn giản. Ta cùng nhau xem một số trường hợp dưới đây.

### 3. Lưu ý

#### 3.1. Quên khai báo từ khóa `async`

Đương nhiên rồi, không khai báo từ khóa này thì ta không có hàm async được, không sử dụng `await` được rồi. Thường bạn sẽ nghĩ đơn giản là không thể nào quên được từ khóa này, nhưng tôi nghĩ đôi lúc có thể đấy. Ví dụ như với trường hợp khai báo một hàm trong một hàm async. Hàm khai báo trong hàm async cũng bắt buộc phải được khai báo với từ khóa `async` nếu như bạn muốn sử dụng như một hàm async.

```javascript
async function main() {
  await wait(1000)
  let arr = [100, 300, 500].map(val => wait(val))
  arr.forEach(func => await func)
  // ??? error
}
```

#### 3.2. Nhập nhằng từ khóa `await`

Có 2 tình huống điển hình cho trường hợp này là:

- Quên khai báo khi cần đợi một xử lý bất đồng bộ

  Có gì đáng sợ không? Câu trả lời là có đấy! Nếu bạn không khai báo từ khóa này thì kết quả bạn nhận được sẽ là một `Promise` chứ không phải là kết quả thực thi của xử lý bất đồng bộ nhé.

  ```javascript
  async function now() {
    return Date.now();
  }

  async function main() {
    let t = now();
    console.log(t);
    // ??? `t` is a `Promise` instance
  }
  ```

- Khai báo "thừa" trước một xử lý đồng bộ

  Nếu mà sợ quên thì cứ khai báo bừa đi, đâu có sao? Ừ không sao đâu ngoại trừ 2 vấn đề là không biết cái nào là đồng bộ, cái nào là bất đồng bộ nữa, và hiệu quả đi xuống đấy. Mỗi khi bạn khai báo `await` thì mặc nhiên sau từ khóa đó là một `Promise`, nếu không phải là một `Promise` thì nó sẽ được gói lại vào `Promise` và được trả ra ngay với phương thức [`Promise.resolve(value)`](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve). Rảnh quá ha, muốn lấy `1 + 0 = 1` mà phải đi đường vòng là tính tổng, rồi nhét vào Promise, rồi lại moi ra để sử dụng.

  ```javascript
  async function main() {
    // run with await
    console.log("run with await");
    let i = 1000000;
    console.time("await");
    while (i-- > 0) {
      let t = await (1 + 0);
    }
    console.timeEnd("await");

    // run without await
    console.log("run without await");
    i = 1000000;
    console.time("normal");
    while (i-- > 0) {
      let t = 1 + 0;
    }
    console.timeEnd("normal");
  }
  ```

#### 3.3. Quên xử lý lỗi

Cũng như với việc quên `catch` lỗi khi sử dụng Promise, việc quên `try catch` để bắt lỗi với hàm async cũng có thể xảy ra. Nếu bạn quên không bắt lỗi, thì khi đoạn mã bất đồng của bạn xảy ra lỗi có thể làm chương trình của bạn bị dừng lại.

```javascript
function wait(ms) {
  if (ms > 2015) throw new Error(ms);
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  console.log("sắp rồi...");
  await wait(2007);
  console.log("chờ tí...");
  await wait(2012);
  console.log("thêm chút nữa thôi...");
  await wait(2016);
  console.log("xong rồi đấy!");
}
```

#### 3.4. Mất tính song song

Cái này có vẻ là căng nhất, bạn cứ khai báo `await` tuần tự đi rồi chương trình của bạn sẽ chậm như con rùa. hahaaa. Vì mỗi lần khai báo `await` như vậy là bạn cần phải chờ cho xử lý của await kết thúc. Kết quả là bạn có 1 con rùa chạy tuần tự qua từng nấc thang.

```javascript
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  console.time("wait3s");
  await wait(1000);
  await wait(2000);
  console.timeEnd("wait3s");
}
```

Với đoạn mã trên bạn sẽ mất tổng cộng là `1 + 2 = 3s` để thực thi. Vì bạn phải chờ từng hàm `wait` một. Vậy làm sao để tránh được tình trạng trên? Câu trả lời là cứ cho xử lý bất đồng bộ chạy trước đi rồi lấy kết quả sau. Vì `Promise` có thể cho phép ta lấy kết quả bất cứ khi nào mà nó ở trạng thái cuối cùng, nên ta có thể chạy nó trước rồi lấy sau cũng không sao cả.

```javascript
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  console.time("wait2s");
  let w1 = wait(1000);
  let w2 = wait(2000);
  await w1;
  await w2;
  console.timeEnd("wait2s");
}
```

Như đoạn mã này, ta chỉ mất `2s` để thực hiện vì đoạn `wait` của ta được thực thi song song. Ngoài cách `await` từng `Promise` như trên ta có thể sử dụng [`Promise.all`](https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/Promise/all) để song song hóa các Promise.

```javascript
function wait(ms) {
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  console.time("wait2s");
  await Promise.all([wait(1000), wait(2000)]);
  console.timeEnd("wait2s");
}
```

Lúc này, có thể bạn đang nghĩ `Promise.all` và `await` từng Promise là như nhau, nhưng nó khác nhau chút đấy. `Promise.all` chỉ ở trạng thái thành công khi mà tất cả các Promise được truyền vào xử lý thành công, còn nó sẽ ở trạng thái lỗi khi một trong các Promise truyền vào bị lỗi. Như vậy, nếu bạn muốn bỏ qua các Promise lỗi thì bạn không thể sử dụng `Promise.all` được đâu. Lúc đó bắt buộc bạn phải sử dụng `await` kèm với `try catch` cho từng Promise của bạn.

```javascript
function wait(ms) {
  if (ms > 2000) throw new Error(ms);
  return new Promise(r => setTimeout(r, ms));
}

async function main() {
  const dur = [1000, 2000, 3000, 4000];
  let all = dur.map(ms => wait(ms));
  try {
    await Promise.all(all);
    console.log("Promise.all - done");
  } catch (e) {
    console.error("Promise.all:", e);
  }

  let each = dur.map(ms => wait(ms));
  each.forEach(async (func, index) => {
    try {
      await func;
      console.log("each - done:", dur[index]);
    } catch (e) {
      console.error("each:", e);
    }
  });
}
```

### 4. Nền tảng/ trình duyệt hỗ trợ

Thời điểm này (2016/10), các nền tảng và trình duyệt sau đã hỗ trợ hàm async.

- Node.js v7.0 với cờ `--harmony-async-await`
- Chrome v5.55
- Microsoft Edge v21.10547

Nếu bạn muốn chạy ở các nền tảng/ trình duyệt chưa hỗ trợ thì có thể dùng babel để chuyển đổi:

- Babel [async-2-generator plugin](https://babeljs.io/docs/plugins/transform-async-to-generator/)

### 5. Kết luận

Bản chất của hàm async chính là `Promise`, vì vậy để sử dụng được nó ta cần phải sử dụng `Promise` cho việc xử lý các thao tác bất đồng bộ. Bạn không thể nào sài `await` để đợi các hàm có sử dụng hàm phản hồi (callback) được, mà bắt buộc phải gắn nó với một Promise trước khi sử dụng `await`.

Mặc dù hàm async có cú pháp rất rõ ràng, ta cũng cần phải lưu ý tránh khai báo thừa thiếu các từ khóa gây lỗi, gây hiểu lầm về lô-gíc chương trình. Và đặc biệt lưu ý tới khả năng làm mất đi tính song song của chương trình.

Với sự tiện dụng của hàm async, ta nên cố gắng sử dụng nó ngay từ bây giờ để giảm thiểu việc bảo trì sau này. Với các nền tảng/ trình duyệt chưa hỗ trợ thì ta có thể chuyển đổi bằng [babel](https://babeljs.io/). Hiện tại Node v7 vẫn đang sử dụng Chrome v5.54 nên muốn sử dụng được async/await, ta buộc phải chạy với cờ `--harmony-async-await` và hiệu năng, bộ nhớ được sử dụng vẫn chưa hiệu quả, không khuyến khích cho các sản phẩm thực tế. Tuy nhiên, rất có thể Node v8 sẽ sử dụng phiên bản Chrome v5.55 và cho phép ta thực hiện mặc định các hàm async.

`async` chúc các bạn `await` vui vẻ!
]]></description>
            <link>https://hungvn.com/blog/javascript-tim-hieu-ve-async-va-await-don-gian</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-tim-hieu-ve-async-va-await-don-gian</guid>
            <pubDate>Tue, 10 Jan 2017 20:03:38 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Bất ngờ về mảng trong javascript]]></title>
            <description><![CDATA[
Từng làm việc với một vài ngôn ngữ lập trình (Java, C, C++, C#, Objective-C, PHP), mỗi ngôn ngữ đều có cái hay riêng. Nhưng khi tiếp xúc với JavaScript (JS) lại tự dưng thấy yêu nó, yêu cái vẻ sexy và bất ngờ của nó. Ví như mảng trong JS rất đặc biệt và bất ngờ. Trong bài này sẽ viết lại một số điểm có thể là bất ngờ với một số người như mình.

### 1. Bạn lấy độ dài của mảng thế nào?

Hôm qua ngồi code lúc lấy độ dài mảng bằng thuộc tính `length` mới thấy khác biệt với phần tử lấy được, làm mình hơi ngạc nhiên một chút. Ngồi đọc lại tài liệu JS, mới thấy dường như nó không có thuộc tính lưu trữ số lượng phần tử hiện hữu (khác `undefined`) trong nó thì phải? Hoặc ít nhất là mình chưa rõ. Có cao thủ nào chỉ giáo cho thì tốt. Các bạn có thể thử đoạn mã sau thì sẽ thấy rằng thuộc tính `length` của mảng sẽ bằng tổng của index lớn nhất của mảng với 1.

```javascript
var arr = [];
arr[10] = 0;
arr[20] = "index 20";
arr["js"] = "JavaScript";
console.log(arr.length);
```

Đoạn mã trên sẽ in ra độ dài của mảng arr là 21, tức là bằng index lớn nhất (20) cộng với 1. Hơi bất ngờ chút vì lúc đầu mình nghĩ nó trả ra là 3 (số phần tử khác `undefined`) .

Còn index không phải là dạng số tự nhiên thì có ý nghĩa gì không? Câu trả lời là không có ý nghĩa gì với thuộc tính length cả. Các bạn có thể xem trong ví dụ sau thì sẽ thấy độ dài `length` sẽ không phụ thuộc vào các index không thuộc dạng số tự nhiên.

```javascript
var arr = [];
arr[-1] = 100;
arr["js"] = "JavaScript";
arr["me"] = "Java Lover";
console.log(arr.length);
```

Đoạn mã này sẽ luôn in ra 0, chứng tỏ các index không số tự nhiên không ảnh hưởng gì tới thuộc tính `length`.

Vậy câu hỏi đặt ra là làm thế nào để lấy được số phần tử chính xác của một mảng?

Một cách làm đơn giản là duyệt mảng để đếm số lượng các phần tử hiện hữu của mảng đúng không? Thế nhưng mọi chuyện lại không đơn giản như ta nghĩ.

### 2. Bạn duyệt mảng thế nào?

Duyệt mảng trong JS cũng rất thú vị. Cách duyệt mảng thông thường với một mảng là lấy `length` của nó rồi duyệt từ đầu tới cuối như sau.

```javascript
var arr = [];
arr[10] = 0;
arr[20] = "index 20";
arr["me"] = "Java Lover";
var counter = 0;
for (var i = 0, len = arr.length; i < len; i++) {
  console.log(i + ": " + arr[i]);
  if (typeof arr[i] != "undefined") counter++;
}
// hoặc như sau
for (var i = arr.length; i > 0; --i) {
  console.log(i + ": " + arr[i]);
  if (typeof arr[i] != "undefined") counter++;
}
console.log("The size of array: %d", counter);
```

Kết quả đoạn mã trên sẽ trả ra các phần từ có index từ 0 ~ 9 và 11 ~ 19 là `undefined`, và counter sẽ là 2.
Như vậy là `counter` không cho ra kết quả chính xác và với một mảng lớn (1000 phần tử chẳng hạn) ta không thể duyệt theo cách này được. Vậy phải có cách khác, ta thử dùng hàm `forEach` của `Array` xem sao.

```javascript
var arr = [];
arr[10] = 0;
arr[20] = "index 20";
arr["me"] = "XXX Lover";
var counter = 0;
arr.forEach(function (ele, i, array) {
  console.log(i + ": " + ele);
  counter++;
});
console.log("The size of array: %d", counter);
```

Cách này vẫn không ăn thua, kết quả lại như duyệt theo biến length. Thêm một cách duyệt khác là với lệnh `for in` như sau.

```javascript
var arr = [];
arr[10] = 0;
arr[20] = "index 20";
arr["me"] = "Java Lover";
var counter = 0;
for (var i in arr) {
  console.log(i + ": " + arr[i]);
  counter++;
}
console.log("The size of array: %d", counter);
```

Đoạn này lại cho ra kết quả chính xác với từng phần tử được in ra và kích cỡ mảng trả về là 3.

Từ đây ta có thể thấy một điều là nên cẩn thận với biến length của mảng và nên chú ý cách duyệt mảng sao cho hợp lý. Với các dữ liệu liên tục ta hoàn toàn có thể duyệt theo biến `length` hay `Array.forEach`, nhưng dữ liệu cách đoạn và index không là số tự nhiên thì cần theo cách duyệt `for in`.

### 3. Làm sao để biết một biến là mảng?

Các bạn thử chạy đoạn mã sau xem thế nào.

```javascript
var arr = [];
arr[10] = 0;
arr[20] = "index 20";
arr["me"] = "JavaScript Lover";

console.log("Trust me, men, I'm an Array @@");
console.log("Really, I have to check your DNA.");
console.log("JavaScript checker: arr is " + typeof arr);
```

??? Mày là Object mà sao lại bảo là Array?
Không cháu là mảng mà, bác thử kiểm tra với cái máy này xem.

```javascript
var arr = [];
arr[10] = 0;
arr[20] = "index 20";
arr["me"] = "JavaScript Lover";

console.log(
  "JavaScript checker: Is arr an array ... " +
    (Object.prototype.toString.apply(arr) === "[object Array]")
);
```

Ồ, ồ khỉ thật sao lại thế nhỉ? Đấy cháu dòng giống hoàng tộc nên phải ẩn mình thế đấy. Đúng là nhìn gái xinh thì dễ chứ nhìn gái tốt hay xấu phải có mẹo thật.

Để kết thúc bài, dành tặng cho các bạn beginner về NodeJS một đoạn mã nhỏ. Bài toán đặt ra là lấy nội dung 3 trang web (giao thức http) với địa chỉ nhập từ bàn phím theo dạng bất đồng bộ và in ra nội dung các trang đó theo đúng thứ tự đầu vào nhập từ bàn phím.
Chắc code này không phải giải thích nhiều các bạn cũng sẽ thấy có mối tương quan với nội dung mình vừa viết phía trên.

```javascript
var http = require("http");
var bl = require("bl");
var data = [];
var counter = 0;

function printData() {
  for (var i = 0; i < 3; i++) console.log(data[i]);
}

function loadData(index) {
  http.get(process.argv[2 + index], function (resp) {
    resp.pipe(
      bl(function (err, buf) {
        if (err) data[index] = err.toString();
        else data[index] = buf.toString();
        counter++;
        if (counter === 3) printData();
      })
    );
  });
}

for (var i = 0; i < 3; i++) loadData(i);
```

Bài này tạm thời thế, khi nào gặp vấn đề lại update tiếp. Mong các cao thủ biết được gì thêm về mảng trong JavaScript thì chỉ giáo cho các hạ.
]]></description>
            <link>https://hungvn.com/blog/javascript-bat-ngo-ve-mang-trong-javascript</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-bat-ngo-ve-mang-trong-javascript</guid>
            <pubDate>Tue, 10 Jan 2017 20:02:14 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về call, apply và bind]]></title>
            <description><![CDATA[
Như trong bài về từ khóa `this` đã đề cập tới ngữ cảnh thực thi với mối tương quan tới từ khóa `this` và việc thay đổi được ngữ cảnh thực thi một cách trực tiếp bằng cách sử dụng `call`, `apply` và `bind`, thì bài viết này sẽ làm rõ ràng hơn 3 phương thức này và sự khác nhau cũng như tính hữu dụng của nó.

Về cơ bản `call` và `apply` gần giống nhau và được giới thiệu từ phiên bản 3 theo chuẩn ECMAScript, còn `bind` được giới thiệu từ phiên bản 5 thì lại khác hẳn về bản chất nhưng cũng có mối quan hệ mật thiết với 2 phương thức kia. Vậy nên trong bài này ta sẽ đi dần từ `call` với `apply` tới `bind`.

### 1. Call và Apply

Cú pháp:

- call()

  > Function.prototype.call(thisArg[, arg1[ , arg2, …]])

- apply()
  > Function.prototype.apply(thisArg, argArray)

Phương thức `call()` và `apply()` để **_gọi thực thi_** một hàm với một ngữ cảnh chỉ định thông qua tham số `thisArg` và các tham số đầu vào của hàm tương ứng. Tức là nó sẽ cho phép hàm thực thi được với một ngữ cảnh chỉ định nào đó tuỳ ý. Sự khác nhau giữa chúng là `call()` sẽ nhận tham số hàm qua từng biến đầu vào riêng biệt còn `apply()` thì lại nhận các tham số hàm qua một mảng chứa các biến đầu vào. Ta cùng xét ví dụ bên dưới:

```javascript
var obj = {
  firstName: "Vô",
  lastName: "Danh",

  mMethod: function (firstName, lastName) {
    var firstName = firstName || this.firstName;
    var lastName = lastName || this.lastName;
    console.log("Hello " + firstName + " " + lastName);
  },
};

var obj1 = {
  firstName: "Ông",
  lastName: "Ké",
};

obj.mMethod(); // Hello Vô Danh

obj.mMethod.call(obj1); // Hello Ông Ké

obj.mMethod.apply(obj1); // Hello Ông Ké

obj.mMethod.call(obj1, "Thị", "Nở"); // Hello Thị Nở

obj.mMethod.apply(obj1, ["Chí", "Phèo"]); // Hello Chí Phèo
```

Với đoạn mã trên ta có thể thấy rằng, sau khi gọi `call()` hoặc `apply()` ngữ cảnh thực thi của `mMethod` đã được đổi sang `obj1` và `call()` cho phép ta truyền tham số đầu vào riêng biệt còn `apply()` lại cho phép truyền vào như một mảng.

Từ phiên bản 5, `apply()` còn có thể được truyền vào một đối tượng tựa mảng (chú thích [1]) thay vì mảng:

```javascript
var obj = {
  firstName: "Vô",
  lastName: "Danh",

  mMethod: function (firstName, lastName) {
    var firstName = firstName || this.firstName;
    var lastName = lastName || this.lastName;
    console.log("Hello " + firstName + " " + lastName);
  },
};

var obj1 = {
  firstName: "Ông",
  lastName: "Ké",
};

obj.mMethod.apply(obj1, ["Chí", "Phèo"]); // Hello Chí Phèo

obj.mMethod.apply(obj1, { length: 2, 0: "Chí", 1: "Phèo" }); // Hello Chí Phèo
```

Với việc sử dụng `call()` hoặc `apply()` ta có thể làm được rất nhiều việc hay ho như sử dụng phương thức của một ngữ cảnh khác như ở ví dụ trên, hay đẩy ngữ cảnh thực thi cho hàm phản hồi hoặc thay đổi cách truyền tham số hàm rất hiểu quả. Các bạn có thể xem ở ví dụ sau:

- Truyền ngữ cảnh thực thi cho hàm phản hồi

```javascript
function print() {
  console.log(this.mVal);
}

var obj = {
  mVal: "Tôi yêu thành phố Hồ Chí Minh",

  mMethod: function (callback) {
    // truyền đối tượng hiện tại cho hàm phản hồi callback
    callback.call(this);
  },
};

obj.mMethod(print);
```

- Thay đổi cách truyền tham số hàm

```javascript
// Math.min([value1[,value2[, ...]]])
// Ta sử dụng mảng cho tham số đầu vào thay vì các giá trị rời rạc
console.log(Math.min.apply(null, [100, -1, 8, 219])); // -1
```

Cũng không tồi đấy chứ, bằng `call`, `apply` ta có thể linh hoạt hơn khi lập trình, đỡ được nhiều công sức biến đổi rắc rối và tận dụng được mã nguồn rất hiệu quả.

### 2. Bind

Cú pháp:

> Function.prototype.bind( thisArg[, arg1[ , arg2, …]])

Phương thức `bind()` sẽ **_tạo_** ra một **_hàm mới_** có nội dung thực thi như hàm được gọi nhưng được gắn với một ngữ cảnh thực thi chỉ định qua tham số `thisArg`. Như vậy khác với `call()` và `apply()`, `bind()` sẽ không gọi để thực thi hàm mà sẽ lưu lại ngữ cảnh thực thi cho một hàm nào đó như ví dụ sau:

```javascript
var obj = {
  mVal: "Việt Nam",

  mMethod: function () {
    console.log("Hello " + this.mVal);
  },
};

var oMethod = obj.mMethod.bind(obj); // this trong oMethod sẽ bị ép thành giá trị obj

oMethod(); // Hello Việt Nam

obj.mVal = "Hà Nội";

oMethod(); // Hello Hà Nội
```

Như vậy khác với `call()` và `apply()`, khi gọi `bind()` hàm sẽ không thực thi ngay mà chỉ gắn ngữ cảnh thực thi cho phương thức mMethod. Vì `mMethod` được gắn với ngữ cảnh đối tượng `obj`, nên mỗi lần thực thi nó sẽ sử dụng `this` như là đối tượng `obj`. Như trong ví dụ phía trên, sau khi ta thay đổi giá trị của biến `mVal` trong đối tượng `obj` thì `mMethod` cũng sẽ in ra giá trị đã bị thay đổi.

Về bản chất thì `bind()` có thể được thực hiện như sau:

```javascript
Function.prototype.bind = function (context) {
  var _this = this;
  return function () {
    _this.apply(context, arguments);
  };
};
```

Bằng việc sử dụng `apply()`, ta có thể thay đổi ngữ cảnh thực thi cho một hàm, còn để lưu lại ngữ cảnh dành cho việc thực thi sau này ta tạo ra một hàm mới như trong đoạn mã trên.

Vì tính chất lưu lại được ngữ cảnh nên `bind()` rất hay được sử dụng với hàm phản hồi như xử lý sự kiện click vào một nút nào đó chẳng hạn. Ví dụ như khi sử dụng jQuery, ta có thể lấy được giá trị cho `this` bằng `button` trong các hàm phản hồi của sự kiện `click` vào một `button` vì jQuery đều đã buộc (bind) sẵn `button` cho hàm phản hồi được truyền vào.

```html
<!doctype html>
<html>
  <head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
    <script>
      $(document).ready(function () {
        $("#btn").click(function () {
          console.log(this);
          $(this).text(Number($(this).text()) + 1);
        });
      });
    </script>
  </head>
  <body>
    <button id="btn">0</button>
  </body>
</html>
```

Ngoài ra, ta có thể làm được rất nhiều việc khá hay ho như tạo shortcut cho hàm nào đó, hay nhóm lại các tham số theo từng cụm như ví dụ bên dưới:

```javascript
var obj = {
  firstName: "Thánh",
  lastName: "Gióng",

  mMethod: function (hello, firstName, lastName) {
    var hello = hello || "Hello",
      firstName = firstName || this.firstName,
      lastName = lastName || this.lastName;

    console.log(hello + " " + firstName + " " + lastName);
  },
};

// tạo shortcut
var print = obj.mMethod.bind(obj);
print();

var print = obj.mMethod.bind(obj, "Hello", "Mr", "Bean");
print();

// Nhóm theo hello
print = obj.mMethod.bind(obj, "Xin chào bạn");
print();

// Nhóm theo firstName
print = obj.mMethod.bind(obj, "Kính chào ngài", "Nguyễn");
print("Trãi");
print("Xiển");
```

### 3. Vui vẻ tý

Như bên trên đã phân tích, khi ta cần thực thi một function cho một ngữ cảnh khác, ta cần sử dụng `call`, `apply` hoặc `bind`, nhưng có một cách vượt mặt để không cần sử dụng nó. Bạn có thể xem ví dụ sau:

```javascript
var obj = {
  firstName: "Vô",
  lastName: "Danh",

  mMethod: function (firstName, lastName) {
    var firstName = firstName || this.firstName;
    var lastName = lastName || this.lastName;
    console.log("Hello " + firstName + " " + lastName);
  },
};

var obj1 = {
  firstName: "Ông",
  lastName: "Ké",
};

obj.mMethod.apply(obj1); // Hello Ông Ké

// vượt mặt ở đây
var method = Function.call.bind(obj.mMethod);

method(obj1); // Hello Ông Ké

// vượt mặt trong prototype của object
method = Function.call.bind(Array.prototype.slice);

console.log(method([100, 20, 40], 1)); // [20, 40]
```

Với đoạn mã trên, ta có thế thấy rằng khi gọi `method` ta không cần phải gọi `call`, `apply` hay `bind` ra nữa mà chỉ cần đẩy trực tiếp đối tượng cần gọi và tham số vào là đủ. Khá hay ho đấy chứ? gọi `call`, `apply`, `bind` mãi cũng chán, overcome một tý thấy nó tiện hơn hẳn.

Ta có thể làm được như vậy là vì tất cả các function trong JavaScript đều kế thừa từ đối tượng `Function.prototype`, nên hiển nhiên nó có tất cả các function được định nghĩa từ `Function.prototype` như `call`, `apply` hay `bind`. Như vậy, ta hoàn toàn có thể gọi được các phương thức kế thừa này từ một function bất kì.

Với ví dụ trên, ta coi `obj.mMethod` là một đối tượng cần gọi tới phương thức `call` thì ta hoàn toàn có thể tạo một phương thức `method` trực tiếp từ phương thức `call` mà đã được gắn `thisVal` bằng `obj.mMethod`: `Function.call.bind(obj.mMethod)` hoặc `Function.prototype.call.bind(obj.mMethod)`. Hay nói cách khác, phương thức `method` mới được tạo ra có nội dung giống như phương thức `call` và đối tượng chứa nó (gọi nó - `this`) là đối tượng `obj.mMethod` nên `method()` ~ `obj.mMethod.call()`.

### 4. Kết luận

Bằng việc sử dụng `call`, `apply` và `bind` ta có thể thay đổi được ngữ cảnh thực thi (phạm vi chứa hàm) để sử dụng một hàm với công dụng đa năng hơn như thực thi cho một đối tượng, phạm vi khác khác giúp ta có thể tận dụng tối đa mã nguồn được đã tạo ra, hay tạo shortcut cho hàm, linh hoạt hơn tham số đầu vào. Với `call` và `apply` chúng ta sử dụng để thực thi hàm đó luôn khi gọi, còn với `bind` ta có thể thực thi hàm đó nhiều lần sau khi đã được buộc (bind) với một ngữ cảnh nhất định.

**_Chú thích_**
[1] đối tượng tựa mảng: Một đối tượng tựa mảng (array-like object) là một đối tượng có các thuộc tính là số tự nhiên và có một thuộc tính bắt buộc là `length` có giá trị bằng số các thuộc tính là số tự nhiên. Ví dụ: `{length: 3, 0: "Tôi", 1: "là", 2: "người Việt"}` hoặc `{'length': 3, '0': "Tôi", '1': "là", '2': "người Việt"}`.
]]></description>
            <link>https://hungvn.com/blog/javascript-tim-hieu-ve-call-apply-va-bind</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-tim-hieu-ve-call-apply-va-bind</guid>
            <pubDate>Tue, 10 Jan 2017 19:57:42 GMT</pubDate>
        </item>
        <item>
            <title><![CDATA[Tìm hiểu về từ khóa this]]></title>
            <description><![CDATA[
```javascript
// app.js
// câu hỏi: Đoán kết quả lệnh (1) và lệnh (2)
var obj = {
  mMethod: function () {
    console.log(this);
  },
};

obj.mMethod(); // (1)

var _mMethod = obj.mMethod;
_mMethod(); // (2)
```

JavaScript (JS) là một ngôn ngữ lập trình khá linh hoạt và thú vị. Nhưng để có được điều đó nó cũng mang tới không ít phiền phức, dễ nhầm lẫn với những người không chuyên. Với những người mới sờ vào JS, họ thường nghĩ ngay chắc JS cũng lơ lớ như các ngôn ngữ lập trình khác như Java hay C#. Nhưng nhiều điểm ở JS lại khá khác với suy nghĩ ở các ngôn ngữ khác gây nên những hiểu lầm cho người mới vào nghề. Một trong những điểm dễ nhầm lẫn đó là biến `this` vì trong JS nó không chỉ đơn giản là đại diện cho đối tượng hiện thời như các ngôn ngữ lập trình hướng đối tượng khác. Cụ thể ra sao ta cùng nhau xem xét ở bài viết này.

Đọc tới đây chắc một số bạn biết về `this` rồi sẽ bật cười là sao lại viết là biến `this`. Nếu bạn nghĩ tới mức đó thì xin chúc mừng bạn, bạn đã đúng. **this** trong JS **là** một **từ khoá** chứ không phải là một biến nào cả. Bạn không thể gắn giá trị trực tiếp cho `this` được cũng như chẳng thể nào `delete` nó đi. Vậy từ khoá này có gì lại rắc rối vậy?

### 1. Bản chất của từ khoá `this`

Các đoạn mã của JavaScript được thực thi trong một ngữ cảnh nhất định (Execution Context). Các ngữ cảnh này lại được sắp xếp để thực hiện chương trình một cách tuần tự. Bạn có thể tưởng tượng thế này, mỗi ngữ cảnh chứa một số đoạn mã nhất định, và toàn chương trình của ta sắp xếp các ngữ cảnh này vào một ngăn xếp (stack). Sau đó các ngữ cảnh sẽ được gọi ra thực thi dần cho tới hết, tức là ngữ cảnh trên đỉnh của ngăn xếp sẽ chứa các đoạn mã sẵn sàng chạy.

Mỗi ngữ cảnh thực thi này có tương ứng một `ThisBinding` có giá trị không đổi đại diện cho ngữ cảnh thực thi đó. Và từ khoá `this` sẽ bằng giá trị `ThisBinding` trong ngữ cảnh đang thực thi hiện thời. Như vậy `this` sẽ đại diện cho ngữ cảnh đang thực thi và nó cần được đánh giá lại tham chiếu khi ngữ cảnh thực thi thay đổi.

Có 3 kiểu ngữ cảnh thực thi là toàn cục (global), eval và hàm (function). Global là ngữ cảnh ở mức trên cùng của toàn bộ chương trình, tức là nó chứa các đoạn mã không nằm trong function hay được gọi bởi eval và global sẽ là ngữ cảnh thực thi chương trình mặc định. Eval là ngữ cảnh chứa các mã được gọi bởi hàm <a href="https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Global_Objects/eval" title="eval" target="_blank">`eval`</a>. Còn function là các đoạn mã nằm trong một function nào đó. Ta sẽ xem chi tiết từng ngữ cảnh thực thi qua phần dưới đây.

### 2. Các ngữ cảnh thực thi

#### 2.1. Toàn cục - Global

Là ngữ cảnh thực thi nằm ở trên cùng của ngăn xếp ngữ cảnh, tức là ngữ cảnh đầu tiên thực thi chương trình. Ví dụ trong các mã thực thi phía máy khách trong trang web thì ngữ cảnh toàn cục này nằm ngay sau thẻ . Trong ngữ cảnh toàn cục này thì `ThisBinding` sẽ được thiết lập giá trị là đối tượng toàn cục (Global Object). Trong Nodejs thì đối tượng toàn cục là đối tượng toàn cục của Nodejs - khởi đầu là một đối tượng trống, trong trình duyệt thì nó là đối tượng window, nhưng cần chú ý là nếu ở trong chế độ <a href="https://developer.mozilla.org/vi/docs/Web/JavaScript/Reference/Strict_mode" title="strict mode" target="_blank">`strict mode`</a> thì đối tượng toàn cục là `undefined`. Ta có thể cùng nhau xem xét ví dụ dưới đây.

```javascript
console.log(this); // đối tượng toàn cục trong ngữ cảnh toàn cục

this.mX = "I love JavaScript"; // sử dụng đối tượng toàn cục

console.log(this.mX); // in ra giá trị của thuộc tính mX

var obj = {
  mMethod: function () {
    console.log(this); // in ra giá trị this hiện thời
  },
};

obj.mMethod(); // không còn là đối tượng toàn cục nữa
```

#### 2.2. Gọi mã - Eval

Với trường hợp sử dụng hàm `eval` ta phân làm 2 trường hợp.

##### 2.2.1. Gọi eval trực tiếp

Gọi `eval` trực tiếp là ta gọi trực tiếp hàm `eval` như ví dụ bên dưới. Với trường hợp này thì `ThisBinding` sẽ được gắn giá trị là ngữ cảnh gốc của đoạn mã đó.

```javascript
function callMe() {
  console.log(this);
}

var obj = {
  callMe: function () {
    console.log(this);
  },
};

eval("callMe()"); // đối tượng toàn cục

eval("obj.callMe()"); // đối tượng obj
```

##### 2.2.2. Gọi eval gián tiếp

Gọi `eval` gián tiếp là ta gọi hàm `eval` thông qua một biến được gắn giá trị tương ứng như truyền hàm `eval` qua tham số hàm khác hoặc gắn nó với một biến nào đó. Với trường hợp này thì `ThisBinding` sẽ được gắn giá trị là ngữ toàn cục.

```javascript
// this trong mã thực thi của eval sẽ là đối tượng toàn cục
this.callMe = function () {
  console.log("callMe in Global Object");
};

var obj = {
  callMe: function () {
    console.log(this);
  },
  _callMe: function (_eval) {
    _eval("console.log(this)");
    _eval("callMe()");
  },
};

obj._callMe(eval); // gọi gián tiếp eval qua tham số hàm

var mEval = eval; // gắn eval với một biến

mEval("console.log(this)"); // gọi gián tiếp eval qua biến mEval
```

#### 2.3. Hàm - Function

Khi hàm được gọi thì ngữ cảnh thực thi của nó sẽ phụ thuộc vào tham số đầu vào và ngữ cảnh gọi nó. Giả sử hàm của ta là F, với tham số là argumentsLits, và ngữ cảnh gọi F tương ứng với thisValue. Việc xác định `thisBinding` được xác định như sau:

> 1. If hàm trong chế độ strict, ThisBinding được gắn là thisValue.
> 2. Else if thisValue là null hoặc undefined, ThisBinding được gắn là đối tượng toàn cục.
> 3. Else if Type(thisValue) không là Object, ThisBinding được gắn là ToObject(thisValue).
> 4. Else ThisBinding được gắn là thisValue

Xem thêm về cách gắn `thisBinding` <a href="http://es5.github.io/#x10.4.3" title="Entering Function Code" target="_blank">ở đây</a>.

Để rõ ràng hơn ta xét một số tình huống cụ với việc gọi hàm.

##### 2.3.1. Gọi thông qua ngữ cảnh toàn cục

Trường hợp này `this` sẽ tham chiếu tới đối tượng toàn cục.

```javascript
function mMethod() {
  console.log(this); // đối tượng toàn cục - global object
}

mMethod();

var obj = {
  myMethod: function () {
    return (function () {
      console.log(this); // đối tượng toàn cục
    })();
  },
};

obj.myMethod();
```

##### 2.3.2. Gọi thông qua đối tượng

Trường hợp này `this` sẽ tham chiếu tới đối tượng thisValue - đối tượng tương ứng chứa hàm.

```javascript
// Tạo đối tượng obj
var obj = {
  mMethod: function () {
    console.log(this);
  },
  oMethod: function () {
    console.log("▼ oMethod");
    console.log(this);
    console.log("▲  oMethod");
  },
};

obj.mMethod(); // this sẽ tương ứng với đối tượng obj
obj["oMethod"](); // this sẽ tương ứng với đối tượng obj

// Gắn mMethod cho đối tượng khác
var obj1 = {
  mVal: "I'm obj1",
};
obj1.mMethod = obj.mMethod;

obj1.mMethod(); // this sẽ tương ứng với đối tượng obj1

// Gọi qua khởi tạo đối tượng với từ khoá new
function MyObject(val) {
  this.mVal = val || "I xxx JS";

  this.mMethod = function () {
    console.log(this);
  };
}

var mObj1 = new MyObject();
var mObj2 = new MyObject("I'm object 2");

mObj1.mMethod(); // this sẽ tương ứng với đối tượng mObj1
mObj2.mMethod(); // this sẽ tương ứng với đối tượng mObj2
```

##### 2.3.3. Gọi thông qua một số hàm đặc biệt

Trong JavaScript có xây dựng sẵn một số hàm đặc biệt cho phép ta sử dụng `this` qua đối tượng đầu vào như:

- Function.prototype.apply(thisArg, argArray)
- Function.prototype.call(thisArg[, arg1[ , arg2, ...]])
- Function.prototype.bind( thisArg[, arg1[ , arg2, ...]])
- Array.prototype.every(callback[, thisArg])
- Array.prototype.some(callback[, thisArg])
- Array.prototype.forEach(callback[, thisArg])
- Array.prototype.map(callback[, thisArg])
- Array.prototype.filter(callback[, thisArg])

Bằng việc sử dụng các hàm trên ta có thể thể sử dụng `this` như là giá trị của đối tượng `thisArg`. Việc này rất tiện cho ta thay đổi `thisBinding` một cách chủ động. Ta có thể xem ví dụ sau:

```javascript
var obj = {
  mMethod: function (firstName, lastName) {
    var firstName = firstName || "Vô";
    var lastName = lastName || "Danh";
    console.log("Hello " + firstName + " " + lastName);
    console.log(this);
  },
};

var obj1 = {
  mVal: "I'm obj1",
};

obj.mMethod.apply(obj1); // đối tượng obj1

obj.mMethod.apply(obj1, ["Chí", "Phèo"]); // đối tượng obj1

obj.mMethod.call(obj1, "Thị", "Nở"); // đối tượng obj1
```

Đoạn mã trên sẽ in ra `this` là đối tượng `obj1` chứ không còn là `obj`, do `call` và `apply` đã đẩy trực tiếp `this` qua tham số đầu vào.

### 3. Một số trường hợp dễ nhầm lẫn

#### 3.1. Gọi thông qua ngữ cảnh khác

Ta xét trường hợp sau:

```javascript
var obj = {
  mVal: "Việt Nam",

  mMethod: function () {
    console.log("Hello " + this.mVal);
  },
};

var oMethod = obj.mMethod; // oMethod nằm trong ngữ cảnh toàn cục

oMethod();
```

Khi thực hiện đoạn mã trên kết quả in ra sẽ là `Hello undefined`, vì ta đã đẩy `this` ra đối tượng toàn cục mất rồi. Vậy làm sao để có được đúng kết quả là `Hello Việt Nam`? Để giải quyết được cái này ta sẽ sử dụng hàm `bind` để đẩy giá trị đối tượng `obj` cho biến `this` ở đây như sau:

```javascript
var obj = {
  mVal: "Việt Nam",

  mMethod: function () {
    console.log("Hello " + this.mVal);
  },
};

var oMethod = obj.mMethod.bind(obj); // this trong oMethod sẽ bị ép thành giá trị obj

oMethod();
```

Vì sao lại là `bind` mà không phải là `call` hay `apply`? Vì `bind` sẽ giữ giá trị của `obj` để gọi nhiều lần chứ không chỉ gọi một lần như với `call` hay `apply`. Các bạn có thể đọc thêm <a href="https://dofeet.wordpress.com/2015/03/07/js-apply-call-va-bind-khac-gi-nhau" title="[JS] apply, call và bind khác gì nhau?" target="_blank">ở đây</a>.
Với trường hợp gọi một lần với `call` hoặc `apply` ta có thể cùng nhau xem ví dụ sau:

```javascript
var obj = {
  mVal: "Việt Nam",

  mMethod: function () {
    console.log("Hello " + this.mVal);
  },
};

var obj1 = {
  mVal: "Nhật Bản",
};

obj.mMethod.call(obj1); // in ra là: Hello Nhật Bản
```

Đoạn mã trên sẽ gọi hàm `mMethod` của đối tượng `obj` nhưng `this` trong hàm `mMethod` đã được ép thành đối tượng `obj1`. Với việc gọi 1 lần này ta có thể mượn phương thức `mMethod` của đối tượng `obj` để thực thi cho đối tượng `obj1` mà không cần tạo phương thức này cho đối tượng `obj1`. Cái này khá <em>kool</em> đúng hem ^.^

#### 3.2. Hàm phản hồi - Callback

Gọi thông qua hàm phản hồi cũng chính là một trường hợp của gọi thông qua ngữ cảnh khác vì hàm phản hồi được thực thi trong một ngữ cảnh khác. Ta xét ví dụ sau:

```javascript
var obj = {
  mVal: "Việt Nam",

  mMethod: function () {
    console.log("Hello " + this.mVal);
  },
};

var obj1 = {
  oMethod: function (callback) {
    return callback();
  },
};

obj1.oMethod(obj.mMethod);
```

Vì gọi trong ngữ cảnh của đối tượng `obj1` nên `mMethod` lúc này sẽ lấy giá trị cho `this` là `obj1` chứ không còn là `obj` nữa. Vẫn làm tương tự như phần 3.1, ta sử dụng `bind` để đẩy giá trị ngữ cảnh `obj` vào cho `mMethod` như sau:

```javascript
var obj = {
  mVal: "Việt Nam",

  mMethod: function () {
    console.log("Hello " + this.mVal);
  },
};

var obj1 = {
  oMethod: function (callback) {
    return callback();
  },
};

obj1.oMethod(obj.mMethod.bind(obj));
```

Hoàn hảo, đoạn mã trên đã cho ta kết quả như mong muốn. Đọc tới đây, nhiều bạn thắc mắc sao cần gì phải tách ra 3.1 với 3.2 làm gì cho rắc rối? Tách ra thế này có lợi thế là không bị vướng quá nhiều vấn đề vào cả một cụm, ví hàm phản hồi là một trường hợp rất hay được sử dụng khi lập trình với JavaScript. Ví dụ như trong Nodejs, hàm phản hồi là một thành phần quan trọng, một khái niệm cơ bản nhất cần nắm được để có thể lập trình với Nodejs. Hay nhiều bạn có sử dụng JQuery để làm phía trình duyệt, các sự kiện `click` vào một nút nào đó chẳng hạn, các bạn đều sử dụng luôn được từ khoá `this` ngay trong hàm phản hồi của các nút đó mà không cần quan tâm tới ngữ cảnh thực thi hiện tại là gì cả. Để làm được việc đó, jQuery đều đã `bind` các nút tương ứng đó cho các hàm phản hồi cho các bạn rồi đó.

#### 3.3. Hàm lồng nhau

Ta cùng xét sự nhập nhằng qua ví dụ sau.

```javascript
var obj = {
  mVal: "Việt Nam",

  oVal: {
    oMethod: function (callMe) {
      callMe();
    },
  },

  mMethod: function () {
    this.oVal.oMethod(function () {
      console.log("Hello " + this.mVal);
    });
  },
};

obj.mMethod(); // in ra là: Hello undefined
```

Với đoạn mã trên ta mong muốn nó in ra được giá chỉ của biến mVal trong đối tượng obj nhưng thực tế nó sẽ in ra `Hello undefined`? Nguyên nhân là ngữ cảnh của thực thi ở `console.log` lúc này là đối tượng `oVal` mất rồi. Vậy làm sao ta có thể sử dụng được biến `mVal` của đối tượng `obj`? Muốn làm được như vậy ta cần lấy được ngữ cảnh thực thi của đối tượng `obj` bằng cách nhớ lại ngữ cảnh thực thi thông qua một biến trung gian và sử dụng biến này với ngữ cảnh của đối tượng `oVal`. Ví dụ dưới đây sẽ thực hiện theo ý tưởng này:

```javascript
var obj = {
  mVal: "Việt Nam",

  oVal: {
    oMethod: function (callMe) {
      callMe();
    },
  },

  mMethod: function () {
    var _this = this; // nhớ ngữ cảnh thực thi của obj trong biến _this

    this.oVal.oMethod(function () {
      console.log("Hello " + _this.mVal); // gọi tới ngữ cảnh thực thi của obj
    });
  },
};

obj.mMethod();
```

### 4. Kết luận

Từ khoá `this` hơi rắc rối một chút nên khi lập trình ta cần chú ý tới ngữ cảnh thực thi để sử dụng từ khoá này cho hiệu quả và đúng đắn dựa vào ngữ cảnh gọi nó và kiểu của ngữ cảnh thực thi. Ta cũng cần chú ý hơn ở những đoạn sử dụng tới hàm phản hồi hay hàm lồng nhau. Ngoài ra ta có thể thay đổi được ngữ cảnh thực thi của một đối tượng bằng cách sử dụng `call`, `apply` hoặc `bind` như đã mô tả phía trên.

Về việc sử dụng Call, Apply và Bind cụ thể ra sao thì các bạn đọc thêm ở [bài viết này](https://dofeet.wordpress.com/2015/03/07/js-apply-call-va-bind-khac-gi-nhau/ "[JS] apply, call và bind khác gì nhau?").

Ngoài ra, bạn có thể tham khảo về chuẩn ECMAScript 5.1 <a href="http://es5.github.io" title="Entering Function Code" target="_blank">ở đây</a>.
]]></description>
            <link>https://hungvn.com/blog/javascript-tim-hieu-ve-tu-khoa-this</link>
            <guid isPermaLink="true">https://hungvn.com/blog/javascript-tim-hieu-ve-tu-khoa-this</guid>
            <pubDate>Tue, 10 Jan 2017 19:55:00 GMT</pubDate>
        </item>
    </channel>
</rss>