如何在一个请求中等待,直到另一个请求完成 nodeJS 中相同功能的执行
Posted
技术标签:
【中文标题】如何在一个请求中等待,直到另一个请求完成 nodeJS 中相同功能的执行【英文标题】:How to wait in one request till another request finishes the execution of same function in nodeJS 【发布时间】:2020-10-23 20:57:22 【问题描述】:我正在使用流星。我在 Iron 路由器中定义了如下路由,
Router.route('/api/generatereceipt', where: 'server').post(function(req, res, next)
console.log("API: generatereceipt invoked.");
const reqBody = req.body;
....
我想一次生成一张收据。即收据需要有一个唯一的编号,该编号本质上是递增的。
现在我正在读取之前存储的收据编号并将其加一。我认为这是当前处理收据的收据编号。
但是,只要generatereceipt
API 没有被多个客户端同时调用,它就可以正常工作。当同时调用 API 时,所有同时处理的收据都认为相同的收据编号。
因此,我想请求检查是否在处理其他请求中的某个其他客户端调用了相同的 REST API。如果它在进程中,那么我想等到它在该请求线程中的执行完成。
【问题讨论】:
【参考方案1】:使用 async 和 await 来等待一个请求的完成。
【讨论】:
但是异步等待只在当前线程中有效。如何观察该 API 是否在其他线程上运行?或其他要求?【参考方案2】:我假设这使用某种数据库/后端来存储收据 ID?如果是这样,您应该对数据库使用约束以确保收据 ID 是唯一的。更好的是,为什么不让收据 id 列自动递增,那么您不需要检查之前的收据编号并自行递增,它将由数据库层处理,它只是作为插入的一部分返回。
如果不需要自动递增,那么只需考虑使用 UUID。
我想不出你为什么要等待执行的单一原因。除了第一个请求之外,它会使您的应用程序变慢,并且无法扩展。
如果您确实有正当理由以这种方式构造它并自己生成自动增量,那么最好详细解释为什么会这样,因为可能有更好的解决方案,而不是“阻塞”下一行
【讨论】:
谢谢。我正在考虑做同样的事情,但只是想我们是否可以检查另一个请求的执行情况。我会将$inc
用于 SimpleSchema 中的 mongo 或 autoValue,方法是使其成为唯一字段。谢谢。
很高兴它已排序,如果此答案对您有所帮助,请随时将其标记为已接受的答案【参考方案3】:
并发请求应该没有问题。请参阅以下示例:
import Meteor from 'meteor/meteor'
import WebApp from 'meteor/webapp'
import HTTP from 'meteor/http'
// create a simple HTTP route
WebApp.connectHandlers.use('/api/generatereceipt', function (req, res, next)
// random 0 - 50ms timeout to simulate response delay
const randomTimeout = Math.floor(Math.random() * 50)
// use Meteor's Promise.await to await async in non-async functions
// --> should prevent troubles with legacy iron-router
const receipt = Promise.await(getReceipt())
setTimeout(() =>
res.writeHead(200)
res.end(String(receipt))
, randomTimeout)
)
// increment id and return new value
let receiptId = 0
async function getReceipt ()
return receiptId++
Meteor.startup(function ()
let testCount = 0
const url = Meteor.absoluteUrl('/api/generatereceipt')
// simulate concurrent calls by using a timeout of 0
function call (id)
setTimeout(Meteor.bindEnvironment(() =>
// simulate calling the /api/generatereceipt route
const response = HTTP.get(url)
console.log(id, ' => ', response.content) // should match
, 0))
for (let i = 0; i < 25; i++)
call(testCount++)
)
如您所见,调用将解析为递增的 id:
=> Meteor server restarted
I20200703-09:59:15.911(2)? 9 => 9
I20200703-09:59:15.912(2)? 7 => 7
I20200703-09:59:15.913(2)? 4 => 4
I20200703-09:59:15.913(2)? 0 => 0
I20200703-09:59:15.913(2)? 21 => 21
I20200703-09:59:15.913(2)? 24 => 24
I20200703-09:59:15.913(2)? 17 => 17
I20200703-09:59:15.913(2)? 18 => 18
I20200703-09:59:15.915(2)? 2 => 2
I20200703-09:59:15.917(2)? 19 => 19
I20200703-09:59:15.923(2)? 6 => 6
I20200703-09:59:15.923(2)? 23 => 23
I20200703-09:59:15.925(2)? 11 => 11
I20200703-09:59:15.928(2)? 8 => 8
I20200703-09:59:15.931(2)? 16 => 16
I20200703-09:59:15.932(2)? 10 => 10
I20200703-09:59:15.934(2)? 5 => 5
I20200703-09:59:15.934(2)? 13 => 13
I20200703-09:59:15.934(2)? 22 => 22
I20200703-09:59:15.936(2)? 20 => 20
I20200703-09:59:15.936(2)? 15 => 15
I20200703-09:59:15.939(2)? 14 => 14
I20200703-09:59:15.940(2)? 1 => 1
I20200703-09:59:15.940(2)? 3 => 3
I20200703-09:59:15.943(2)? 12 => 12
【讨论】:
您给出的解决方案仅在同一客户端发出并发请求时才有效。我的要求是从不同的请求中了解方法的执行。对于同一个客户端,我什至可以使用 Meteor 的this.unblock
作为方法,该方法将允许并发执行方法。无论如何,感谢您展示了一种不同的并发请求方式。谢谢。
this.unblock
仅适用于使用 DDP 连接客户端的 Meteor 方法,而 Iron 路由器路由是基于 HTTP 的,因此没有可用的 unblock
。也没有真正的并发,因为节点服务器仍然受到单一威胁,所有传入的请求仍然在单个线程中处理。我宁愿给人的印象是您产生了多个进程并遇到了每个进程都有自己的计数器的问题。在这种情况下,您将不得不依靠 Mongo 集合来坚持反击。
哦.. 是的,我从没想过我在使用铁路由器。 unblock
仅适用于 Meteor 方法。正如您所说,我们需要依靠 mongo 集合来保留一个全局计数器,任何请求的任何进程都可以看到该计数器。 npm 包mongodb-autoincrement
做同样的事情。以上是关于如何在一个请求中等待,直到另一个请求完成 nodeJS 中相同功能的执行的主要内容,如果未能解决你的问题,请参考以下文章
如何等待在 react.js 中渲染视图,直到 $.get() 完成?