Callback hell là gì và cách ngăn chặn năm 2024

JavaScript là đồng bộ. Điều này có nghĩa là nó sẽ thực thi code của bạn theo thứ tự sau khi hoiting. Trước khi code thực thi, các khai báo

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

9 và

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

0 được "đẩy" lên phía trên cùng scope (phạm vi) của chúng.

Đây là ví dụ về code đồng bộ:

console.log('1') console.log('2') console.log('3')

Đoạn code này chắc này chắc chắn sẽ in ra "1 2 3".

Các request bất đồng bộ sẽ chờ timer kết thúc (setTimeout) hoặc request được đáp trả, trong khi phần còn lại của code tiếp tục được thực thi. Sau đó, khi đến thời điểm callback sẽ đưa các request bất đồng bộ vào hoạt động.

Đây là một ví dụ về code bất đồng bộ:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

Đoạn code trên sẽ in ra "1 3 2", trong đó "2" ở trong hàm

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

1, cái sẽ chỉ thực thi sau 2 giây. Ứng dụng của bạn sẽ không chờ cho đến khi 2 giây kết thúc. Thay vào đó nó sẽ tiếp tục thực thi phần còn lại của code và khi timeout kết thúc nó sẽ quay trở lại để thực thi hàm

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

2.

Bạn có thể hỏi "Tại sao điều này lại hữu ích?" hay "Làm thế nào tôi biến code bất đồng bộ (async) thành đồng bộ (sync)?". Hi vọng rằng tôi sẽ cho bạn thấy câu trả lời.

Vấn đề

Mục tiêu của chúng ta là tìm kiếm một người dùng GitHub và lấy tất cả các repo (kho) của người đó. Và bởi vì chúng ta không biết chính xác tên người dùng. Vì thế chúng ta liệt kê tất cả người dùng có tên tương tự nhau và các repo tương ứng. Như thế này:

Callback hell là gì và cách ngăn chặn năm 2024

Trong những ví dụ này, chúng ta sẽ sử dụng XHR (XMLHttpRequest). Bạn có thể thay thế nó với jQuery

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

3 hoặc một hướng tiếp cập tự nhiên hơn gọi là

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

4. Tất cả sẽ cho bạn các promise ở đầu ra.

Đoạn code dưới đây sẽ thay đổi một chút phụ thuộc và hướng tiếp cận của bạn, nhưng bắt đầu sẽ như thế này:

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

Hãy nhớ rằng, trong những ví dụ này phần quan trọng không phải là kết quả cuối cùng của code. Thay vào đó, mục tiêu của bạn là phải hiểu được sự khác biệt của các cách tiếp cận và cách bạn có thể tận dụng chúng cho công việc của mình.

Callback

Bạn có thể lưu một hàm trong một biến khi sử dụng JavaScript. Sau đó, sử dụng chúng như các tham số của một hàm khác để thực thi sau đó. Đây chính là "callback".

Một ví dụ sẽ là:

// Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi. doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

Sử dụng

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

5 cho phép chúng ta làm một số thứ với hàm

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

6 đã định nghĩa trước đó:

function request(url, callback) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   callback(null, xhr.response)  
  } else {  
   callback(xhr.status, null)  
  }  
}  
} xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

Hàm request sẽ có thêm một tham số

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

5, và khi một

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

6 được tạo nó sẽ được gọi trong cả 2 trường hợp lỗi hoặc thành công.

const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users request(userGet, function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, function handleReposList(err, repos) {  
  if (err) throw err  
  // Handle the repositories list here  
})  
}) })

