CSDL_Thực hành (1) - Dữ liệu và CSDL

1. Dữ liệu và CSDL

1.1 Dữ liệu là gì

Trong ngành Công nghệ Thông tin, dữ liệu được hiểu là:

- Một chuỗi gồm một hoặc nhiều ký hiệu (sequence of one or more symbols), như chữ cái, số, ký hiệu đặc biệt (ví dụ: A, 1, $). Đây là cách dữ liệu được biểu diễn ở mức người dùng hoặc mức trừu tượng cao hơn, trước khi máy tính xử lý. Ví dụ, chuỗi "123" hoặc "Xin chào" là dữ liệu dạng ký hiệu mà con người nhập vào hệ thống. Ở mức cơ bản (mức máy tính xử lý), các ký hiệu này sẽ được mã hóa để máy tính hiểu.

- Ở mức lưu trữ thấp nhất (cấp độ phần cứng), mọi dữ liệu trong máy tính đều được biểu diễn bằng bit (binary digits) – tức là 0 và 1. Đây là ngôn ngữ cơ bản mà máy tính sử dụng để lưu trữ và xử lý. Ví dụ: chuỗi "Xin chào” sẽ được mã hóa thành một dãy bit (ví dụ: 01011000  01101001 trong mã ASCII cho chữ "X" và "i"). Tất cả văn bản, hình ảnh, âm thanh cuối cùng đều quy về nhị phân.

- Cần được thông dịch (diễn dịch, xử lý) để trở thành thông tin. Dữ liệu thô (raw data) chỉ là tập hợp ký hiệu hoặc số liệu, không có ý nghĩa cho đến khi được xử lý hoặc diễn dịch để trở thành thông tin (information) – dữ liệu có ngữ cảnh và ý nghĩa. Ví dụ, số "19" là dữ liệu; khi được diễn dịch là "tuổi của bạn", nó trở thành thông tin. Máy tính hoặc con người cần xử lý dữ liệu để hiểu và sử dụng nó.

- Biểu diễn số lượng, tính chất của các đối tượng hoặc chỉ dẫn hoạt động. Ví dụ, biểu diễn số lượng: "5" là số sản phẩm trong kho; biểu diễn tính chất: "đỏ" là màu của một chiếc xe; chỉ dẫn hoạt động: mã lệnh "1010" yêu cầu CPU thực hiện phép cộng.

- Dữ liệu được lưu trữ trên ổ đĩa (HDD, SSD) hoặc các thiết bị khác như RAM, đám mây

- Được tổ chức theo dạng cấu trúc, bán cấu trúc hoặc không cấu trúc.

Xem hình minh họa (dữ liệu được lưu trong máy tính).

Tháp xử lý thông tin

Tháp xử lý thông tin (DIKW Pyramid, hoặc Information Hierarchy) là một mô hình khái niệm phổ biến trong CNTT và quản lý thông tin. Mô hình này mô tả quá trình chuyển đổi từ dữ liệu (data) lên thông tin (information), tri thức (knowledge), và cuối cùng là minh triết/sự khôn ngoan (wisdom).

Trong cuộc sống hàng ngày, dữ liệu quanh ta rất phong phú và ẩn chứa bên dưới nhiều giá trị mà chúng ta ít nhận ra. Từ số bước chân bạn đi mỗi ngày, các giao dịch ngân hàng, đến bài đăng trên mạng xã hội. Tuy nhiên, nếu không được xử lý, nó chỉ là những con số hoặc ký hiệu vô nghĩa, tiềm ẩn giá trị mà con người thường không nhận ra ngay. Ví dụ, hàng triệu giao dịch mua sắm là dữ liệu, nhưng nếu không phân tích, ta không thấy được xu hướng mua hàng nào đang nổi bật.

Do vậy, chúng ta sẽ làm cho máy tính có khả năng lưu trữ và xử lý dữ liệu (data) nhằm tạo ra thông tin (information) có ích; từ đó rút trích ra các tri thức (knowledge) và hỗ trợ cho quá trình ra quyết định (wisdom – minh triết/sự khôn ngoan).

Xem hình minh họa.

Ý nghĩa mỗi tầng của Tháp xử lý thông tin:

- Dữ liệu (Data): nhiều, thô, chưa có ý nghĩa rõ ràng

- Thông tin (Information): dữ liệu được xử lý để có ý nghĩa

- Tri thức (Knowledge): hiểu biết từ thông tin

- Minh triết (Wisdom): áp dụng tri thức vào quyết định thực tế

Ví dụ minh họa:

- Dữ liệu: "50, 60, 70" (nhịp tim đo được trong 3 ngày)

- Thông tin: "nhịp tim trung bình là 60 lần/phút" (máy tính xử lý)

- Tri thức: "nhịp tim tăng dần qua 3 ngày" (phân tích xu hướng)

- Minh triết: "nên đi khám vì nhịp tim bất thường" (quyết định dựa trên tri thức)

