Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Promise trong JavaScript

Khái niệm

Promise (ES2015) đại diện cho giá trị sẽ có trong tương lai (async operation). 3 trạng thái:

  • Pending: Đang chờ
  • Fulfilled/Resolved: Thành công, có value
  • Rejected: Thất bại, có reason (error)

Ví dụ: Fetch users với Promise

<!DOCTYPE html>
<html lang="vi">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JavaScript Promises</title>
    <style>
        body { font-family: 'Segoe UI', sans-serif; padding: 20px; }
        .sample { font-size: 14px; font-weight: 500; color: #d32f2f; margin: 15px 0; padding: 15px; background: #ffebee; border-radius: 4px; max-height: 300px; overflow: auto; }
        button { padding: 10px 20px; background: #1976d2; color: white; border: none; border-radius: 4px; cursor: pointer; }
        .loading { color: #1976d2; }
        .error { color: #c62828; }
    </style>
</head>
<body>
    <h1>JavaScript Promises</h1>
    <div class="sample" id="sample"></div>
    <button id="btn">FETCH USERS (Promise)</button>
    <h3>Nhấn nút để lấy danh sách user từ API</h3>

    <script>
        const sampleEle = document.getElementById('sample');
        const btn = document.getElementById('btn');

        btn.addEventListener('click', () => {
            sampleEle.textContent = 'Đang tải...';
            sampleEle.className = 'sample loading';
            
            fetch('https://jsonplaceholder.typicode.com/users')
                .then(response => {
                    if (!response.ok) throw new Error(`HTTP ${response.status}`);
                    return response.json();
                })
                .then(users => {
                    sampleEle.className = 'sample';
                    sampleEle.innerHTML = users.map(u => 
                        `👤 ${u.name} (@${u.username}) - ${u.email}`
                    ).join('
'); }) .catch(err => { sampleEle.className = 'sample error'; sampleEle.textContent = `❌ Lỗi: ${err.message}`; }); }); </script> </body>

Kết quả

Hiển thị danh sách 10 users từ API giả lập.

Tạo Promise

// Constructor
const promise = new Promise((resolve, reject) => {
    // Async work
    setTimeout(() => {
        const success = Math.random() > 0.5;
        if (success) resolve('Thành công!');
        else reject(new Error('Thất bại!'));
    }, 1000);
});

// Static methods
Promise.resolve(42);           // Resolved promise
Promise.reject(new Error('err')); // Rejected promise

// Promise.all - tất cả thành công
Promise.all([p1, p2, p3])
    .then(([r1, r2, r3]) => ...)
    .catch(err => ...); // Fail fast - 1 reject thì catch

// Promise.allSettled - chờ tất cả xong
Promise.allSettled([p1, p2, p3])
    .then(results => {
        results.forEach((r, i) => {
            if (r.status === 'fulfilled') console.log(i, r.value);
            else console.log(i, r.reason);
        });
    });

// Promise.race - nhanh nhất thắng
Promise.race([fetchWithTimeout(5000), slowRequest()])
    .then(result => ...);

// Promise.any - thành công đầu tiên (ES2021)
Promise.any([p1, p2, p3])
    .then(firstSuccess => ...)
    .catch(err => ...); // AggregateError nếu tất cả fail

Async/Await (Syntax Sugar)

async function fetchUsers() {
    try {
        const response = await fetch('https://jsonplaceholder.typicode.com/users');
        if (!response.ok) throw new Error(`HTTP ${response.status}`);
        const users = await response.json();
        return users;
    } catch (error) {
        console.error('Lỗi:', error);
        throw error;
    }
}

// Gọi
fetchUsers().then(users => console.log(users));

Promise Chaining vs Async/Await

Khía cạnhPromise ChainAsync/Await
Đọc hiểuKhó với logic phức tạpDễ, như code đồng bộ
Error handling.catch() ở cuốitry/catch block
DebugStack trace khó theo dõiStack trace rõ ràng
ParallelPromise.all tự nhiênCần Promise.all thủ công
Top-level awaitKhôngModule (type="module")

Anti-patterns cần tránh

// ❌ Promise constructor anti-pattern
const p = new Promise((resolve, reject) => {
    fetch(url).then(resolve).catch(reject);
});

// ✅ Đơn giản
const p = fetch(url);

// ❌ Sequential await không cần thiết
const user = await fetchUser(id);
const posts = await fetchPosts(id); // Không phụ thuộc user!

// ✅ Parallel
const [user, posts] = await Promise.all([fetchUser(id), fetchPosts(id)]);