Как ждать на http-вызовах в Iron Routers onBeforeAction?
Я хочу создать предварительную загрузку script, которая выполняет несколько асинхронных функций для загрузки внешнего контента. Я довольно близко здесь, но я не совсем понял, как отложить вызов this.next() в моей функции onBeforeAction. В приведенном ниже коде вы можете видеть, что я использую цикл и setTimeout, но я каким-то образом теряю контекст моего маршрутизатора, а this.next() - undefined. Я считаю, что это связано с тем, что моя функция preloadProject заканчивается, и маршрутизатор предупреждает меня, что я забыл вызвать this.next(); до завершения моей функции waitToRender.
if (Meteor.isClient) {
IR_BeforeHooks = {
preloadProject: function() {
var itemsProcessed = 0;
_.each(items.items, function(e) {
HTTP.get(e.S3URL, {
headers: {
'Accept': '*/*'
},
responseType: 'arraybuffer' //requires aldeed:http
}, function(error, result) {
if (error) {
Session.set('error', {
'title': 'Could not download',
'message': error
});
}
if (result) {
itemsProcessed = itemsProcessed + 1;
}
}) //http get
}) //each
function waitToRender(router) {
console.log('waiting...')
var progress = (itemsProcessed / items.items.length) * 100;
if (progress < 100) {
$('.progress-bar').css('width', Math.floor(progress) + '%');
setTimeout((function() {
waitToRender(router);
}), 50);
//console.log('timeout for a few ms here')
}
else {
console.log('all done, render');
router.next(); // I get this is not a function error here
}
}
waitToRender(this);
}
}
}
и мой маршрутизатор
Router.before(
IR_BeforeHooks.preloadProject,
{
only:['editor', 'viewer', 'embedder']
}
);
Из-за сложных требований в моем проекте мне нужно выполнить эти задачи перед рендерингом. Как я могу заставить Iron Router ждать своих HTTP-вызовов, не блокируя браузер?
Ответы
Ответ 1
Я нашел решение. Проблема, как я подозревал, заключалась в том, что Iron Router обнулялся, когда моя основная функция перехвата завершила синхронизацию. Поэтому, чтобы исправить это, я настраиваю свою собственную копию this.next, когда я начинаю свою работу, и вызываю мою копию функции, когда моя работа async завершена.
IR_BeforeHooks = {
preloadProject: function() {
var myNext = this.next;
...//http calls and etc
function waitToRender(router) {
console.log('waiting...')
var progress = (itemsProcessed / items.items.length) * 100;
if (progress < 100) {
...//use set timeout to recall waitToRender
}
else{
myNext();
}
}
}
}
Ответ 2
Поместите router.next()
вне else
блока, даже если вы ничего не визуализируете, вам нужно позвонить next
.
if (progress < 100) {
$('.progress-bar').css('width', Math.floor(progress) + '%');
setTimeout((function() {
waitToRender(router);
}), 50);
//console.log('timeout for a few ms here')
}
else {
console.log('all done, render');
}
router.next();