1.2 Cơ sở dữ liệu là gì

Hãy tưởng tượng bạn lưu trữ một khối lượng dữ liệu khổng lồ (như số liệu, danh sách, hình ảnh, âm thanh), một cách lộn xộn trong ổ cứng dưới dạng các tập tin riêng lẻ. Hoặc giả sử bạn lưu trữ danh sách hàng ngàn mặt hàng (chưa bán, đã bán), giá cả từng món hàng, và thông tin khách hàng trong các tệp văn bản. Việc tìm kiếm, thêm, xóa hay sửa từng mục trong hàng ngàn dữ liệu như vậy sẽ khó khăn và mất thời gian đến mức nào?

Đây chính là lúc bạn cần một giải pháp để lưu trữ và sử dụng dữ liệu một cách hiệu quả. Giải pháp chính là dùng cơ sở dữ liệu (CSDL). Nó giúp bạn tổ chức dữ liệu ngăn nắp, tìm kiếm nhanh chóng và khai thác thông tin một cách thuận tiện.

Cơ sở dữ liệu (database) là một tập hợp dữ liệu được tổ chức, lưu trữ và quản lý một cách có hệ thống trên máy tính, để bạn có thể dễ dàng truy cập, thêm, sửa, xóa hoặc tìm kiếm thông tin khi cần. Hãy nghĩ về CSDL như một "kho lưu trữ thông minh".

Ưu điểm khi sử dụng cơ sở dữ liệu:

- Giúp người dùng dễ dàng truy cập, quản lý, khai thác và cập nhật thông tin

- Giảm sự trùng lặp thông tin xuống mức thấp nhất

- Có thể truy xuất thông tin theo nhiều cách

- Cho phép nhiều người cùng sử dụng một lúc

- Tăng tính bảo mật cho dữ liệu

- Tăng tính toàn vẹn dữ liệu

- Khả năng mở rộng dễ dàng

1.3 Làm việc với CSDL

Khi làm việc với CSDL, chúng ta quan tâm tới 3 thành phần sau:

- Dữ liệu

- Cách thức tổ chức dữ liệu

- Phần mềm quản lý CSDL

Dữ liệu

Khi làm việc với CSDL, bạn có thể hiểu đơn giản, dữ liệu là tập hợp các thông tin thô (raw facts) được thu thập, lưu trữ và xử lý trong cơ sở dữ liệu. Đây là thành phần cốt lõi, đại diện cho các giá trị thực tế mà hệ thống cần quản lý. Dữ liệu có thể ở dạng số, văn bản, hình ảnh, âm thanh, hoặc bất kỳ định dạng nào khác tùy thuộc vào mục đích sử dụng.

Dữ liệu có một số đặc điểm

- Nguyên bản: chưa qua xử lý hoặc tổ chức thành thông tin có ý nghĩa.

- Đa dạng: có thể là dữ liệu có cấu trúc (structured), bán cấu trúc (semi-structured), hoặc không cấu trúc (unstructured).

- Nguồn gốc: được thu thập từ người dùng, hệ thống, cảm biến, hoặc các nguồn khác.

Ví dụ về dữ liệu:

- Dữ liệu về khách hàng (tên, địa chỉ, số điện thoại).

- Dữ liệu về sản phẩm (tên sản phẩm, giá cả, số lượng).

- Dữ liệu về kết quả học tập của sinh viên (mã sinh viên, điểm số).

Cách thức tổ chức dữ liệu

Khi đã có dữ liệu rồi, chúng ta cần phải có cách thức để tổ chức dữ liệu, nhằm giúp cho việc việc lưu trữ, quản lý và truy xuất được dễ dàng.

Có hai mô hình tổ chức dữ liệu đang được sử dụng phổ biến, gồm:

- Mô hình quan hệ (relational model): dữ liệu được tổ chức dưới dạng các bảng

- Mô hình phi quan hệ (noSQL): dữ liệu được tổ chức dưới dạng phi cấu trúc, hoặc bán cấu trúc như JSON, XML.

Phần mềm quản lý CSDL

Khi đã có cơ sở dữ liệu (CSDL), bao gồm dữ liệu và mô hình tổ chức dữ liệu, chúng ta cần sử dụng các công cụ (phần mềm) để chuyển CSDL vào hệ thống máy tính.

Phần mềm đảm nhận vai trò này được gọi là Phần mềm quản lý CSDL, hay còn được gọi là Hệ quản trị CSDL (Database Management System - DBMS).

Hệ quản trị CSDL (DBMS) là một phần mềm chuyên dụng, cho phép người dùng thực hiện các thao tác như tạo lập, quản lý và truy xuất dữ liệu trong CSDL. DBMS cung cấp các công cụ hỗ trợ định nghĩa cấu trúc dữ liệu, nhập liệu, thực hiện truy vấn dữ liệu, đồng thời đảm bảo tính bảo mật cho dữ liệu được lưu trữ.

