4

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

目前我正在做以下事情

// 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视图,只有在最慢的功能完成时才会呈现视图。

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

4

2 回答 2

5

你想要的是 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>'))
})

您无法发送</body></html>,因为您的文档尚未完成。然后writePartials将是一堆并行执行的异步函数(部分或小页面)。

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

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

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

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。

于 2013-04-29T20:34:20.343 回答
1

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

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

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

于 2013-04-29T19:03:38.560 回答