Phân tích:

  • Chúng tạo một request để lấy danh sách người dùng
  • Sau khi request hoàn thành chúng ta sử dụng hàm callback // url argument can be something like 'https://api.github.com/users/daspinola/repos'

    function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       // Code here for the server answer when successful  
      } else {  
       // Code here for the server answer when not successful  
      }  
    }  
    
    } xhr.ontimeout = function () {
    // Well, it took to long do some code here to handle that  
    
    } xhr.open('get', url, true) xhr.send(); }

    9
  • Nếu không có lỗi chúng ta sẽ phân tích kết quả trả về từ server sử dụng // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    0
  • Sau đó lặp qua danh sách người dùng khi nó lớn hơn 1. Với mỗi người dùng chúng ta yêu cầu danh sách các repo của họ. Chúng ta sẽ sử dụng url là giá trị của // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    1 trong mỗi đối tượng

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    2.
  • Khi request hoàn thành callback sẽ được gọi. Nó sẽ xử lý lỗi hoặc kết quả trả về là danh sách các repo.

Lưu ý: Sử dụng

// Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi. doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

3 như là tham số đầu tiên của callback là một quy ước khá phổ biến, đặc biệt khi sử dụng Node.js.

Một hướng tiếp cần "hoàn chỉnh" và dễ đọc hơn sẽ có một vài hàm xử lý lỗi. Chúng ta cũng tách callback ra khỏi hàm request. Giống như thế này:

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, handleReposList)  
}) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

Đoạn code này có vấn đề là bạn không thể điều khiển thứ tự nhận danh sách repo của người dùng. Chúng ta đang yêu cầu thông tin cho tất cả người dùng trong trường hợp có nhiều hơn 1. Và không thể quyết định được thứ tự sẽ nhận. Ví dụ, danh sách repo của người dùng thứ 10 có thể nhận được đầu tiên và người dùng thứ 2 thì nhận được cuối cùng. Có một giải pháp khả thi cho vấn đề này sẽ được đề cập ở phần sau.

Vấn đề chính với callbacks là việc bảo trì và tính dễ đọc. Đây được gọi là callback hell, cái có thể tránh được với cách tiếp cận ở phần tiếp theo.

Callback hell là gì và cách ngăn chặn năm 2024

Hình ảnh lấy từ [đây](https://medium.com/@sagish/node-with-benefits-using-coffeescript-in-your-stack-e9754bf58668)

Promies

Promises có thể làm cho code của bạn dễ đọc hơn. Một lập trình viên mới có thể xem code base và thấy rõ thứ tự thực thi của code.

Để tạo một promise bạn có thể sử dụng:

const myPromise = new Promise(function(resolve, reject) { // code here if (codeIsFine) {

resolve('fine')  
} else {
reject('error')  
} }) myPromise .then(function whenOk(response) {
console.log(response)  
return response  
}) .catch(function notOk(err) {
console.error(err)  
})

Hãy phân tích đoạn code trên:

  • Một promise được khởi tạo với hàm với 2 tham số // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    4 và

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    5
  • Đặt code bất đồng bộ bên trong hàm // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    6. Gọi hàm

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    4 khi mọi thứ hoạt động như mong muốn. Ngược lại gọi

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    5
  • Khi một // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    4 được tìm thấy phương thức

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0 được thực thi. Khi một

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    5 được tìm thấy

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    2 được kích hoạt.

Những điều cần ghi nhớ:

  • // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    4 và

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    5 chỉ chấp nhận một tham số.

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    5 sẽ chỉ gửi 'yey' tới

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0
  • Nếu nối chuỗi nhiều function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0. Bạn nên thêm một

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    8 tại cuối mỗi callback tương ứng với chúng.
  • Khi một // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    5 xảy ra

    const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users

    request(userGet, function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, function handleReposList(err, repos) {  
      if (err) throw err  
      // Handle the repositories list here  
    })  
    
    }) })

    0 sẽ được thực thi, nếu bạn có một

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0 đã được nối đằng sau

    const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users

    request(userGet, function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, function handleReposList(err, repos) {  
      if (err) throw err  
      // Handle the repositories list here  
    })  
    
    }) })

    0. Nó sẽ vẫn thực thi

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0 đó.
  • Với một chuỗi function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0 nếu lỗi xảy ra trên hàm đầu tiên. Nó sẽ bỏ qua chuỗi

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0 đằng sau cho đến khi tìm thấy một

    function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    2
  • Một promise có 3 trạng thái
    • pending khi nó đang chờ // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

      doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() {

       console.log('and then this')  
      
      } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) {
       console.log('this first');  
       callback()  
      
      }

      4 hoặc

      // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

      doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() {

       console.log('and then this')  
      
      } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) {
       console.log('this first');  
       callback()  
      
      }

      5 xảy ra
    • resolved
    • rejected
  • Khi trong trạng thái const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users

    request(userGet, function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, function handleReposList(err, repos) {  
      if (err) throw err  
      // Handle the repositories list here  
    })  
    
    }) })

    9 hoặc

    try {

    request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, handleReposList)  
    
    }) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

    0. Nó không thể thay đổi.

