在我们的Grails应用程序中,我们使用CMS为我们的应用程序提供GSP模板。 GSP模板包含一些自定义标签(并且我很欣赏)打破了MVC范例 - 它们实际上是迷你MVC,它们获取数据然后渲染一些模板。在伪代码中,它可能看起来像:
def customTag1 = {attrs, body ->
def data = service.getData(attrs)
out << render (template: 'template1', model: data)
}
现在,我们可以和我们一起生活。但是我们的页面上有很多这些标签,对于某些标签,它们可能需要几毫秒才能获得数据。并且当标签同步执行(逐个)时,呈现页面的总时间是所有调用的总和(加上实际呈现的小余量)。
我们尝试做的是提出一种并行(异步)执行标记的方法。
到目前为止,我们已经提出了几种方法,但是没有一种方法可以帮助我们。
首先,我们尝试将模型检索委托给promises,然后在过滤器中等待它们的实现,然后进行标记的呈现。但它在GroovyPageOutputStack
上的竞争条件失败,因为标签正在临时访问它。
我们的第二次尝试是进行两阶段渲染。在第一次运行中,所有自定义标签都不是真正呈现,而只是异步获取其数据(启动承诺)。在第二轮中,一旦承诺完成,我们就会做真实的事情并呈现页面。但是,运行渲染两次的性能损失似乎太高了。
在我们的最后一次尝试中,我们想尝试通过CMS(预处理的类型)复制所有自定义标签,这将允许我们异步收集数据,然后在数据准备好时进行渲染。再次,在伪代码中它可以像:
<a:async>
<c:customTag1 attr1="1" norender="1"/>
<c:customTag2 attr2="2" norender="1"/>
</async>
<c:customTag1 attr1="1"/>
<c:customTag2 attr1="2"/>
这样,一旦所有数据都可用,我们将首先进行繁重的渲染和渲染。
无论如何,你认为有一种更好的异步执行某些标签的方法吗?到目前为止,似乎没有人预料到这样的情况 - 据我所知,GSP渲染看起来非常单线程(一些threadlocals,使用一个GroovyPageOutputStack
等等。)
所有帮助/想法都将受到高度赞赏!