问题描述
我正在创建一个循环来使用具有内置承诺的函数来创建/更新用户:
for (const user of usersjson.users) {
let getuser = getUser(url,okapikey,user[fieldMap.externalSystemId],'externalSystemId'); //Check if user exists on the server
await getuser
.then(async (data) => {
if (data.users.length != 0) { //If user exists in the array
update = updateUser(url,createduser,data.users[0].id);//Create update function
promises.push(update); //Store function in array
i++;
} else {
create = createNewUser(url,createduser);//Create create function
promises.push(create); //Store function in array
i++;
}
}).catch((err) => {
console.error(err);
});
if (promises.length == 50 || i == usersjson.users.length) {//Run functions in batches of 50
await Promise.allSettled(promises)
.then((responses)=> {
for (const response of responses) { //For each promise response
if (response.status == 'fulfilled') { //If fulfilled
if (response.value.status == 204) {
console.log(`${response.value.status}: User ${response.value.request.path.substring(7)} was updated.`);
} else {
if (response.value.status == 201 && response.value.headers.location) {
console.log(`${response.value.status}: User ${response.value.headers['location']} was created.`);
} else {
console.log(response.value.headers.location);
}
}
} else { //Handle rejections
console.log(`There was an error with the user:${response.value}`);
}
}
}).catch((err)=> {
console.log(err);
});
promises=[]; //Empty Promise array
}
}
async function updateUser(url,token,user,userid)
{
return new Promise((resolve,reject) => {
//Create headers for put request
const options = {
method: "put",headers: {
'x-okapi-token': token,'x-okapi-tenant':'tenant','Content-type':"application/json"
}
};
//Make API get call
user.id=userid; //Adding the required field ID to the JSON
axios.put(`${url}/users/${userid}`,JSON.stringify(user),options)
.then(response => {
if (response.status == 204) {
resolve(response);
} else {
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
}
}).catch((err) => {
console.error(`Error Code: ${err.response.status}`);
if (typeof err.response.data == 'string') {
console.error(err.response.data);
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
} else if (err.response.data.errors[0].message) {
console.error(`Error Text: ${err.response.data.errors[0].message}`);
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
} else {
reject(`Error Code: ${err.response.status}\nError Text: ${err.response.data.errors[0].message}\nError Status: ${err}`);
}
console.log(err.response);
});
});
};
async function createNewUser (url,user) {
return new Promise((resolve,reject) => {
//Create headers for put request
const options = {
headers: {
'X-Okapi-token': token,'Content-type':"application/json"
}
};
//Make API get call
axios.post(`${url}/users`,options)
.then(response => {
if (response.status == 201) {
resolve(response);
} else {
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Text: ${err.response.data.errors[0].message},\nError Status: ${err}`)
}
}).catch((err) => {
console.error(`Error on ${user.externalSystemId}: ${err}`);
if (err.response.data && typeof err.response.data == 'string') {
console.error(err.response.data);
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Status: ${err}`)
} else if (err.response.data.errors[0].message) {
console.error(`Error Text: ${err.response.data.errors[0].message}`);
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Status: ${err}`)
} else {
reject(`Error Code: ${err.response.status}: ${user.externalSystemId},\nError Status: ${err}`)
}
});
});
};
const getUsers = (url,password) =>
{
return new Promise((resolve,reject) => {
//Create headers for POST request
const options = {
method: 'post',headers: {
'Authorization': 'Basic '+Buffer.from(`${user}:${password}`).toString('base64')
}
}
//Make API get call
axios.get(url,options)
.then(response => {
resolve(response.data);
}).catch((err) => {
console.error(err);
reject(err);
});
});
};
当每个 promise 都完成时,代码和循环运行良好,但是一旦 promise 被拒绝,循环就会中断。我收到错误消息,例如:
XXX 上的错误:错误:请求失败,状态代码为 422 错误文本: 使用此用户名的用户已存在 节点:内部/进程/承诺:246 triggeruncaughtException(err,true /* fromPromise */); ^
[UnhandledPromiseRejection:这个错误是由抛出 在没有 catch 块的异步函数内部,或者通过拒绝一个 未使用 .catch() 处理的 promise。被拒绝的承诺 原因“错误代码:422:XXX,错误文本:具有此用户名的用户 已经存在,错误状态:错误:请求失败,状态码 422"。] { }
看代码和错误,我相信这来自“createNewUser”函数。 我不确定代码为什么会中断 - 我向所有函数添加了捕获、处理拒绝并在代码主体中添加了 catch 语句,但循环仍然中断。
我需要的是,即使一个函数失败,循环也能照常继续(我稍后会将日志从 console.log 更改为实际的日志文件)。
解决方法
public function actionView()
{
$this->view->title = 'List Hotels';
$items = ArrayHelper::map(Hotel::find()->all(),'id','name');
return $this->render('index',[
'items' => $items,]);
}
这是不准确的。您没有在该数组中存储函数,您实际上在这里调用了 <?php
/* @var $this yii\web\View */
use yii\helpers\Html;
$this->title = 'Hotel list';
$this->params['breadcrumbs'][] = $this->title;
?>
<?php foreach ($items as $item): ?>
<p> <?= $item-> name ?></p>
<p> <?= $item->address ?></p>
<p> <?= $item->description ?></p>
<?php endforeach; ?>
/update = updateUser(url,okapikey,createduser,data.users[0].id);//Create update function
promises.push(update); //Store function in array
create = createNewUser(url,createduser);//Create create function
promises.push(create); //Store function in array
函数并将结果 promise 存储在数组中。然后,在实际调用 updateUser
数组上的 createNewUser
之前,您的循环继续(由于 await
)执行更多 getUser
操作。与此同时,一些承诺可能已经被拒绝,而没有附加任何处理程序。
这与Waiting for more than one concurrent await operation和Any difference between await Promise.all() and multiple await?中讨论的问题基本相同。
要修复它,请收集您稍后可以在数组中执行的实际函数:
Promise.allSettled