在我正在编写的脚本中,我正在迭代邮箱中的一些消息并尝试删除已阅读的消息。我遇到的问题是,当我迭代数组时,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/