Một số DBMS phổ biến:

- MySQL

- PostgreSQL

- Oracle Database

- Microsoft SQL Server

- MongoDB(NoSQL)

1.4 Bài tập

Câu 1.1 Trong lĩnh vực Công nghệ Thông tin, dữ liệu là gì? Phát biểu nào sau đây không đúng?

A. Dữ liệu thô (raw data) đã có ngữ cảnh và ý nghĩa, không cần phải thông dịch (xử lý) để trở thành thông tin.

B. Dữ liệu là một chuỗi gồm một hoặc nhiều ký hiệu, như chữ cái, số, ký hiệu đặc biệt.

C. Ở mức lưu trữ thấp nhất (cấp độ phần cứng), mọi dữ liệu trong máy tính đều được biểu diễn bằng bit (binary digits) – tức là 0 và 1.

D. Dữ liệu được lưu trữ trên ổ đĩa (HDD, SSD) hoặc các thiết bị khác như RAM, đám mây.

Câu 1.2 Cơ sở dữ liệu (database) là gì? Phát biểu nào sau đây không đúng?

A. Cơ sở dữ liệu là một tập hợp dữ liệu được tổ chức, lưu trữ và quản lý một cách có hệ thống trên máy tính.

B. Cơ sở dữ liệu làm tăng sự trùng lặp thông tin lên mức cao nhất.

C. Cơ sở dữ liệu giúp người dùng dễ dàng truy cập, quản lý, khai thác và cập nhật thông tin.

D. Cơ sở dữ liệu cho phép nhiều người cùng sử dụng một lúc.

Câu 1.3 DBMS là gì? Phát biểu nào sau đây không đúng?

A. DBMS là phần mềm cho phép người dùng tạo, quản lý và truy xuất dữ liệu trong CSDL.

B. DBMS cung cấp các công cụ để định nghĩa cấu trúc dữ liệu, nhập dữ liệu, truy vấn dữ liệu và bảo mật dữ liệu.

C. MySQL, PostgreSQL, Oracle Database, Microsoft SQL Server, MongoDB là các ví dụ về DBMS.

D. DBMS chỉ hỗ trợ các mô hình dữ liệu quan hệ, không hỗ trợ mô hình phi quan hệ.

Câu 1.4 Theo “Tháp xử lý thông tin”, quá trình chuyển đổi dữ liệu được thực hiện theo thứ tự nào?

A. Data > Knowledge > Information > Wisdom

B. Information > Data > Knowledge > Wisdom

C. Data > Information  > Wisdom > Knowledge

D. Data > Information > Knowledge > Wisdom

-----

Cập nhật: 11/3/2025

-----

Bài sau:


Web back-end (10) - Hàm callback

Bài trước: Web back-end (9) - Một số chủ đề JavaScript (2)

-----

10. Hàm callback

10.1 Hàm callback là gì

Trong JavaScript, hàm callback là một hàm được truyền vào một hàm khác như một tham số, và sẽ được thực thi sau khi hàm "cha" hoàn thành một tác vụ nào đó. Nói một cách đơn giản, nó là một cách để đảm bảo một đoạn mã được thực thi sau khi một đoạn mã khác hoàn thành.

Hàm callback cũng là một trong ba kỹ thuật được sử dụng để lập trình bất đồng bộ trong JavaScript.

Callback nghĩa là gọi lại.

Các đặc điểm của hàm callback

- Truyền như tham số: callback là một hàm được truyền vào hàm khác để thực thi sau khi một điều kiện hoặc tác vụ hoàn tất.

- Thực thi bất đồng bộ: thường dùng để xử lý các tác vụ không chặn luồng chính (non-blocking), như truy cập thiết bị (đọc/ghi tập tin), gọi API, hoặc trong các hàm hẹn giờ (timer).

- Tính linh hoạt: có thể là hàm ẩn danh (anonymous function), hàm mũi tên (arrow function), hoặc hàm đã được định nghĩa trước (function expression).

- "Callback Hell": nếu lồng quá nhiều callback, mã nguồn có thể trở nên khó đọc và bảo trì. Callback hell thường được giải quyết bằng Promise hoặc async/await.

Một số tính huống có sử dụng hàm callback

- Xử lý sự kiện (event handling): gắn hàm callback để phản hồi hành động của người dùng (ví dụ: click, hover, submit).

- Tác vụ bất đồng bộ: gọi API, đọc/ghi tập tin, hoặc sử dụng trong các hàm hẹn giờ (ví dụ: setTimeout, setInterval).

- Xử lý mảng: sử dụng trong các phương thức như forEach, map, filter, reduce.

- Hoàn thành tác vụ: đảm bảo một đoạn mã chạy sau khi tác vụ khác hoàn tất (ví dụ: tải dữ liệu từ server rồi hiển thị lên giao diện).

