异步并行请求 - 部分渲染

Posted

技术标签:

【中文标题】异步并行请求 - 部分渲染【英文标题】:async parallel request - partial render 【发布时间】:2013-04-23 06:04:45 【问题描述】:

在异步并行请求之后部分呈现视图的正确方法是什么?

目前我正在做以下事情

// an example using an object instead of an array
async.parallel(
    one: function(callback)
        setTimeout(function()
            callback(null, 1);
            // can I partially merge the results and render here?
        , 200);
    ,
    two: function(callback)
        setTimeout(function()
            callback(null, 2);
            // can I partially merge the results and render here?
        , 100);
    
,
function(err, results) 
    // results is now equals to: one: 1, two: 2
    // merge the results and render a view
    res.render('mypage.ejs',  title: 'Results');

);

它基本上工作正常,但是,如果我有 function1, function2, ..., functionN,则只有在最慢的功能完成时才会呈现视图。

我想找到正确的方法,以便能够在第一个函数返回时立即渲染视图,以最大限度地减少用户延迟,并在函数结果可用时立即添加。

【问题讨论】:

如果功能以随机顺序完成,您希望它如何工作?我怀疑你可以像这样发送部分数据(以随机顺序)。您是否考虑过从客户端执行多个部分请求? 【参考方案1】:

你想要的是 facebook 的 bigpipe:https://www.facebook.com/note.php?note_id=389414033919。幸运的是,使用 nodejs 这很容易,因为流是内置的。不幸的是,模板系统在这方面做得不好,因为异步模板很麻烦。但是,这比执行任何其他 AJAX 请求要好得多。

基本思路是你先发送一个布局:

res.render('layout.ejs', function (err, html) 
  if (err) return next(err)

  res.setHeader('Content-Type', 'text/html; charset=utf-8')
  res.write(html.replace('</body></html>', ''))

  // Ends the response. 
  // `writePartials` should not return anything in the callback!
  writePartials(res.end.bind(res, '</body></html>'))
)

您无法发送&lt;/body&gt;&lt;/html&gt;,因为您的文档尚未完成。那么writePartials 将是一堆并行执行的异步函数(partials 或 pagelet)。

function writePartials(callback) 
  async.parallel([partial1, partial2, partial3], callback)
)

注意:由于您已经编写了响应,因此除了记录错误之外,您无能为力。

每个部分的作用是将内联 javascript 发送到客户端。例如,布局可以有.stream,pagelet 将在到达时或“回调完成”时替换.streaminnerHTML

function partialStream(callback) 
  res.render('stream.partial.ejs', function (err, html) 
    // Don't return the error in the callback
    // You may want to display an error message or something instead
    if (err) 
      console.error(err.stack)
      callback()
      return
    

    res.write('<script>document.querySelector(".stream").innerHTML = ' + 
      JSON.stringify(html) + ';</script>')
    callback()
  )
)

就个人而言,我有 .stream.placeholder 并将其替换为新的 .stream 元素。原因是我基本上做.placeholder, .placeholder ~ * display: none 所以事情不会在页面上跳转。但是,这需要一个 DIY 前端框架,因为突然 JS 变得更加复杂。

在那里,您的回复正在流式传输。唯一的要求是客户端支持Javascript。

【讨论】:

有趣的方法。我以为 res.render 会提交流,但我想那时不会。 只有在没有回调的情况下才会结束流 确实是出色而干净的解决方案,谢谢。它就像一个魅力。我现在需要在客户端上处理 JS 以根据需要重新排序结果,但是“证明留作练习”(对我来说 :-)) 哎呀。我忘了用&lt;/body&gt;&lt;/html&gt; 完成回复。【参考方案2】:

我认为你不能只在后端这样做。

为了最大限度地减少用户的延迟,您需要将最小页面发送到浏览器,然后通过 AJAX 从浏览器请求其余信息。另一种最小化延迟的方法是在第一个页面加载时将所有模板与渲染页面一起发送到浏览器,并根据您从服务器请求的数据在浏览器中渲染所有页面。我就是这样做的。 nodejs 的美妙之处在于您可以在后端和前端使用相同的模板引擎,并且还可以共享模块。

如果您的页面以这样一种方式组成,即慢速信息在 HTML 中比快速信息更远,您可以在不使用 res.render(呈现完整页面)的情况下部分编写响应,并改用 res.write。我不认为这种方法值得认真关注,因为你会在注意到之前就坚持下去......

【讨论】:

当然可以,但这并不容易:facebook.com/note.php?note_id=389414033919 从来没想过,谢谢...我需要弄清楚如何才能将仍在下载的数据(我的意思是在浏览器中)作为同一响应的一部分。我假设有一些浏览器事件......

以上是关于异步并行请求 - 部分渲染的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET 异步/等待第 2 部分

Ajax

嵌套组件页面渲染完了还请求不到数据

根据 ajax 请求渲染多个刀片视图部分

用Ajax异步更新网页

用 node.js 模仿 Apache 的部分功能