2013-04-29 3 views
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 мнение будет оказана только тогда, когда медленная функция будет завершена.

Я хотел бы найти правильный способ визуализации представления, как только первая функция вернется, чтобы свести к минимуму задержку пользователя и добавить результаты функции, как только они будут доступны.

+0

Как вы ожидали, что он будет работать, если функции будут выполнены в случайном порядке? Я сомневаюсь, что вы могли бы отправить частичные данные (в случайном порядке).Вы считали, что вместо этого выполняете несколько частичных запросов от клиента? – NilsH

ответ

5

то, что вам нужно, это большая трубка Facebook: 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, и проспект будет заменен .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.

+0

Интересный подход. Я думал, что res.render будет передавать поток, но я полагаю, что это не так. – NilsH

+0

он только закончит поток, если он не имеет обратного вызова –

+0

Очень приятно! +1 от меня – NilsH

1

Я думаю, вы не можете сделать это только на бэкэнде.

Чтобы свести к минимуму задержку пользователя, вам необходимо отправить минимальную страницу в браузер, а затем запросить остальную информацию из браузера через AJAX. Другим подходом к минимизации задержек является отправка всех шаблонов в браузер при загрузке первой страницы вместе с отображаемой страницей и отображение всех страниц в браузере на основе данных, запрашиваемых с сервера. Так я это делаю. Красота nodejs заключается в том, что вы можете использовать один и тот же механизм шаблонов как в бэкэнд, так и в интерфейсе, а также совместно использовать модули.

Если ваша страница составлена ​​таким образом, что медленная информация в HTML более длинная, чем быстрая информация, вы можете написать ответ частично, не используя res.render (который делает полную страницу) и вместо этого используйте res.write. Я не думаю, что этот подход заслуживает серьезного внимания, поскольку вы застряли бы с ним раньше, чем вы заметили ...

+1

уверен, что вы можете, но это непросто: https://www.facebook.com/note.php?note_id=389414033919 –

+0

никогда не думал об этом, спасибо ... Мне нужно выяснить, как я могу получить данные, которые все еще загружается (в браузере я имею в виду) как часть одного и того же ответа. Есть некоторые события в браузере, которые я предполагаю ... – esp