- Tùy chỉnh logic: cho phép người dùng truyền logic riêng vào hàm tổng quát.

Một số ví dụ sử dụng hàm callback

Ví dụ 1. Dùng hàm callback trong xử lý sự kiện.

Khi người dùng nhấp vào một nút “Đăng ký”, một sự kiện "click" được kích hoạt. Bạn có thể sử dụng hàm callback để xử lý sự kiện này và thực hiện một hành động nào đó.

[callback1.html]

<!DOCTYPE html>

<html lang="en">

<head>

</head>

<body>

    <button id="dang-ky">Đăng ký</button>

    <script>

        document.getElementById("dang-ky").addEventListener("click", () => {

            alert("Nút đã được bấm!");

        });

    </script>

</body>

</html>

Mở tập tin callback1.html bằng trình duyệt để xem kết quả.

Ví dụ 2. Sử dụng hàm callback trong các hàm hẹn giờ (ví dụ: setTimeout, setInterval).

Khi hàm setTimeout() chạy, nó sẽ đưa luồng xử lý vào trạng thái chờ với thời gian được xác định ở tham số thứ 2 (ví dụ chờ 5000ms = 5 giây). Sau khi hết thời gian chờ, hàm callback sẽ được gọi và thực thi. 

setTimeout(() => {

    console.log("Đã hết 5 giây! (sau 5 giây)");

}, 5000);

console.log("Đang chờ");

Kết quả chạy:

Đang chờ

Đã hết 5 giây! (sau 5 giây)

 

Ví dụ 3. Sử dụng callback trong các phương thức như forEach, map, filter, reduce.

const numbers = [1, 2, 3, 4];

numbers.forEach(num => console.log(num * num));

// Kết quả: 1, 4, 9, 16

Ví dụ 4.  Dùng callback trong gọi API

function getUser(userId, callback) {

    fetch(`https://jsonplaceholder.typicode.com/users/${userId}`)

        .then(response => response.json())

        .then(data => callback(null, data)) // Thành công, gọi callback với dữ liệu

        .catch(error => callback(error, null)); // Lỗi, gọi callback với lỗi

}

 

getUser(1, function(error, user) {

    if (error) {

        console.error("Lỗi:", error);

    } else {

        console.log("Tên người dùng:", user.name);

    }

});

// Kết quả: "Tên người dùng: Leanne Graham"

Ví dụ 5.  Callback tùy chỉnh logic, cho phép người dùng truyền logic riêng vào hàm tổng quát. Hàm callback x => x * x cho phép người dùng tự định nghĩa cách xử lý từng phần tử.

function xuLyMang(arr, callback) {

    for (let i = 0; i < arr.length; i++) {

        arr[i] = callback(arr[i]);

    }

    return arr;

}

 

const numbers = [1, 2, 3];

const binhPhuong = xuLyMang(numbers, x => x * x);

console.log(binhPhuong); // Kết quả: [1, 4, 9]

 

const nhan2 = xuLyMang(numbers, x => x * 2);

console.log(nhan2); // Kết quả: [2, 8, 18]

Ví dụ 6. “Callback hell”, hiện tượng lồng quá nhiều callback dẫn đến mã nguồn khó đọc.

setTimeout(() => { console.log("Bước 1 hoàn tất");

    setTimeout(() => { console.log("Bước 2 hoàn tất");

        setTimeout(() => { console.log("Bước 3 hoàn tất");

        }, 1000);

    },1000);

}, 1000);

Nhược điểm của hàm callback

- Callback Hell: lồng quá nhiều callback dẫn đến mã khó đọc.

- Xử lý lỗi phức tạp: cần kiểm tra lỗi thủ công trong mỗi callback.

- Không trực quan: với các luồng phức tạp, khó theo dõi thứ tự thực thi.

Vì vậy, bạn nên sử dụng Promise và Async/Await thay thế cho kỹ thuật callback.

10.2 Bài tập

Bài tập 10.1 Cài đặt các ví dụ trong bài học.

Câu 10.2 Hàm callback trong JavaScript là gì? Phát biểu nào sau đây không đúng?

A. Hàm callback là một hàm được truyền vào một hàm khác như một tham số.

B. Hàm callback thường được sử dụng để xử lý các tác vụ bất đồng bộ.

C. Hàm callback có thể là hàm ẩn danh, hàm mũi tên hoặc hàm đã được định nghĩa trước.

D. Hàm callback được thực thi ngay lập tức sau khi hàm "cha" bắt đầu thực hiện.

Câu 10.3 Callback hell trong JavaScript là gì? Phát biểu nào sau đây không đúng?

A. Callback hell xảy ra khi có quá nhiều hàm callback lồng nhau, khiến mã nguồn khó đọc và bảo trì.

B. Callback hell thường xuất hiện khi xử lý các tác vụ bất đồng bộ phức tạp.

C. Callback hell là một cách hiệu quả để quản lý các tác vụ bất đồng bộ trong JavaScript.

