Javascript 异步混乱。正在处理一个API响应,并对代码中发生的事情失去了理解
关于如何最好地构造这个函数,我在自己的头脑中迷失了方向。 下面的代码基本上是正确的,我只是在底部删掉了一些函数,并不重要 应该发生什么:Javascript 异步混乱。正在处理一个API响应,并对代码中发生的事情失去了理解,javascript,node.js,asynchronous,Javascript,Node.js,Asynchronous,关于如何最好地构造这个函数,我在自己的头脑中迷失了方向。 下面的代码基本上是正确的,我只是在底部删掉了一些函数,并不重要 应该发生什么: 我的节点应用程序在特定时间运行并调用refreshDevices() 该函数从API获取JSON负载 该函数在该有效负载中的元素上循环,并检查是否已经存在记录 如果没有记录,则创建一个记录,如果有,则更新该记录 运行此操作后,将创建一个日志条目,记录更改的数量 我的问题是日志条目发生在任何记录检查之前。。。我的日志显示0已添加和0已更新。 我尝试重新编写代码以
refreshDevices()
- 我甚至尝试在
块,但这是在检查发生之前执行的.finally()
- 我使用了
和forEach
两种方法尝试了这一点map
这个问题您可以使用
Async/await
使代码更具可读性,并使用for of
对数据进行迭代
for of
循环将等待第一次迭代完成,然后进行第二次迭代,依此类推
另一方面,forEach基于回调,因此它将为回调队列中的每个迭代执行和注册回调,并退出,而不等待回调完成
试试这个
async refreshDevices(_timespan) {
const status = {
added: 0,
updated: 0,
};
// Standard API fetch & json() conversion
try {
let response = await fetch(`https://api.example.com/test×pan=${timespan}`)
let data= await response.json();
for (const device of data) {
try {
let record = await findDevice(device._id);
if (!record) {
addDeviceRecord(device);
status.added++;
} else {
deviceSeen(device._id);
status.updated++;
}
} catch (error) {
console.log('Error!');
}
}
systemlog.log({
message: 'Refresh',
data: {
success: true,
note: `Added: ${status.added} & updated: ${status.updated}`,
},
});
} catch (error) {
systemlog.log({
message: 'Refresh',
type: systemlog.logType.ERROR,
data: {
success: false,
note: error,
},
});
}
}
function findDevice(id) {
return DB('device').findOne({ id }); // this returns is a promise
}
function addDeviceRecord(record) {
return DB('device').insertOne(record); // this returns is a promise
}
function deviceSeen(id) {
return DB('device').updateOne({ id }, { $set: { lastSeen: new Date() } }); // this returns is a promise
}
或者,您也可以使用promise.all
等待所有承诺得到解决。
async refreshDevices(_timespan) {
const status = {
added: 0,
updated: 0,
};
// Standard API fetch & json() conversion
try {
let response = await fetch(`https://api.example.com/test×pan=${timespan}`)
let data = await response.json();
let promises = data.map(device => {
return new Promise( async (resolve, reject) => {
try {
let record = await findDevice(device._id);
if (!record) {
addDeviceRecord(device);
status.added++;
} else {
deviceSeen(device._id);
status.updated++;
}
resolve();
} catch (error) {
console.log('Error!');
reject(error);
}
});
});
let result = await Promise.all(promises);
systemlog.log({
message: 'Refresh',
data: {
success: true,
note: `Added: ${status.added} & updated: ${status.updated}`,
},
});
} catch (error) {
systemlog.log({
message: 'Refresh',
type: systemlog.logType.ERROR,
data: {
success: false,
note: error,
},
});
}
}
function findDevice(id) {
return DB('device').findOne({ id }); // this returns is a promise
}
function addDeviceRecord(record) {
return DB('device').insertOne(record); // this returns is a promise
}
function deviceSeen(id) {
return DB('device').updateOne({ id }, { $set: { lastSeen: new Date() } }); // this returns is a promise
}
正如您所确定的,您的
system.log
调用在启动一系列尚未解决的承诺后立即发生
在refreshDevices(\u timespan)
函数中添加一个空数组,以在forEach
中添加每个新承诺
然后修改您的代码,如
JSON.forEach((device) => {
promises.push( // Add this promise to the array
findDevice(device._id)
.then(record => {
if (!record) {
addDeviceRecord(device);
status.added++;
} else {
deviceSeen(device._id);
status.updated++;
}
})
.catch(error => {
console.log('Error!');
});
) // end of .push() arg
});
然后使用Promise.all()等待解析所有承诺,然后再调用systemLog.log
,类似于(伪伪代码:)
Promise.all(JSON.map(…)。然后(=>systemlog.log)(…)您可能想考虑将VAR <代码> JSON < /代码>重命名为<代码>数据< /代码>或类似的内容,以免混淆JS。object@csum说得好,我没想到。谢谢!@kaido这听起来像Ellight在下面回答的。我要试试看!这应该行得通,尽管你正在启动多个异步进程将多个同步进程转换为多个同步进程,而不是允许每个承诺异步运行,然后在最终承诺解决后立即继续执行。感谢@Sohail,这看起来就像我试图做的那样(我对该函数重新编码了大约5次,我有一个版本具有async/Wait everywhere)。但是,我没有使用for of
循环,这听起来像是我的撤销。我今天学到了有关forEach&map函数的一些新知识…谢谢!谢谢!这看起来是一条路要走,我以后会尝试更新我的代码。我仍然在努力承诺将函数从堆栈中拉出,并按照顺序执行r、 感谢你的回答:D
JSON.forEach((device) => {
promises.push( // Add this promise to the array
findDevice(device._id)
.then(record => {
if (!record) {
addDeviceRecord(device);
status.added++;
} else {
deviceSeen(device._id);
status.updated++;
}
})
.catch(error => {
console.log('Error!');
});
) // end of .push() arg
});
Promise.all(promises).then(
systemlog.log({
message: 'Refresh',
data: {
success: true,
note: `Added: ${status.added} & updated: ${status.updated}`,
},
});
)