Javascript 等待承诺完成,然后将对象的错误数组推送到CSV

Javascript 等待承诺完成,然后将对象的错误数组推送到CSV,javascript,node.js,promise,okta-api,csv-write-stream,Javascript,Node.js,Promise,Okta Api,Csv Write Stream,我正在尝试从Okta导入和删除大量用户,同时保持在速率限制内,并将任何错误记录到excel中。下面的代码似乎正常工作,但问题是我在控制台日志上看到的5个错误中的最后一个没有出现在输出的CSV中 我已经尝试了一系列的替代方法,包括将csvWriter调用放在.then而不是.finally中。问题是它没有等待最后一个错误被推送到数组中 “严格使用”; const-okta=require(“@okta/okta-sdk-nodejs”); const csv=require(“csv解析器”);

我正在尝试从Okta导入和删除大量用户,同时保持在速率限制内,并将任何错误记录到excel中。下面的代码似乎正常工作,但问题是我在控制台日志上看到的5个错误中的最后一个没有出现在输出的CSV中

我已经尝试了一系列的替代方法,包括将csvWriter调用放在.then而不是.finally中。问题是它没有等待最后一个错误被推送到数组中

“严格使用”;
const-okta=require(“@okta/okta-sdk-nodejs”);
const csv=require(“csv解析器”);
常数fs=要求(“fs”);
const createCsvWriter=require(“csv编写器”)。createObjectCsvWriter;
让时间运行=新日期()
.toISOString()
.replace(/T/,“”)//用空格替换T
.replace(/\…+/,“”)//删除点和后面的所有内容
.替换(/:/g,“.”;//用空格代替T
const csvWriter=createCsvWriter({
路径:“错误日志-”+timeRun+“.csv”,
标题:[
{id:“错误”,标题:“错误”},
{id:“行”,标题:“行”},
],
});
让记录=[];
让currentError={}
//在此处输入租户信息和API密钥
const client=新的okta.client({
组织URL:“https://xxxxxxxx.oktapreview.com",
令牌:“XXXXXXXXXXXXXXXXXXXX”,
});
让usersToDelete=[];
让currentUserID;
var getUsersToDelete=新承诺((解决、拒绝)=>{
fs.createReadStream(“testImport.csv”)
.pipe(csv())
.on(“数据”,(行)=>{
usersToDelete.push(行);
})
.on(“结束”,(行)=>{
解决();
});
});
getUsersToDelete
。然后(异步()=>{
设iCount=1;
while(usersToDelete.length>0){
var deleteUserTimeout=新承诺((解析、拒绝)=>{
setTimeout(异步函数(){
currentUserID=usersToDelete.pop();
客户
.getUser(currentUserID.email)
。然后(异步(用户)=>{
返回用户
.deactivate()
。然后(()=>console.log(“用户已被停用”))
。然后(()=>user.delete())
。然后(()=>console.log(“用户已被删除”);
})
.catch(异步函数(错误,行){
currentError={error:error.message,行:“row”};
控制台错误(currentError);
返回误差;
})
.最后(()=>{
record.push(当前错误);
拒绝
});
解决();
}, 2000);
});
等待删除用户超时;
log(“超时”+currentUserID,“迭代”+iCount);
I计数++
}
}).finally(异步()=>{
等待CSV编写者编写记录(记录);

});在你的
deleteUserTimeout
承诺中有一场竞赛。它在
client.getUser
之后立即解析,而不等待结果

var deleteUserTimeout=新承诺((解析、拒绝)=>{
setTimeout(异步函数(){
currentUserID=usersToDelete.pop();
client.getUser(currentUserID.email)//忘记等待这个
//…剪断
resolve();//立即解析
}, 2000);
});
等待deleteUserTimeout;//这不会等待删除
为了清晰起见,我会重构它(未经测试):

异步函数deleteUser(电子邮件){
let user=wait client.getUser(电子邮件);
等待用户。停用();
等待user.delete();
}
功能睡眠(超时){
返回新承诺(=>setTimeout(,timeoutMs));
}
异步函数deleteUsers(usersToDelete){
常量错误=[];
for(让row=0;row{
errors.push({error:error.message,row});
});
}
返回错误;
}

你的
deleteUserTimeout
承诺中有一场竞赛。它在
client.getUser
之后立即解析,而不等待结果

var deleteUserTimeout=新承诺((解析、拒绝)=>{
setTimeout(异步函数(){
currentUserID=usersToDelete.pop();
client.getUser(currentUserID.email)//忘记等待这个
//…剪断
resolve();//立即解析
}, 2000);
});
等待deleteUserTimeout;//这不会等待删除
为了清晰起见,我会重构它(未经测试):

异步函数deleteUser(电子邮件){
let user=wait client.getUser(电子邮件);
等待用户。停用();
等待user.delete();
}
功能睡眠(超时){
返回新承诺(=>setTimeout(,timeoutMs));
}
异步函数deleteUsers(usersToDelete){
常量错误=[];
for(让row=0;row{
errors.push({error:error.message,row});
});
}
返回错误;
}

您的
deleteUserTimeout
承诺没有等待用户删除操作的完成,脚本在启动最后一个要删除的用户的
setTimeout
回调后几乎立即完成。CSV将在该时间写入
记录中累积的所有错误,而不是等待某些操作完成,包括遇到错误的5次迭代

基本思想与@teppic相同,但您可能希望在发现错误时写出每个错误,而不是将它们延迟到最后,以减少在脚本因任何原因(如机器断电)崩溃时丢失错误信息的可能性

const sleep=time=>newpromise(解析=>setTimeout(解析,时间))
const deleteUser=异步电子邮件=>{
const user=wait client.getUser(电子邮件)
等待用户。停用()
等待用户。删除()
}
const deleteUsers=异步用户=>{
for(const user of users){
试一试{
阿华