在 ES6 promise 中的 for 循环中作为 'undefined' 返回的值
Values coming back as 'undefined' in for loop inside ES6 promise
所以我目前正在编写一个库存应用程序,我 运行 遇到了一些将值插入我的数据库的问题。发生的事情是我得到一个项目对象列表,其中包含有关该特定项目的信息。然后我将这些项目推入列表并调用一个运行 for 循环的套接字将这些项目插入我的数据库,但是当我查看 table 这些项目应该在哪里时,它们的所有值都设置为 undefined
.
我的项目对象看起来像这样:
let ItemObject = {
ID: id,
Name: name,
Qty: qty
}
调用数据库序列的promise:
export const insertItem = async (list) => {
return new Promise(async (resolve, reject) => {
try {
console.log(list);
for(let i = 0; i < list.length; i++){
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty});`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
}
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
};
这是被调用的套接字:
socket.on('insertItem', async (data, callback) => {
try {
const results = await insertItem(data);
callback(true);
}
catch (error) {
callback(false);
}
});
当我在 for 循环之前控制台记录列表时,我得到了我期望的输出,但是在这个承诺完成之后,我的数据库中返回的数据是 undefined
。我也没有从回调中收到任何错误。 ES6 promises 的想法对我来说仍然是新的,所以如果我这里的内容不正确,请原谅我。这是我第一次尝试在这样的异步 promise 中实现 for 循环,所以第一次没有成功对我来说并不奇怪。
如果有人对我做错了什么有任何建议,我将不胜感激。谢谢!
我认为 insertItem
不是异步函数,因为它不包含 await
...
export const insertItem = /*async <- remove it */ (list) => {
return new Promise(async (resolve, reject) => {
try {
console.log(list);
for(let i = 0; i < list.length; i++){
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty});`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
}
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
};
insertItem
不一定是 async
函数。只需 return Promise
并使用 async
承诺回调,仅在该范围内需要 await
关键字。
一个async
函数自动return一个Promise
,但是你需要一个Promise
构造函数来使用resolve
和reject
方法.它基本上是同一件事,但语法和选项不同。
我还注意到你的循环有一个错误。您尝试从数组中获取 select list.ID
、list.Name
和 list.Qty
,但应该从 中的 项中获取值数组。
我还发现您的查询字符串末尾缺少 "
。
export const insertItem = (list) => new Promise(async (resolve, reject) => {
try {
list.forEach(item => {
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${item.ID}", "${item.Name}", "${item.Qty}");`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
});
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
附录
使用 Promise.all
更新了答案。由@wizloc 建议。
这将循环所有项目和 return 来自 db()
函数的承诺,并将它们存储到一个新数组中。 Promise.all
将在数组中的所有承诺都已完成时解析,并且 return 单个数组中每个承诺的值。
export const insertItem = (list) => new Promise(async (resolve, reject) => {
try {
const responses = list.map(item => {
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${item.ID}", "${item.Name}", "${item.Qty}");`;
return db(writeSolutionData, "Inserting Item");
});
const results = await Promise.all(responses);
resolve(results);
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
我不熟悉
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty}");`;
const response = await db(writeSolutionData, "Inserting Item");
确实如此(除了显而易见的),但由于 db(writeSolutionData, "Inserting Item")
是可等待的,它 returns 是一个承诺。正如我在评论中提到的,您的原始代码在循环的第一次迭代中解析,因此如果您需要访问从您的承诺中返回的值,您会发现您只能访问第一个值。你问为什么你需要这些值,因为你可以事后查询它们,我无法回答这个问题,因为我对你的项目一无所知,你打算在插入数据后如何处理等等。但是promises 的另一个好处是通过链接 .then()
和 .catch()
来处理错误。
您可以将整个 insertData 方法简化为以下
socket.on('insertItem', async (data, callback) => {
const promises = data.map(x =>
db(`INSERT INTO database (ID, Name, Qty) VALUES ("${x.ID}", "${x.Name}", "${x.Qty});`)
)
Promise.all(promises)
.then(values => {
// Do something with values array
callback(true)
})
.catch(error => {
// Error handling
callback(false)
})
});
这样做将确保 callback(true)
仅在所有项目都成功插入时调用,并且如果任何项目失败则将出错 (callback(false)
)。
所以我目前正在编写一个库存应用程序,我 运行 遇到了一些将值插入我的数据库的问题。发生的事情是我得到一个项目对象列表,其中包含有关该特定项目的信息。然后我将这些项目推入列表并调用一个运行 for 循环的套接字将这些项目插入我的数据库,但是当我查看 table 这些项目应该在哪里时,它们的所有值都设置为 undefined
.
我的项目对象看起来像这样:
let ItemObject = {
ID: id,
Name: name,
Qty: qty
}
调用数据库序列的promise:
export const insertItem = async (list) => {
return new Promise(async (resolve, reject) => {
try {
console.log(list);
for(let i = 0; i < list.length; i++){
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty});`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
}
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
};
这是被调用的套接字:
socket.on('insertItem', async (data, callback) => {
try {
const results = await insertItem(data);
callback(true);
}
catch (error) {
callback(false);
}
});
当我在 for 循环之前控制台记录列表时,我得到了我期望的输出,但是在这个承诺完成之后,我的数据库中返回的数据是 undefined
。我也没有从回调中收到任何错误。 ES6 promises 的想法对我来说仍然是新的,所以如果我这里的内容不正确,请原谅我。这是我第一次尝试在这样的异步 promise 中实现 for 循环,所以第一次没有成功对我来说并不奇怪。
如果有人对我做错了什么有任何建议,我将不胜感激。谢谢!
我认为 insertItem
不是异步函数,因为它不包含 await
...
export const insertItem = /*async <- remove it */ (list) => {
return new Promise(async (resolve, reject) => {
try {
console.log(list);
for(let i = 0; i < list.length; i++){
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty});`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
}
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
};
insertItem
不一定是 async
函数。只需 return Promise
并使用 async
承诺回调,仅在该范围内需要 await
关键字。
一个async
函数自动return一个Promise
,但是你需要一个Promise
构造函数来使用resolve
和reject
方法.它基本上是同一件事,但语法和选项不同。
我还注意到你的循环有一个错误。您尝试从数组中获取 select list.ID
、list.Name
和 list.Qty
,但应该从 中的 项中获取值数组。
我还发现您的查询字符串末尾缺少 "
。
export const insertItem = (list) => new Promise(async (resolve, reject) => {
try {
list.forEach(item => {
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${item.ID}", "${item.Name}", "${item.Qty}");`;
const response = await db(writeSolutionData, "Inserting Item");
resolve(response);
});
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
附录
使用 Promise.all
更新了答案。由@wizloc 建议。
这将循环所有项目和 return 来自 db()
函数的承诺,并将它们存储到一个新数组中。 Promise.all
将在数组中的所有承诺都已完成时解析,并且 return 单个数组中每个承诺的值。
export const insertItem = (list) => new Promise(async (resolve, reject) => {
try {
const responses = list.map(item => {
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${item.ID}", "${item.Name}", "${item.Qty}");`;
return db(writeSolutionData, "Inserting Item");
});
const results = await Promise.all(responses);
resolve(results);
} catch (e) {
console.log("ERROR database.insertItem: " + e);
reject(e);
}
});
我不熟悉
const writeSolutionData = `INSERT INTO database (ID, Name, Qty) VALUES ("${list.ID}", "${list.Name}", "${list.Qty}");`;
const response = await db(writeSolutionData, "Inserting Item");
确实如此(除了显而易见的),但由于 db(writeSolutionData, "Inserting Item")
是可等待的,它 returns 是一个承诺。正如我在评论中提到的,您的原始代码在循环的第一次迭代中解析,因此如果您需要访问从您的承诺中返回的值,您会发现您只能访问第一个值。你问为什么你需要这些值,因为你可以事后查询它们,我无法回答这个问题,因为我对你的项目一无所知,你打算在插入数据后如何处理等等。但是promises 的另一个好处是通过链接 .then()
和 .catch()
来处理错误。
您可以将整个 insertData 方法简化为以下
socket.on('insertItem', async (data, callback) => {
const promises = data.map(x =>
db(`INSERT INTO database (ID, Name, Qty) VALUES ("${x.ID}", "${x.Name}", "${x.Qty});`)
)
Promise.all(promises)
.then(values => {
// Do something with values array
callback(true)
})
.catch(error => {
// Error handling
callback(false)
})
});
这样做将确保 callback(true)
仅在所有项目都成功插入时调用,并且如果任何项目失败则将出错 (callback(false)
)。