Hiểu những lời hứa về JavaScript

Lời hứa là một cách để xử lý mã không đồng bộ trong JavaScript mà không cần viết quá nhiều lệnh gọi lại trong mã của bạn.

Giới thiệu về lời hứa

Một lời hứa thường được định nghĩa làproxy cho một giá trị cuối cùng sẽ trở nên khả dụng.

Lời hứa là một cách để xử lý mã không đồng bộ mà không cần viết quá nhiều lệnh gọi lại trong mã của bạn.

Mặc dù chúng đã tồn tại trong nhiều năm, nhưng chúng đã được tiêu chuẩn hóa và giới thiệu trongES2015và bây giờ chúng đã được thay thế trongES2017bởichức năng không đồng bộ.

Hàm không đồng bộsử dụng API Promise làm khối xây dựng của chúng, vì vậy hiểu chúng là điều cơ bản ngay cả khi trong mã mới hơn, bạn có thể sẽ sử dụng các hàm không đồng bộ thay vì các hứa hẹn.

Tóm lại, lời hứa hoạt động như thế nào

Khi một lời hứa đã được gọi, nó sẽ bắt đầu trongtrạng thái đang chờ xử lý. Điều này có nghĩa là hàm người gọi tiếp tục quá trình thực thi, trong khi nó đợi lời hứa thực hiện xử lý riêng và cung cấp cho hàm người gọi một số phản hồi.

Tại thời điểm này, hàm người gọi đợi nó trả về lời hứa trongtrạng thái đã giải quyết, hoặc trong mộttrạng thái bị từ chối, nhưngchức năng tiếp tục thực hiện trong khi lời hứa hoạt động.

Lời hứa sử dụng API JS nào?

Ngoài mã và mã thư viện của riêng bạn, các hứa hẹn được sử dụng bởi các API Web hiện đại tiêu chuẩn như:

Không chắc trong JavaScript hiện đại, bạn sẽ thấy mìnhkhông phảisử dụng các lời hứa, vì vậy chúng ta hãy bắt đầu đi sâu vào chúng.


Tạo một lời hứa

API Promise hiển thị một phương thức khởi tạo Promise mà bạn khởi tạo bằng cách sử dụngnew Promise():

let done = true

const isItDoneYet = new Promise((resolve, reject) => { if (done) { const workDone = ‘Here is the thing I built’ resolve(workDone) } else { const why = ‘Still working on something else’ reject(why) } })

Như bạn có thể thấy lời hứa kiểm tradonebiến toàn cục và nếu điều đó đúng, chúng tôi trả về một lời hứa đã giải quyết, nếu không thì một lời hứa bị từ chối.

Sử dụngresolverejectchúng ta có thể trả về một giá trị, trong trường hợp trên, chúng ta chỉ trả về một chuỗi, nhưng nó cũng có thể là một đối tượng.


Thực hiện một lời hứa

Trong phần trước, chúng tôi đã giới thiệu cách tạo một lời hứa.

Bây giờ chúng ta hãy xem lời hứa có thể như thế nàotiêu thụhoặc đã qua sử dụng.

const isItDoneYet = new Promise()
//...

const checkIfItsDone = () => {
  isItDoneYet
    .then(ok => {
      console.log(ok)
    })
    .catch(err => {
      console.error(err)
    })
}

Đang chạycheckIfItsDone()sẽ thực hiệnisItDoneYet()hứa và sẽ đợi nó giải quyết bằng cách sử dụngthengọi lại và nếu có lỗi, nó sẽ xử lý nó trongcatchgọi lại.


Chuỗi lời hứa

Một lời hứa có thể được trả lại cho một lời hứa khác, tạo ra một chuỗi các lời hứa.

Một ví dụ tuyệt vời về chuỗi lời hứa được đưa ra bởiAPI tìm nạp, một lớp ở trên cùng của API XMLHttpRequest, mà chúng ta có thể sử dụng để lấy tài nguyên và xếp hàng một chuỗi các lời hứa sẽ thực thi khi tài nguyên được tìm nạp.

API tìm nạp là một cơ chế dựa trên lời hứa và gọifetch()tương đương với việc xác định lời hứa của chính chúng ta bằng cách sử dụngnew Promise().

Ví dụ về chuỗi lời hứa

const status = response => {
  if (response.status >= 200 && response.status < 300) {
    return Promise.resolve(response)
  }
  return Promise.reject(new Error(response.statusText))
}

const json = response => response.json()

fetch(’/todos.json’) .then(status) .then(json) .then(data => { console.log(‘Request succeeded with JSON response’, data) }) .catch(error => { console.log(‘Request failed’, error) })