D. Callback hell có thể được giải quyết bằng Promise hoặc async/await.

-----

Cập nhật: 10/3/2025

Bài sau:

Web back-end (9) - Một số chủ đề JavaScript (2)

Bài trước: Web back-end (8) - Một số chủ đề JavaScript (1)

-----

9. Một số chủ đề JavaScript (2)

Ở phần trước, chúng ta đã tìm hiểu về lập trình đồng bộ trong JavaScript, hàm ẩn danh. Chúng ta sẽ tìm hiểu tiếp một số chủ đề liên quan đến lập trình trong JavaScript.

9.1 Hàm mũi tên (arrow function)

Ở phần trước bạn cũng đã được làm quen với hàm mũi tên, phần này chúng ta sẽ tìm hiểu kỹ hơn.

Hàm mũi tên là một tính năng quan trọng được giới thiệu trong ES6 (ECMAScript 2015). Đây là cách viết hàm ngắn gọn và hiện đại trong JavaScript, thường được dùng trong lập trình bất đồng bộ và các tình huống khác.

Hàm mũi tên là một cách định nghĩa hàm trong JavaScript, thay thế cho cú pháp hàm truyền thống (function declaration/expression). Nó sử dụng ký hiệu => (mũi tên) để kết nối tham số và thân hàm, mang lại sự ngắn gọn và một số đặc tính độc đáo về ngữ nghĩa.

Hàm mũi tên giúp viết mã ngắn hơn, dễ đọc hơn, đặc biệt trong các callback hoặc hàm bất đồng bộ.

Sự khác biệt quan trọng của hàm mũi tên chính là cách xử lý từ khóa this (ngữ cảnh) so với hàm thông thường.

Đặc điểm của hàm mũi tên

- Cú pháp ngắn gọn: do loại bỏ từ khóa function, dấu {} và lệnh return trong một số trường hợp

- Không có this (ngữ cảnh) riêng: this trong hàm mũi tên được kế thừa từ phạm vi bên ngoài (lexical scoping), không bị ràng buộc (bound) như hàm thông thường

- Không có arguments: không tự động tạo biến arguments để truy cập danh sách tham số

- Không thể dùng làm hàm tạo (constructor): không thể gọi với từ khóa new để tạo đối tượng

Cú pháp của hàm mũi tên

Cú pháp chung của hàm mũi tên là sử dụng ký hiệu => (mũi tên) để kết nối tham số và thân hàm.

Có 3 cách để viết hàm mũi tên:

- [1] Không tham số: () => { ... }

- [2] Một tham số: x => { ... } (không cần dấu ngoặc cho một tham số)

- [3] Nhiều tham số: (x, y) => { ... }

Một số ví dụ

[1] Hàm không có tham số

const thongBao = () => {

    console.log("Chưa có thông báo, khi nào có thông báo sẽ thông báo!");

}

 

thongBao();

Tình huống: áp dụng trong hàm setTimeout()

setTimeout(() => {

    console.log("Đã hết 4 giây! (sau 4 giây)");

}, 4000);

console.log("Đang chờ");

[2] Hàm có một tham số: x => { ... }

Không cần dấu ngoặc cho hàm chỉ có một tham số. 

Hàm mũi tên có thể tự động trả về kết quả, mà không cần lệnh return.

const binhPhuong = x => x * x;

console.log(binhPhuong(3)); // 9

Tình huống: áp dụng trong duyệt mảng

const numbers = [1, 2, 3, 4];

numbers.forEach(num => console.log(num * num));

// Kết quả: 1, 4, 9, 16

[3] Nhiều có tham số: (x, y) => { ... }

const cong = (x,y) => x + y;

console.log(cong(2,4)); //6

Do thân hàm chỉ có một dòng lệnh, nên không cần dấu {}. Hàm tự động trả về kết quả, mà không cần lệnh return.

Từ khóa this trong hàm mũi tên

Như đã đề cập, hàm mũi tên không tạo this (biến ngữ cảnh) riêng, mà lấy this từ phạm vi bao quanh.

Ví dụ: 

function Person() {

    this.age = 0;

    setInterval(() => {

        this.age++; // 'this' tham chiếu đến đối tượng Person

        console.log(this.age);

    }, 1000);

}

 

const p = new Person(); // Kết quả: 1, 2, 3, ... (tăng mỗi giây)

Nếu dùng hàm thông thường (function() { ... }), this sẽ trỏ đến setInterval thay vì Person, gây lỗi. Hàm mũi tên khắc phục vấn đề này.

Mặc dù hàm mũi tên có nhiều ưu điểm như trên. Tuy nhiên, hàm mũi tên không phải lúc nào cũng phù hợp. Trong một số trường hợp, chẳng hạn như khi bạn cần sử dụng đối tượng arguments hoặc khi bạn cần sử dụng hàm làm hàm tạo, bạn nên sử dụng hàm truyền thống. Hoặc khi cần sự rõ ràng trong mã nguồn, hãy dùng function thông thường.

