节点。从数据库中获取数据并使用结果发出请求

时间:2016-11-30 10:06:51

标签: javascript node.js spotify

我有一个数据库中的用户列表。在注册到db时,他们最初被给予了access_token,但是当它到期时,我需要通过refresh_token创建一个新的access_token,它也已经在数据库中保存了对用户。

我需要向端点发出POST请求以访问获取新的访问令牌。

我试图遍历数据库中的每一行并以这种方式获得新的access_token。当有一个用户时它可以正常工作,但是当users数组中有多个用户时,每个user都是相同的,即数据库表中的最后一个用户。我猜这个请求还没有完成,它正在尝试发送新的请求或类似的东西。

有谁知道怎么解决这个问题?

app.get('/get-users', function (req, res) {
    connection.query('SELECT * from users', function(err, rows, fields) {
        if(err) console.log(err);

        for(var i = 0; i < rows.length; i++) {
            name = rows[i].name;
            userId = rows[i].userId;
            console.log(userId);// this gives the correct userid
            var authOptions = {
                url: url,
                headers: {
                    'Authorization': 'Basic ' + (new Buffer(client_id + ':' + client_secret).toString('base64'))
                },
                form: {
                    grant_type: 'refresh_token',
                    refresh_token: refresh_token
                },
                json: true
            };

            request.post(authOptions, function(error, response, body) {
                if (!error && response.statusCode === 200) {
                    var access_token = body.access_token;
                    users.push({name: name, userId: userId, accessToken: access_token});
                    console.log(userId)//gives last entry in db
                }
            });
        setTimeout(function () {
           console.log(users)
         }, 3000)
        }
    });
   res.send('getting here');
})

1 个答案:

答案 0 :(得分:0)

你的问题是:

    for(var i = 0; i < rows.length; i++) {
        name = rows[i].name;
        userId = rows[i].userId;
        // ...
        request.post(authOptions, function(error, response, body) {
          // you're using name and userId here
        });
        // and also you use users here:
        console.log(users)
    }

现在,问题是在循环迭代的全部完成之前,不会调用任何回调(即使是第一次迭代)。

首先,console.log(users)总是会得到users的价值,无论 之前发生了什么users.push()

此外,对于每次回调nameuserId的值将相同 - 无论您for循环的最后一次迭代后是什么。

您的nameuserId似乎是全局变量,或者它们是在某些外部范围内定义的。您需要做的是使用let在本地定义它们,以便它们为每个循环迭代获得新的绑定。

请参阅一个简单示例来演示此处发生的事情:

for (var i = 0; i < 4; i++) {
  x = 'Number ' + i;
  setTimeout(function () {
    console.log(x);
  }, 500*i);
}

这不好,因为x是一个全局变量。现在使用var

for (var i = 0; i < 4; i++) {
  var x = 'Number ' + i;
  setTimeout(function () {
    console.log(x);
  }, 500*i);
}

仍然不好,因为每次迭代共享x只有一个绑定。现在使用let

for (var i = 0; i < 4; i++) {
  let x = 'Number ' + i;
  setTimeout(function () {
    console.log(x);
  }, 500*i);
}

它起作用,因为每次迭代都会获得一个新的绑定。

更新

另一件事是确保您知道每个request.post何时结束,以便您可以在合适的时间发送回复。

您可以使用async来帮助您。您可以使用BluebirdQ等承诺和库来帮助您。但你也可以做一个简单的伎俩。如果你想知道你在上面展示的例子的最后一个回调中,你可以计算这样的调用:

let current = 0, last = 0;
for (let i = 0; i < 4; i++) {
  let x = 'Number ' + i;
  setTimeout(function () {
    if (++current === last) console.log('Last callback:');
    console.log(x);
  }, 500*i);
  last++;
}

这可能不是处理复杂情况的最佳方法,但它演示了正在发生的事情:last变量在每次迭代时都会递增,而回调只会在那时进行注册。然后回调开始一个接一个地触发,你可以在每次触发一个回调时增加current变量,并比较它是否是最后一个。

现在,一般建议:每次使用let(或const)代替var。它的工作方式更加直观。当然,如果你知道自己在做什么,可以使用var,但如果有疑问则使用let