Lưu ý: Bạn có thể tạo ra các promise mà không cần thực thi ngay tại thời điểm khai báo.

Hãy sử dụng ví dụ request với một promise để minh họa

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

Trong trường hợp này khi bạn thực thi

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

6 nó sẽ trả về như thế này:

Callback hell là gì và cách ngăn chặn năm 2024

Một promise đang chờ resolved hoặc rejected

const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users const myPromise = request(userGet) console.log('will be pending when logged', myPromise) myPromise .then(function handleUsersList(users) {

console.log('when resolve is found it comes here with the response, in this case users ', users)
const list = JSON.parse(users).items  
return Promise.all(list.map(function(user) {  
  return request(user.repos_url)  
}))  
}) .then(function handleReposList(repos) {
console.log('All users repos in an array', repos)  
}) .catch(function handleErrors(error) {
console.log('when a reject is executed it will come here ignoring the then statement ', error)  
})

Đây là cách chúng ta xử lý thứ tự kết quả trả về và một vài vấn đề xử lý lỗi. Code vẫn còn hơi phức tạp. Nhưng đó là một cách để cho bạn thấy rằng cách tiếp cận này cũng có thể tạo ra các vấn đề gây khó đọc.

Chúng ta có thể sửa nhanh để tách các callback ra như thế này:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

0

Bằng cách nhìn vào chuỗi

function request(url, callback) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   callback(null, xhr.response)  
  } else {  
   callback(xhr.status, null)  
  }  
}  
} xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

0 đằng sau

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, handleReposList)  
}) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

3 bạn có thể biết được cái chúng ta mong đợi từ đoạn code này. Mọi thứ đều có nhiệm vụ riêng.

Đây chỉ là "bề nổi" về Promises. Để có một cái nhìn sâu sắc về cách chúng làm việc tôi khuyên bạn nên đọc thêm bài viết này.

Generators

Một hướng tiếp cận khác là sử dụng generators. Phần này hơi nâng cao một chút vì thế nếu mới bắt đầu có thể thoải mái bỏ qua phần này.

Generators cho phép bạn viết code bất đồng bộ giống như đồng bộ.

Chúng được biểu diễn bằng dấu

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, handleReposList)  
}) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

4 trong một hàm như thế này:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

1

Thay vì trả lại với câu lệnh

function request(url, callback) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   callback(null, xhr.response)  
  } else {  
   callback(xhr.status, null)  
  }  
}  
} xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

8, generators có một câu lệnh

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, handleReposList)  
}) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

6. Nó dừng thực thi hàm cho đến khi một phương thức

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, handleReposList)  
}) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

7 được gọi. Tương tự với

function request(url, callback) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   callback(null, xhr.response)  
  } else {  
   callback(xhr.status, null)  
  }  
}  
} xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

0 của promise chỉ thực thi khi resoled được trả lại.

Hàm request của chúng ta sẽ trông như thế này:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

2

Chúng ta muốn

try { request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

request(user.repos_url, handleReposList)  
}) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

9 như một tham số. Nhưng thay vì thực thi request ngay lập tức, chúng ta chỉ muốn khi có một callback để xử lý kết quả trả về (response).