9.2 Lập trình bất đồng bộ trong JavaScript

Nhắc lại một chút về lập trình đồng bộ.

Trong JavaScript, lập trình đồng bộ (synchronous programming) là kỹ thuật lập trình mà các lệnh (statements) được thực thi tuần tự, theo thứ tự từ trên xuống dưới. Mỗi lệnh phải hoàn thành trước khi lệnh tiếp theo được thực thi. Điều này có nghĩa là nếu một tác vụ mất nhiều thời gian (như đọc tập tin, gọi API, giao tiếp client-server), thì toàn bộ chương trình sẽ bị "chặn" (blocked) cho đến khi tác vụ đó hoàn tất.

Ví dụ, một chương trình lập trình theo kiểu đồng bộ.

// chặn luồng

function chanLuong(){

    console.log("Bắt đầu tác vụ cần nhiều thời gian xử lý");

    let batDau = Date.now();

    while(Date.now() - batDau < 5000){

        // Giả lập chờ 5 giây bằng vòng lặp

    }

    console.log("Tác vụ chạy 5 giây hoàn tất")

}

 

console.log("Trước khi chạy tác vụ");

chanLuong() // chặn luồng 5 giây

console.log("Sau khi chạy tác vụ");

JavaScript là một ngôn ngữ đơn luồng, nghĩa là nó chỉ có thể thực hiện một tác vụ tại một thời điểm. Nếu một tác vụ mất nhiều thời gian để hoàn thành, mà chúng ta lại lập trình theo kiểu đồng bộ, thì nó sẽ chặn luồng chính và làm cho ứng dụng không phản hồi.

Lập trình bất đồng bộ giải quyết vấn đề này bằng cách cho phép chương trình tiếp tục thực hiện các tác vụ khác, trong khi chờ đợi tác vụ tốn thời gian hoàn thành.

Lập trình bất đồng bộ là gì?

Trong JavaScript, lập trình bất đồng bộ (asynchronous programming) là một mô hình lập trình cho phép chương trình thực hiện nhiều tác vụ cùng lúc mà không cần chờ đợi tác vụ trước đó hoàn thành. Điều này đặc biệt hữu ích khi xử lý các tác vụ tốn thời gian như yêu cầu xử lý qua mạng (gọi API, giao tiếp client-server), đọc/ghi tập tin hoặc tương tác với cơ sở dữ liệu.

Các kỹ thuật lập trình bất đồng bộ

[1] Callback

- Đây là cách tiếp cận truyền thống để xử lý bất đồng bộ trong JavaScript.

- Một callback là một hàm được truyền vào một hàm khác và được thực thi khi tác vụ bất đồng bộ hoàn thành.

- Tuy nhiên, sử dụng quá nhiều callback có thể dẫn đến "callback hell", khiến mã nguồn trở nên khó đọc và khó bảo trì.

[2] Promises

- Promises là một đối tượng đại diện cho kết quả cuối cùng của một tác vụ bất đồng bộ.

- Chúng cung cấp một cách viết mã bất đồng bộ rõ ràng và dễ bảo trì hơn so với callback.

- then() được sử dụng khi thực hiện thành công, catch() được sử dụng khi gặp lỗi.

[3] Async/await:

- Async/await là một cú pháp mới hơn để viết mã bất đồng bộ, được giới thiệu trong ES2017.

- Nó cho phép bạn viết mã bất đồng bộ trông giống như mã đồng bộ, giúp mã trở nên dễ đọc và dễ hiểu hơn.

- async được đặt trước function, await được đặt trước các lời gọi hàm bất đồng bộ.

9.3 Bài tập

Bài tập 9.1 Cài đặt các ví dụ trong bài học.

Câu 9.2: Hàm mũi tên (arrow function) là gì? Phát biểu nào sau đây không đúng về hàm mũi tên?

A. Hàm mũi tên có cú pháp ngắn gọn, giúp viết mã dễ đọc hơn.

B. Hàm mũi tên có this (ngữ cảnh) riêng, không kế thừa từ phạm vi bên ngoài.

C. Hàm mũi tên không thể được dùng làm hàm tạo (constructor).

D. Hàm mũi tên không có biến arguments để truy cập danh sách tham số.

Câu 9.3: Lập trình bất đồng bộ là gì? Phát biểu nào sau đây không đúng về lập trình bất đồng bộ?

A. Lập trình bất đồng bộ cho phép chương trình thực hiện nhiều tác vụ cùng lúc mà không cần chờ đợi tác vụ trước đó hoàn thành.

B. Lập trình bất đồng bộ đặc biệt hữu ích khi xử lý các tác vụ tốn thời gian như yêu cầu mạng, đọc/ghi tập tin hoặc tương tác với cơ sở dữ liệu.

