如何与 forEach 同时执行承诺?
Posted
技术标签:
【中文标题】如何与 forEach 同时执行承诺?【英文标题】:How to execute promises simultaneously with forEach? 【发布时间】:2021-05-14 09:23:06 【问题描述】:我有一个代码可以在我的系统中更新或创建新用户。它与 forEach 函数一起使用,效果很好。 但是,我想利用 Node.js 并同时执行多个更新/创建。 我试图创建一系列承诺,但我认为我构建的承诺是错误的。 这是可以正常工作的代码:
import usersjson from './jsons/users.json';
if (usersjson.users.length)
for (const user of usersjson.users)
let getuser = getUser(url, user.Id, 'Id');
getuser.then((data) => //Make a call to get user by id
if (data.users.length != 0) //If user exists
let update = updateUser(url, user, data.users[0].id);//update user function
update.then((updateresponse) =>
console.log(updateresponse);
).catch((err) =>
console.log(err);
)
else //if user doesn't exist
let update = newUser(url, user);//createUser(settings.fieldMap, user)
update.then((response) =>
console.log(response);
).catch((err) =>
console.log(err);
);
)
;
;
现在,我想将“更新”变成 Promise,这样我就可以使用 Promise.all() 同时发送多个。这是我尝试过的:
import usersjson from './jsons/users.json';
let promises = [];
if (usersjson.users.length)
for (const user of usersjson.users)
if (promises.length <= 20)
let getuser = getUser(url, user.Id, 'Id');
getuser.then((data) => //Make a call to get user by id
if (data.users.length != 0) //If user exists
let update = new promise ((resolve, reject) =>
updateUser(url, user, data.users[0].id).then((response) =>
resolve(response);
).catch((err) =>
console.log(err)
);
);
promises.push(update);
else //if user doesn't exist
let update = new promise ((resolve, reject) =>
newUser(url, user).then((response) =>
resolve(response);
).catch((err) =>
console.log(err);
)
);
psomises.push(update);
);
else
await promises.all(update)
.then ((result) =>
console.log(result);
promises = [];
).catch(err)
console.log(err);
;
;
;
但我收到一条错误消息:
(node:22016) UnhandledPromiseRejectionWarning: ReferenceError: promise 没有定义 在文件:///C:/xampp/htdocs/NodeAPI/server.js:70:21 在 processTicksAndRejections (internal/process/task_queues.js:97:5) (node:22016) UnhandledPromiseRejectionWarning:未处理的承诺拒绝。这 错误源于在异步函数内部抛出 没有 catch 块,或拒绝未处理的承诺 使用 .catch()。在未处理的承诺上终止节点进程 拒绝,请使用 CLI 标志
--unhandled-rejections=strict
(请参阅 https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode)。 (拒绝 ID:1)(节点:22016)[DEP0018] 弃用警告:未处理 不推荐使用承诺拒绝。在未来,承诺拒绝 未处理的将终止 Node.js 进程 非零退出代码。
我的问题是,如何让数组中的 20 个用户同时运行 forEach,而不是一个一个地运行?
【问题讨论】:
你为什么要把await
和then
混在一起?
另外,您不再需要使用.forEach
。 for( of )
是很久以前添加到 javascript 中的,它适用于任何可迭代对象,包括所有具有 .forEach
函数属性的类型。
因为我显然不知道自己在做什么? :) 我什至不知道为什么我的原始代码需要使用 Promise。我只是被要求这样做。
这段代码比它需要的要复杂得多。我会先以更简单的方式重写它。我不太了解您试图用这段代码完成什么,以及您调用的某些函数做了什么才能建议进行更简单的重写。
另外,你不会“执行承诺”。您执行函数,某些函数可能会返回一个 Promise,它只是一个帮助您监视异步操作的对象。承诺不会“执行”。区别不仅仅是语义,因为它对于理解异步操作和承诺实际发生的事情很重要。
【参考方案1】:
首先,将处理每个单独的user
值的代码流 移到它自己单独的async
函数中。
async
函数的实际工作方式(因为每个 async function
标记每个异步状态机的边界),在 for
语句中执行并发异步工作实际上并不可行。
从for
循环中调用该函数。
总是更喜欢===
而不是==
。
使用 TypeScript。在没有 TypeScript 的情况下使用 async
JavaScript 是一个痛苦的世界,因为您需要跟踪哪些函数返回 Promise<T>
与那些不返回的函数,以及正确解包 Promise<T>
对象。
始终尽可能拥有自己的 try/catch
语句来包装 async
函数的整个主体,否则您将不得不处理不同 JS 引擎和 JS 代码如何处理抛出的异常和对象的不一致。
import usersjson from './jsons/users.json';
async function updateUsers()
const promises = [];
const users = usersjson;
for( const user of users )
const promise = updateUser( user ); // <-- Note this is *NOT* awaited here.
promises.push( promise );
await Promise.all( promises ); // <-- This is where we await everything.
async function updateUser( user )
try
const data = await getUser( url, user.Id, 'Id' );
if( data.users.length === 0 )
let createResult = await newUser( url, user );
console.log( "Created new user %o", createResult );
else
const updateResult = await updateUser( url, user, data.users[0].id );
console.log( "Update user %o: Result: %o", user.Id, updateResult );
catch( err )
console.error( "Failed to update (or create) user with UserId %o: %o", user.userId, err );
【讨论】:
那么如果我想分块做呢?例如,一次 20-50 个用户?在那种情况下,我怎样才能在 for 循环之外等待? 好的,我设法通过异步所有这些所在的函数来正确地做到这一点。非常感谢!【参考方案2】:实现这一点的最简单方法是在 foarch 方法中,将所有的 Promise 引入一个数组中,然后调用它们,然后使用 Promise.all 等到一切都完成。
let promiseArray = []
array.forEach(x =>
// Do whatever you need
promiseArray.push(updateUser(...))
// Push only the promise without the 'then'
// You are going to handle the response or
// the errors later
)
const promiseResponses = await Promise.all(promiseArry)
// promiseResponses is an array of responses
// like promiseResponse[0]
【讨论】:
谢谢!但是,当我尝试使用此方法时,“Promise.all”之前的“await”出现错误“SyntaxError: Unexpected reserved word”。我不能在“forEach”循环中使用“await”,这会阻止我设置一个计数器(我想一次推送大约 50 个承诺,所以在每次“推送”之后我检查数组的长度和如果是 20,我使用“Promise.all”函数。以上是关于如何与 forEach 同时执行承诺?的主要内容,如果未能解决你的问题,请参考以下文章