const myPromise = new Promise(function(resolve, reject) { // code here if (codeIsFine) {

resolve('fine')  
} else {
reject('error')  
} }) myPromise .then(function whenOk(response) {
console.log(response)  
return response  
}) .catch(function notOk(err) {
console.error(err)  
})

0 sẽ như thế này:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

3

Nó sẽ:

  • Chờ cho đến khi // url argument can be something like 'https://api.github.com/users/daspinola/repos'

    function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       // Code here for the server answer when successful  
      } else {  
       // Code here for the server answer when not successful  
      }  
    }  
    
    } xhr.ontimeout = function () {
    // Well, it took to long do some code here to handle that  
    
    } xhr.open('get', url, true) xhr.send(); }

    6 được chuẩn bị
  • Chấp nhận một tham số try {

    request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, handleReposList)  
    
    }) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

    9 và trả lại

    // url argument can be something like 'https://api.github.com/users/daspinola/repos'

    function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       // Code here for the server answer when successful  
      } else {  
       // Code here for the server answer when not successful  
      }  
    }  
    
    } xhr.ontimeout = function () {
    // Well, it took to long do some code here to handle that  
    
    } xhr.open('get', url, true) xhr.send(); }

    0 với tham số là một

    // url argument can be something like 'https://api.github.com/users/daspinola/repos'

    function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       // Code here for the server answer when successful  
      } else {  
       // Code here for the server answer when not successful  
      }  
    }  
    
    } xhr.ontimeout = function () {
    // Well, it took to long do some code here to handle that  
    
    } xhr.open('get', url, true) xhr.send(); }

    5
  • Nhận const myPromise = new Promise(function(resolve, reject) {

    // code here if (codeIsFine) {

    resolve('fine')  
    
    } else {
    reject('error')  
    
    } }) myPromise .then(function whenOk(response) {
    console.log(response)  
    return response  
    
    }) .catch(function notOk(err) {
    console.error(err)  
    
    })

    5 để gửi tới

    try {

    request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, handleReposList)  
    
    }) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

    7 tiếp theo
  • Lặp qua const myPromise = new Promise(function(resolve, reject) {

    // code here if (codeIsFine) {

    resolve('fine')  
    
    } else {
    reject('error')  
    
    } }) myPromise .then(function whenOk(response) {
    console.log(response)  
    return response  
    
    }) .catch(function notOk(err) {
    console.error(err)  
    
    })

    5
  • Chờ try {

    request(userGet, handleUsersList) } catch (e) { console.error('Request boom! ', e) } function handleUsersList(error, users) { if (error) throw error const list = JSON.parse(users).items list.forEach(function(user) {

    request(user.repos_url, handleReposList)  
    
    }) } function handleReposList(err, repos) { if (err) throw err // Xử lý danh sách repo ở đây console.log('My very few repos', repos) }

    7 cho mỗi

    const myPromise = new Promise(function(resolve, reject) {

    // code here if (codeIsFine) {

    resolve('fine')  
    
    } else {
    reject('error')  
    
    } }) myPromise .then(function whenOk(response) {
    console.log(response)  
    return response  
    
    }) .catch(function notOk(err) {
    console.error(err)  
    
    })

    5
  • Trả lại hàm callback tương ứng với chúng

Đoạn code để thực thi sẽ như thế này:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

4

Bạn sẽ thấy đoạn code này có những vấn đề tương tự callback hell.

Giống như async/await, một trình biên dịch được khuyến khích. Bởi vì nó không được hỗ trợ trong các trình duyệt cũ.

Ngoài ra, theo kinh nghiệm của tôi generators không phổ biến. Vì thế có thể phát sinh nhầm lẫm trong code base được bảo dưỡng bởi nhiều lập trình viên khác nhau.

Cách generators làm việc có thể được tìm thấy trong bài viết này và đây là một tài nguyên khác.

Async/Await

Phương thức này giống như pha trộn generators với promises. Bạn chỉ cần khai báo function nào là

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

0. Và phần nào trong code sẽ có

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