C. Callback là một kỹ thuật bất đồng bộ, nó sẽ làm cho code dễ đọc và dễ bảo trì hơn khi code có nhiều callback lồng nhau.

D. Async/await cho phép viết mã bất đồng bộ trông giống như mã đồng bộ, giúp mã trở nên dễ đọc và dễ hiểu hơn.

-----

Cập nhật: 10/3/2025

-----

Bài sau: Web back-end (10) - Hàm callback

Python thực hành (1) - Tổng quan về lập trình

 1. Tổng quan về lập trình

1.1 Lập trình là gì?

Lập trình là việc bạn viết ra những "lệnh" hoặc "hướng dẫn" để máy tính hiểu và làm theo. Những "lệnh" này được viết bằng một ngôn ngữ đặc biệt mà máy tính có thể hiểu được.

Các ngôn ngữ đặc biệt (mà máy tính có thể hiểu) gọi là ngôn ngữ lập trình, được chia thành 2 nhóm:

- Ngôn ngữ lập trình bậc thấp

- Ngôn ngữ lập trình bậc cao

Ngôn ngữ lập trình bậc thấp

Ngôn ngữ lập trình bậc thấp là loại ngôn ngữ mà máy tính "hiểu" dễ hơn, nhưng con người lại khó đọc và viết hơn. Nó gần với cách máy tính hoạt động, giống như "ngôn ngữ bí mật" của máy tính. Ngôn ngữ này thường dùng các số, ký hiệu hoặc lệnh rất cơ bản.

Ví dụ ngôn ngữ lập trình cấp thấp:

[1] Ngôn ngữ máy (machine language): là ngôn ngữ chỉ dùng số 0 và 1. 

Ví dụ: 01001000 01100101 01101100 01101100 01101111

[2] Hợp ngữ (assembly): cao hơn một chút so với ngôn ngữ máy, dùng từ và ký hiệu ngắn, nhưng vẫn gần với máy tính. 

Ví dụ, lệnh 5 + 3, viết trong Hợp ngữ sẽ là:

MOV AX, 5 

ADD AX, 3

Ngôn ngữ lập trình cấp thấp giúp máy tính xử lý nhanh, nhưng bạn rất khó để đọc, học, hiểu và viết.

Vì vậy, chúng ta sẽ học ngôn ngữ lập trình cấp cao.

Ngôn ngữ lập trình cấp cao

Ngôn ngữ lập trình bậc cao là ngôn ngữ lập trình gần với ngôn ngữ tự nhiên của con người, giúp người lập trình dễ dàng viết và hiểu mã nguồn. 

Ngôn ngữ bậc cao sử dụng sử dụng các từ ngữ và cú pháp quen thuộc, giúp người lập trình tập trung vào việc giải quyết các bài toán, chứ không phải lo lắng về các chi tiết kỹ thuật của phần cứng.

Ví dụ, một số ngôn ngữ lập trình bậc cao: Python, C#, Java, JavaScript, C++

1.2 Chương trình máy tính là gì?

Chương trình máy tính là một tập hợp các lệnh được viết bằng ngôn ngữ lập trình, hướng dẫn máy tính thực hiện một công việc cụ thể.

Một số lệnh phổ biến trong chương trình gồm:

- Nhập số liệu: là việc lấy số liệu từ bàn phím, tập tin, hoặc một thiết bị khác

- Xuất kết quả: là việc hiển thị kết quả lên màn hình hoặc gửi kết quả ra tập tin hoặc một thiết bị khác

- Tính toán: là thực hiện các phép toán cơ bản như cộng, trừ, nhân, chia

- Thực hiện có điều kiện: là kiểm tra một điều kiện cụ thể và thực hiện danh sách câu lệnh tương ứng với điều kiện đó

- Tính lặp: là thực hiện lặp lại công việc nhiều lần, với một vài thay đổi giữa các lần lặp

Chương trình máy tính được lưu trong một hoặc nhiều tập tin, được gọi là tập tin mã nguồn.

Một chương trình máy tính có thể thực hiện công việc đơn giản như hiển thị một dòng chữ trên màn hình, hoặc phức tạp, chẳng hạn như xử lý nghiệp vụ của một ngân hàng hoặc điều khiển một hệ thống tự động.

Ví dụ một số chương trình: 

- Trình duyệt web: cho phép bạn truy cập và xem các trang web trên Internet. Ví dụ: Google Chrome, Mozilla Firefox

- Phần mềm xử lý văn bản: cho phép bạn tạo, chỉnh sửa và lưu trữ các tài liệu văn bản. Ví dụ: Microsoft Word, Google Docs

- Trò chơi điện tử: cho phép bạn tương tác với một thế giới ảo và tham gia vào các hoạt động giải trí. Ví dụ: Khan Academy Kids, Math Land, Minecraft

- Hệ điều hành: là một chương trình máy tính quản lý tài nguyên của máy tính và cung cấp môi trường để các chương trình khác hoạt động. Ví dụ: Windows, macOS, Linux

