变量有效但在代码块的下方未定义

Variable works but undefined further down the code block

我有一个函数可以将 JSON 个对象插入(冻结)到 MongoDB:

var result = null, OID = null ; 
...

var test = dbHandle.collection('TestItems') ;
result = prepareObject() ;
test.insert(result, {w:1}, function(err, item) {
    if (err) throw err ; 
    OID = ObjectID(item[0]._id) ;
    test.update({_id: OID}, {$set: { userName: socket.userName, state: 'Ready'} }, {w:1}, function( err ) {
        if (err) throw err ;
        test.findOne({ _id: OID }, function (err, loaded) {
            if (err) throw err ;
            socket.emit('newData', { data: loaded }) ;
        });
    }) ;
}) ;

此代码按我的预期工作。然而,在我的代码中,我需要同时使用 OID 和结果对象,但它们始终未定义。我知道我一定做错了什么,但我不知道是什么。我的背景是 C++,我的方法对我来说很有意义,但这是我第一次尝试 JavaScript / NodeJS / MongoDB。如果有人能指出正确的方向,我将不胜感激。

例如,当我稍后尝试创建一个新对象时:

var myObj = {Title: result.Title, TID: OID, Stuff:'More Stuff Here'} ;

当此对象插入 MongoDB 时,Title 和 TID 值都是 'undefined',但我的 TestItems 集合已正确更新,这意味着 OID 有值!这是某种形式的范围问题吗?我看不出声明、赋值和使用如何都在同一个闭包中。

很有可能是异步设计的问题。 您的 test.insert 函数将所谓的 "callback" 函数作为第三个参数。此函数将在插入完成后调用,但执行不会被 test.insert 阻塞,因此您可能会在调用回调之前执行更多代码。

为了让您更好地了解正在发生的事情,您的脚本按以下顺序运行:

  • test.insert被称为
  • 调用 test.insert 之后的任何内容(您仍然没有 OID 和结果)
  • (稍后)调用 test.insert 的回调(设置您的 OID 和结果属性)

您可以做的是将代码放在您想要使用 OID 和 test.insert 的函数中,然后从 test.insert 回调中调用它:

result = prepareObject();
test.insert(result, ..., function(err, item) {
    // do stuff, get result objects, OID, etc
    // call your onInsertFinish function (pass result and OID to avoid using globals)
    onInsertFinish(result, OID);
});

function onInsertFinish(result, OID) {
    // do stuff with result and OID
}

希望对您有所帮助。