1 để

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

2 kết thúc.

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

5

Trong kịch bản này:

  • Chúng ta có function request(url) {

    return new Promise(function (resolve, reject) {

    const xhr = new XMLHttpRequest();  
    xhr.timeout = 2000;  
    xhr.onreadystatechange = function(e) {  
      if (xhr.readyState === 4) {  
        if (xhr.status === 200) {  
          resolve(xhr.response)  
        } else {  
          reject(xhr.status)  
        }  
      }  
    }  
    xhr.ontimeout = function () {  
      reject('timeout')  
    }  
    xhr.open('get', url, true)  
    xhr.send();  
    
    }) }

    3 là một hàm async
  • Chúng ta chờ // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    4 hoặc

    // Thực thi hàm "doThis" với tham số là một hàm khác, trong trường hợp này là "andThenThis". doThis sẽ thực thi ở bất kỳ đau trong code và khi nó kết thúc hàm "andThenThis" sẽ được thực thi.

    doThis(andThenThis) // Bên trong "doThis" nó được tham chiếu như "callback", cái chỉ là một biến lưu giữ tham chiếu tới hàm này. function andThenThis() { console.log('and then this') } // Bạn có thể sử dụng bất cứ tên nào bạn muốn, nhưng "callback" được sử dụng phổ biến nhất. function doThis(callback) { console.log('this first'); callback() }

    5 cho hàm promise

    // url argument can be something like 'https://api.github.com/users/daspinola/repos'

    function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       // Code here for the server answer when successful  
      } else {  
       // Code here for the server answer when not successful  
      }  
    }  
    
    } xhr.ontimeout = function () {
    // Well, it took to long do some code here to handle that  
    
    } xhr.open('get', url, true) xhr.send(); }

    2
  • Nó sẽ chỉ kết thúc trong function request(url, callback) {

    const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

    if (xhr.readyState === 4) {  
      if (xhr.status === 200) {  
       callback(null, xhr.response)  
      } else {  
       callback(xhr.status, null)  
      }  
    }  
    
    } xhr.ontimeout = function () { console.log('Timeout') } xhr.open('get', url, true) xhr.send(); }

    0 khi

    function request(url) {

    return new Promise(function (resolve, reject) {

    const xhr = new XMLHttpRequest();  
    xhr.timeout = 2000;  
    xhr.onreadystatechange = function(e) {  
      if (xhr.readyState === 4) {  
        if (xhr.status === 200) {  
          resolve(xhr.response)  
        } else {  
          reject(xhr.status)  
        }  
      }  
    }  
    xhr.ontimeout = function () {  
      reject('timeout')  
    }  
    xhr.open('get', url, true)  
    xhr.send();  
    
    }) }

    1 kết thúc.

Áp dụng vào hàm

// url argument can be something like 'https://api.github.com/users/daspinola/repos' function request(url) { const xhr = new XMLHttpRequest(); xhr.timeout = 2000; xhr.onreadystatechange = function(e) {

if (xhr.readyState === 4) {  
  if (xhr.status === 200) {  
   // Code here for the server answer when successful  
  } else {  
   // Code here for the server answer when not successful  
  }  
}  
} xhr.ontimeout = function () {
// Well, it took to long do some code here to handle that  
} xhr.open('get', url, true) xhr.send(); }

6 chúng ta sẽ để nó như một

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

2 đã thấy trước đó:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

6

Chúng ta tạo hàm

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

0 với các

function request(url) { return new Promise(function (resolve, reject) {

const xhr = new XMLHttpRequest();  
xhr.timeout = 2000;  
xhr.onreadystatechange = function(e) {  
  if (xhr.readyState === 4) {  
    if (xhr.status === 200) {  
      resolve(xhr.response)  
    } else {  
      reject(xhr.status)  
    }  
  }  
}  
xhr.ontimeout = function () {  
  reject('timeout')  
}  
xhr.open('get', url, true)  
xhr.send();  
}) }

1 như thế này:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

7

Bây giờ chúng ta có một hàm async

const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users const myPromise = request(userGet) console.log('will be pending when logged', myPromise) myPromise .then(function handleUsersList(users) {

console.log('when resolve is found it comes here with the response, in this case users ', users)
const list = JSON.parse(users).items  
return Promise.all(list.map(function(user) {  
  return request(user.repos_url)  
}))  
}) .then(function handleReposList(repos) {
console.log('All users repos in an array', repos)  
}) .catch(function handleErrors(error) {
console.log('when a reject is executed it will come here ignoring the then statement ', error)  
})

3, cái sẽ xử lý các request. Một hàm async là cần thiết trong

const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users const myPromise = request(userGet) console.log('will be pending when logged', myPromise) myPromise .then(function handleUsersList(users) {

console.log('when resolve is found it comes here with the response, in this case users ', users)
const list = JSON.parse(users).items  
return Promise.all(list.map(function(user) {  
  return request(user.repos_url)  
}))  
}) .then(function handleReposList(repos) {
console.log('All users repos in an array', repos)  
}) .catch(function handleErrors(error) {
console.log('when a reject is executed it will come here ignoring the then statement ', error)  
})

4 vì chúng ta có danh sách

const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users const myPromise = request(userGet) console.log('will be pending when logged', myPromise) myPromise .then(function handleUsersList(users) {

console.log('when resolve is found it comes here with the response, in this case users ', users)
const list = JSON.parse(users).items  
return Promise.all(list.map(function(user) {  
  return request(user.repos_url)  
}))  
}) .then(function handleReposList(repos) {
console.log('All users repos in an array', repos)  
}) .catch(function handleErrors(error) {
console.log('when a reject is executed it will come here ignoring the then statement ', error)  
})

5 của mỗi người dùng.

Chúng ta gọi hàm

const userGet = https://api.github.com/search/users?page=1&q=daspinola&type=Users const myPromise = request(userGet) console.log('will be pending when logged', myPromise) myPromise .then(function handleUsersList(users) {

console.log('when resolve is found it comes here with the response, in this case users ', users)
const list = JSON.parse(users).items  
return Promise.all(list.map(function(user) {  
  return request(user.repos_url)  
}))  
}) .then(function handleReposList(repos) {
console.log('All users repos in an array', repos)  
}) .catch(function handleErrors(error) {
console.log('when a reject is executed it will come here ignoring the then statement ', error)  
})

3:

console.log('1') setTimeout(function afterTwoSeconds() { console.log('2') }, 2000) console.log('3')

8

Phương pháp này và promises là những phương pháp yêu thích của tôi vì chúng dễ đọc và dễ thay đổi. Bạn có thể đọc nhiều hơn về async/await ở đây.

Một nhược điểm của việc sử dụng async/await là chúng không được hỗ trợ trong các trình duyệt cũ ở phía front-end. Ở phía back-end bạn phải sử dụng Node 8 trở lên.

Bạn có thể sử dụng một trình biên dịch như babel để giải quyết vấn đề này.

Giải pháp

Bạn có thể xem source code sử dụng async/await ở đây.

Bạn cũng có thể tự thử những cách khác nhau đã được đề cập trong bài viết này.

Kết luận

Tùy thuộc vào từng tình huống mà bạn có thể sử dụng:

  • async/await
  • callbacks
  • hỗn hợp

Nó phụ thuộc vào mục đích của bạn. Và cái nào sẽ dễ hiểu với những người khác và với chính bạn trong tương lai để có thể dễ dàng bảo trì code.

Đọc thêm

https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html

https://codeburst.io/generators-in-javascript-1a7f9f884439

https://ponyfoo.com/articles/understanding-javascript-async-await

http://chrisbuttery.com/articles/synchronous-asynchronous-javascript-with-es6-generators/

https://medium.com/codebuddies/getting-to-know-asynchronous-javascript-callbacks-promises-and-async-await-17e0673281ee