- Ứng dụng trên điện thoại di động: là chương trình được thiết kế để chạy trên thiết bị di động. Ví dụ: Zalo, Facebook

1.3 Các bước tạo ra một chương trình

Để có một chương trình, cần trải qua 7 bước sau:

[Bước 1] Phân tích bài toán và thiết kế thuật toán

- Trước khi viết bất kỳ dòng mã nào, bạn cần hiểu rõ bài toán cần giải quyết

- Thuật toán là một chuỗi các bước logic để giải quyết bài toán đó

- Bước này rất quan trọng, vì nó quyết định tính hiệu quả và độ chính xác của chương trình

[Bước 2] Lập trình (Coding)

- Đây là bước bạn viết mã nguồn của chương trình bằng một ngôn ngữ lập trình cụ thể (ví dụ: Python, Java, C++)

- Mã nguồn là tập hợp các lệnh mà máy tính có thể hiểu và thực thi

- Người lập trình cần tuân thủ cú pháp và quy tắc của ngôn ngữ lập trình.

[Bước 3] Biên dịch (Compilation) hoặc Thông dịch (Interpretation)

Biên dịch:

- Đối với các ngôn ngữ biên dịch (như C++), mã nguồn được chuyển đổi thành mã máy (machine code) bởi một trình biên dịch (compiler)

- Mã máy là ngôn ngữ mà máy tính có thể hiểu trực tiếp

- Quá trình biên dịch tạo ra một tập tin thực thi (executable file) có thể chạy độc lập

Thông dịch:

- Đối với các ngôn ngữ thông dịch (như Python), mã nguồn được thực thi từng dòng một bởi một trình thông dịch (interpreter)

- Không cần tạo ra tập tin thực thi riêng biệt

[Bước 4] Liên kết (Linking)

- Bước này thường áp dụng cho các ngôn ngữ biên dịch

- Trình liên kết (linker) kết hợp các tập tin mã máy khác nhau (ví dụ: các thư viện) thành một tập tin thực thi hoàn chỉnh

[Bước 5] Thực thi (Execution)

- Đây là bước chạy chương trình

- Máy tính thực thi các lệnh trong mã máy (đối với ngôn ngữ biên dịch) hoặc mã nguồn (đối với ngôn ngữ thông dịch)

[Bước 6] Kiểm thử (Testing) và Gỡ lỗi (Debugging)

- Sau khi chạy chương trình, bạn cần kiểm tra xem chương trình có hoạt động đúng như mong đợi hay không

- Nếu có lỗi, bạn cần gỡ lỗi để tìm và sửa lỗi

- Bước này có thể được lặp lại nhiều lần

[Bước 7] Xuất kết quả

- Chương trình hiển thị kết quả cho người dùng

- Kết quả có thể là văn bản, hình ảnh, âm thanh, hoặc các dạng dữ liệu khác

1.4 Bài tập

Câu 1. Ngôn ngữ lập trình bậc cao là gì? Phát biểu nào sau đây không chính xác?

A. Ngôn ngữ lập trình bậc cao gần gũi với ngôn ngữ tự nhiên của con người.

B. Ngôn ngữ lập trình bậc cao giúp người lập trình tập trung vào giải quyết bài toán hơn là chi tiết phần cứng.

C. Ngôn ngữ lập trình bậc cao sử dụng các lệnh số 0 và 1 để giao tiếp trực tiếp với máy tính.

D. Python, Java, và JavaScript là các ví dụ về ngôn ngữ lập trình bậc cao.

Câu 2. Chương trình máy tính là gì? Phát biểu nào sau đây không chính xác?

A. Chương trình máy tính là một tập hợp các lệnh được viết bằng ngôn ngữ lập trình.

B. Chương trình máy tính hướng dẫn máy tính thực hiện một công việc cụ thể.

C. Chương trình máy tính chỉ có thể thực hiện các công việc đơn giản như hiển thị một dòng chữ.

D. Chương trình máy tính có thể được lưu trữ trong một hoặc nhiều tập tin mã nguồn.

Câu 3. Các bước để có một chương trình là gì? Phát biểu nào sau đây không đúng?

A. Bước đầu tiên là phân tích bài toán và thiết kế thuật toán, giúp xác định tính hiệu quả của chương trình.

B. Đối với ngôn ngữ thông dịch, cần phải thực hiện bước liên kết (linking) để tạo ra tập tin thực thi.

C. Lập trình là bước viết mã nguồn bằng ngôn ngữ lập trình, đòi hỏi tuân thủ cú pháp.

D. Kiểm thử và gỡ lỗi là bước quan trọng để đảm bảo chương trình hoạt động đúng như mong đợi.

Câu 4. Liệt kê 10 ngôn ngữ lập trình bậc cao phổ biến.

-----

Cập nhật: 8/3/2025

-----

Bài sau: