Большая часть Node.js API-интерфейсы были созданы в то время, когда обещаний еще не существовало, и они используют решение на основе обратного вызова.
Типичный Node.js API работает следующим образом:
doSomething(param, (err, result) => {
})Это относится и к библиотекам. Одним из примеров является узел-redis , и во время работы с ним над проектом в какой-то момент мне действительно понадобилось удалить все обратные вызовы, потому что у меня было слишком много уровней обратных вызовов, вложенных друг в друга – идеальный сценарий “обратного вызова ад”.
Кроме того, иногда абсолютно необходимо избегать обратных вызовов, потому что вам нужно вернуть из функции результат вызова функции. Если это возвращается при обратном вызове, единственный способ вернуть результат – отправить его обратно с помощью функции, и участник обратного вызова продолжит:
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)
})Есть простое решение.
Решение, предоставляемое Node.js сам по себе.
Мы можем “обещать” любую функцию, которая не поддерживает обещания (и, как следствие, синтаксис async/await), импортировав promisify из ядра Node.js утилита модуль:
const { promisify } = require('util')Затем мы создаем новые функции, используя его:
const ahget = promisify(client.hget).bind(client) const asmembers = promisify(client.smembers).bind(client) const ahkeys = promisify(client.hkeys).bind(client)
Посмотрите, как я добавил букву a для обозначения асинхронного .
Теперь мы можем изменить этот пример “ад обратного вызова”.:
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)
})
})
})
})в гораздо более чистый:
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)
})Это оптимально при использовании функции, к которой у вас нет доступа, как в этом случае, когда я использую стороннюю библиотеку.
Под капотом promisify обертывает функцию в обещание и возвращает ее.
Вы также можете сделать это вручную, вернув обещание из функции, а затем используя его с помощью 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)Оригинал: “https://flaviocopes.com/node-promisify/”