javascript - 当变量选择数组中的元素时,为什么 Node 看不到该元素?

标签 javascript arrays node.js object timeout

在我正在编写的脚本中,我正在迭代邮箱中的一些消息并尝试删除已阅读的消息。我遇到的问题是,当我迭代数组时,Node 说它找不到给定元素的属性 id(这是删除或查看任何内容所必需的)。如果该属性不存在,那就没问题,但是当使用 util.inspect 并指定 1 而不是迭代器变量时,它可以找到并打印该字段。现有代码如下所示:

             for(var b = 1; b < length; b++){
                setTimeout(function(){
                  console.log(util.inspect(messageList, false, null));
                  console.log(util.inspect(messageList[1], false, null));
                  console.log(util.inspect(messageList[1].id, false, null));
                  console.log(util.inspect(messageList[b].id, false, null));
                  var delID = messageList[b].id;
                  //console.log(util.inspect(messageList, false, null));
                  if(delID){
                    gmail.users.messages.trash({
                      auth:auth,
                      userId: 'me',
                      id: delID,
                    }, function(err2, delObject){
                      if(err2){
                        console.log("The message with ID: "+ delID + " could not be deleted");
                        console.log(err2);
                        return;
                      }
                      else{
                        console.log(util.inspect(delObject, false, null));
                        console.log("Message was deleted with id: " + delID);
                      }
                    })
                  }
                }, 2000);
              }

上面的 messageList 具有实际数字而不是变量的行显示“157550983b6c1cb”(撇号也打印出来)。在我用 b 切换它的行上,它抛出:

    TypeError: Cannot read property of undefined
       at Timeout.oneTimeout(.......etc)
       at tryOnTimeout(timers.js:232:11)
       at Time.listonTimeout(timers.js:202:5)

这是否意味着无法在Timeout函数中使用变量b?如果是这样,我如何避免需要迭代整个 messageList 并在删除之间中断?

最佳答案

因为 setTimeout 是异步的,所以在 for 循环完成之前不会调用回调 - 此时,b 将是 messageList.length - 太大了

您希望在每次迭代之间等待 2 秒 - 一种方法是使用像这样的递归函数调用

var length = messageList.length;
function myFunction(b) {
    setTimeout(function() {
        console.log(util.inspect(messageList, false, null));
        console.log(util.inspect(messageList[1], false, null));
        console.log(util.inspect(messageList[1].id, false, null));
        console.log(util.inspect(messageList[b].id, false, null));
        var delID = messageList[b].id;
        //console.log(util.inspect(messageList, false, null));
        if (delID) {
            gmail.users.messages.trash({
                auth: auth,
                userId: 'me',
                id: delID,
            }, function(err2, delObject) {
                if (err2) {
                    console.log("The message with ID: " + delID + " could not be deleted");
                    console.log(err2);
                    return;
                } else {
                    console.log(util.inspect(delObject, false, null));
                    console.log("Message was deleted with id: " + delID);
                }
            })
        }
        b += 1;
        if (b < length) {
            myFunction(b);
        }
    }, 2000);
}
if (messageList.length > 0) {
    myFunction(0);
}
// note - any code here will run immediately! 
// it wont wait for the "iteration" to complete - 
// if you need to wait for the above to finish, 
// that's a whole other set of problems

as per comments, if you want the first iteration to run immediately, change the code to

var length = messageList.length;
function myFunction(b) {
    console.log(util.inspect(messageList, false, null));
    console.log(util.inspect(messageList[1], false, null));
    console.log(util.inspect(messageList[1].id, false, null));
    console.log(util.inspect(messageList[b].id, false, null));
    var delID = messageList[b].id;
    //console.log(util.inspect(messageList, false, null));
    if (delID) {
        gmail.users.messages.trash({
            auth: auth,
            userId: 'me',
            id: delID,
        }, function(err2, delObject) {
            if (err2) {
                console.log("The message with ID: " + delID + " could not be deleted");
                console.log(err2);
                return;
            } else {
                console.log(util.inspect(delObject, false, null));
                console.log("Message was deleted with id: " + delID);
            }
        })
    }
    if (b < length - 1) {
        setTimeout(myFunction, 2000, b + 1);
    }
}
if (messageList.length > 0) {
    myFunction(0);
}
// note - any code here will run immediately! 
// it wont wait for the "iteration" to complete - 
// if you need to wait for the above to finish, 
// that's a whole other set of problems

If you want to have code that runs on completion of the iteration, things can be made a whole lot simpler with Promises - you could use this method regardless if you have code that runs on completion or not

messageList
.slice(1) // skip the first item in the array as per question code - remove this line to start at 0
.reduce(function(prom, messageItem, index) {
    return prom
    .then(function () {
        if (index) { // this avoids the 2 second wait on the first item
            return new Promise(function(resolve) {
                setTimeout(resolve, 2000);
            });
        }
    })
    .then(function() {
        console.log(util.inspect(messageList, false, null));
        console.log(util.inspect(messageItem, false, null));
        console.log(util.inspect(messageItem.id, false, null));
        var delID = messageItem.id;
        //console.log(util.inspect(messageList, false, null));
        if (delID) {
            gmail.users.messages.trash({
                auth: auth,
                userId: 'me',
                id: delID,
            }, function(err2, delObject) {
                if (err2) {
                    console.log("The message with ID: " + delID + " could not be deleted");
                    console.log(err2);
                    return;
                } else {
                    console.log(util.inspect(delObject, false, null));
                    console.log("Message was deleted with id: " + delID);
                }
            });
        }
    });
}, Promise.resolve()) // this starts the promise chain
.then(function() {
    // this code gets called once the "loop" finishes
});
// code here does not wait for the "loop" to finish
// in fact it runs before the first messageList item is even processed

在开始等待下一次迭代之前,此代码等待gmail.users.messages.trash完成 - 如果您需要等待,那么再说一次,这又是一个完全不同的问题,但使用 Promise 方法时非常容易处理

关于javascript - 当变量选择数组中的元素时,为什么 Node 看不到该元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39724624/

相关文章:

python - 在 numpy 数组中找到仅符号不同的行对

java - 如何组合 int 和 string 数组?

javascript - 如何在 vis.js 网络中进行更细粒度的扩展?

javascript - 以 Rails 4 形式将 <ul> 列表作为参数数组提交,使用 javascript 将 params 值添加到 params 哈希

javascript - 在 Angular/Mongoose/Node.js 中使用枚举的最佳方法

javascript - 将数组元素从 [1] 移动到 [0]

node.js - Node 红色: share data between node

javascript - 为什么 Object.toString 会抛出 SyntaxError 而 Array.slice 不会?

javascript - 强制 "inspected mode"中的 DOM 元素

node.js - 重复询问带 Node 的用户输入?