Cách sử dụng các lời hứa và chờ đợi với các hàm dựa trên cuộc gọi lại của Node.js

Hầu hết các API Node.js được xây dựng trong thời điểm mà lời hứa vẫn chưa trở thành hiện thực và chúng sử dụng giải pháp dựa trên gọi lại.

API Node.js điển hình hoạt động như sau:

doSomething(param, (err, result) => {

})

Điều này cũng áp dụng cho các thư viện. Một ví dụ lànode-redisvà trong khi làm việc với nó trong một dự án, tại một số thời điểm tôi thực sự cần phải loại bỏ tất cả các lệnh gọi lại, bởi vì tôi có quá nhiều cấp độ gọi lại lồng vào nhau - một kịch bản hoàn hảo “địa ngục gọi lại”.

Ngoài ra, đôi khi hoàn toàn cần thiết để tránh các lệnh gọi lại vì bạn cần trả về từ hàm kết quả của một lệnh gọi hàm. Nếu nó được trả về trong một lệnh gọi lại, cách duy nhất để lấy lại kết quả là gửi nó trở lại bằng một hàm và bên gọi lại tiếp tục:

const myFunction = () => {
  doSomething(param, (err, result) => {
    return result //can't return this from `myFunction`
  })
}
const myFunction = callback => {
  doSomething(param, (err, result) => {
    callback(result) //no
  })
}

myFunction(result => { console.log(result) })

Có một giải pháp dễ dàng.

Một giải pháp do chính Node.js cung cấp.

Chúng tôi có thể "quảng bá" bất kỳ hàm nào không hỗ trợ các hứa hẹn (và do đó là cú pháp async / await) bằng cách nhậppromisifytừ Node.js cốt lõiutilmô-đun:

const { promisify } = require('util')

Sau đó, chúng tôi tạo các chức năng mới bằng cách sử dụng nó:

const ahget = promisify(client.hget).bind(client)
const asmembers = promisify(client.smembers).bind(client)
const ahkeys = promisify(client.hkeys).bind(client)

Xem cách tôi thêmathư có nghĩa làkhông đồng bộ.

Bây giờ chúng ta có thể thay đổi ví dụ này "địa ngục gọi lại":

client.hget(`user:${req.session.userid}`, 'username', (err, currentUserName) => {
  client.smembers(`followers:${currentUserName}`, (err, followers) => {
    client.hkeys('users', (err, users) => {
      res.render('dashboard', {
        users: users.filter((user) => user !== currentUserName && followers.indexOf(user) === -1)
      })
    })
  })
})

trở nên sạch sẽ hơn nhiều:

const currentUserName = await ahget(`user:${req.session.userid}`, 'username')
const followers = await asmembers(`followers:${currentUserName}`)    
const users = await ahkeys('users')

res.render(‘dashboard’, { users: users.filter((user) => user !== currentUserName && followers.indexOf(user) === -1) })

Điều này là tối ưu khi sử dụng một chức năng mà bạn không có quyền truy cập, như trong trường hợp này khi tôi sử dụng thư viện của bên thứ ba.

Dưới mui xe, promisify kết thúc hàm trong một lời hứa và trả về nó.

Bạn cũng có thể thực hiện việc này theo cách thủ công, trả về một lời hứa từ một hàm, sau đó sử dụng nó với async / await:

const handleLogin = (req, user) => {
  return new Promise((resolve, reject) => {
    req.login(user, (err) => {
      if (err) {
        return reject({
          error: true,
          message: err,
        })
      }
      return resolve({
        success: true,
      })
    })
  })
}

//… const resultLogin = await handleLogin(req, user)

Tải xuống miễn phí của tôiSổ tay Node.js


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