Trong ví dụ này, chúng tôi gọifetch()để có được danh sách những việc CẦN LÀM từtodos.jsontệp được tìm thấy trong gốc miền và chúng tôi tạo một chuỗi các lời hứa.

Đang chạyfetch()trả về mộtphản ứng, có nhiều thuộc tính và trong những thuộc tính mà chúng tôi tham khảo:

  • status, một giá trị số đại diện cho mã trạng thái HTTP
  • statusText, một thông báo trạng thái, làOKnếu yêu cầu thành công

responsecũng có mộtjson()phương thức này trả về một lời hứa sẽ giải quyết với nội dung của phần thân được xử lý và chuyển đổi thànhJSON.

Vì vậy, với những tiền đề đó, đây là những gì sẽ xảy ra: lời hứa đầu tiên trong chuỗi là một hàm mà chúng tôi đã xác định, được gọi làstatus(), kiểm tra trạng thái phản hồi và nếu đó không phải là phản hồi thành công (từ 200 đến 299), nó sẽ từ chối lời hứa.

Thao tác này sẽ khiến chuỗi hứa bỏ qua tất cả các chuỗi hứa được liệt kê và sẽ trực tiếp bỏ quacatch()tuyên bố ở dưới cùng, ghi lạiRequest failedvăn bản cùng với thông báo lỗi.

Nếu điều đó thành công, nó sẽ gọijson()chức năng chúng tôi đã xác định. Kể từ lời hứa trước đó, khi thành công, trả vềresponse, chúng tôi lấy nó làm đầu vào cho lời hứa thứ hai.

Trong trường hợp này, chúng tôi trả về dữ liệu JSON đã xử lý, do đó, lời hứa thứ ba sẽ nhận trực tiếp JSON:

.then((data) => {
  console.log('Request succeeded with JSON response', data)
})

và chúng tôi đăng nhập nó vào bảng điều khiển.


Xử lý lỗi

Trong ví dụ trên, trong phần trước, chúng ta đã cócatchđã được thêm vào chuỗi lời hứa.

Khi bất cứ điều gì trong chuỗi lời hứa không thành công và phát sinh lỗi hoặc từ chối lời hứa, sự kiểm soát sẽ được thực hiệncatch()tuyên bố xuống chuỗi.

new Promise((resolve, reject) => {
  throw new Error('Error')
}).catch(err => {
  console.error(err)
})

// or new Promise((resolve, reject) => { reject(‘Error’) }).catch(err => { console.error(err) })

Lỗi xếp tầng

Nếu bên trongcatch()bạn nêu ra một lỗi, bạn có thể thêm một thứ haicatch()để xử lý nó, v.v.

new Promise((resolve, reject) => {
  throw new Error('Error')
})
  .catch(err => {
    throw new Error('Error')
  })
  .catch(err => {
    console.error(err)
  })

Sắp xếp lời hứa

Promise.all()

Nếu bạn cần đồng bộ hóa các lời hứa khác nhau,Promise.all()giúp bạn xác định danh sách các lời hứa và thực thi một điều gì đó khi tất cả chúng đã được giải quyết xong.

Thí dụ:

const f1 = fetch('/something.json')
const f2 = fetch('/something2.json')

Promise.all([f1, f2]) .then(res => { console.log(‘Array of results’, res) }) .catch(err => { console.error(err) })

CácNhiệm vụ tái cấu trúc ES2015cú pháp cho phép bạn cũng làm

Promise.all([f1, f2]).then(([res1, res2]) => {
  console.log('Results', res1, res2)
})

Bạn không bị giới hạn sử dụngfetchtất nhiên,bất kỳ lời hứa nào cũng tốt để đi.

Promise.race()

Promise.race()chạy ngay sau khi một trong những lời hứa bạn chuyển đến nó được giải quyết và nó chạy lệnh gọi lại đính kèm chỉ một lần với kết quả của lời hứa đầu tiên được giải quyết.

Thí dụ:

const promiseOne = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, 'one')
})
const promiseTwo = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'two')
})

Promise.race([promiseOne, promiseTwo]).then(result => { console.log(result) // ‘two’ })

Lỗi thông thường

Uncaught TypeError: undefined không phải là một lời hứa

Nếu bạn nhận đượcUncaught TypeError: undefined is not a promiselỗi trong bảng điều khiển, hãy đảm bảo bạn sử dụngnew Promise()Thay vì chỉPromise()

Tải xuống miễn phí của tôiSổ tay dành cho Người mới bắt đầu JavaScript


Các hướng dẫn js khác: