我有一个简单的函数tokenExists
,它检查令牌是否已经是Redis set
的一部分。我知道resp
将以undefined
的形式返回,因为最后一行代码在函数完成之前运行,并发出请求并从Redis
获取响应。我已经阅读了许多关于使用async
处理Redis
Node
性质的SO文章,但几乎所有这些文章都必须使用多行命令或Express
和特定路径的问题。我想知道如何使这个代码同步。
function tokenExists(token, callback) {
db.sismember("tokens", token, function(err,res) {
if (err) throw err;
callback(null, parseInt(res, 10) === 1);
});
}
function generateToken(){
try {
var token = urlSafeBase64(crypto.randomBytes(23));
} catch (ex) {
console.log(ex)
}
tokenExists(token, function(err,res){
if (err) throw err;
res ? token : generateToken();
})
}
^^ this method is returning 'undefined'
答案 0 :(得分:0)
你不能。
数据库调用是异步的,因此您必须使用tokenExists函数的回调。
function tokenExists(token, callback) {
db.sismember("tokens", token, function(err,res) {
if (err) throw err;
callback(null, parseInt(res, 10) === 1);
});
}
答案 1 :(得分:0)
我不确定Javascript,这些是伪代码:
您可能希望以某种同步方式使用generateToken
,如下所示:
void foo() {
var token = generateToken();
print(token);
use(token);
}
但是你可能无法以某种方式使用它,如BarışUşaklı已经说过, 因为node.js只使用一个线程,并且可能不允许您阻止该线程。 因此,如果您想以异步方式使用它:
void foo() {
generateToken(function(token) {
print(token);
use(token);
});
}
您应该更改generateToken
:
function generateToken(callback){ // this line is changed.
try {
var token = urlSafeBase64(crypto.randomBytes(23));
} catch (ex) {
console.log(ex)
}
tokenExists(token, function(err,res){
if (err) throw err;
callback(res ? token : generateToken(callback)); // this line is changed.
})
答案 2 :(得分:0)
使用异步代码,您必须完全接受延续模式。由于您使用redis呼叫进行了一次异步呼叫,因此您必须一直前往原始呼叫者。
您的代码修改了一下:
function tokenExists(token, callback) {
db.sismember("tokens", token, function(err,res) {
if (err) throw err;
callback(null, parseInt(res, 10) === 1);
});
}
//add an additional callack to generateToken
function generateToken(callback){
try {
var token = urlSafeBase64(crypto.randomBytes(23));
} catch (ex) {
console.log(ex)
}
//once this async call is made, you're off the main event loop.
tokenExists(token, function(err,res){
//standard node convention passes an error function as the first paramter
//you can log it if you want,but let the callback know there was an error
if (err) return callback(err,null);
if(res){
return callback(null,res);
}
generateToken(callback);
})
}
您必须从执行代码提供回调并在那里处理结果。以下是在快速路由回调中发送令牌的示例。如果您使用令牌执行更复杂的操作,例如保存记录(当然是异步),那么您将不得不在原始方法调用中管理多个回调。像Q或Bluebird这样的异步或承诺库等库可以提供帮助。您还可以查看callbackhell.com,了解如何使用命名方法和模块使用纯JavaScript进行操作。
//calling your generateToken
app.get('/token',function(req, res){
generateToken(function(err, token){
if(err) return res.send(500,err);
res.end(token);
})
});