Здравствуйте. Пытаюсь собрать блок на основе ответа от сервера через модуль http. У блока в *.bemhtml.js выполняю запрос и заполняю блок на основе ответа в callback-функции. Но сборщик не дожидается ответа и строит html дальше. Естественно блок выходит пустой. Как быть в этом случае?
var http = require('http');
var options = {
host: 'localhost',
path: '/TESTindex.php'
};
callback = function(response) {
var str = '';
//another chunk of data has been recieved, so append it to `str`
response.on('data', function (chunk) {
str += chunk;
});
//the whole response has been recieved, so we just print it out here
response.on('end', function () {
var items = JSON.parse(str);
var response = [];
for (var i = 0;i < items.length;i++) {
item = items[i];
response[i] = {
title: item
};
}
console.log('resp', response);
createBlock(response);
});
};
var createBlock = function (items) {
console.log('1',items);
block('testmenu').elem('content')(
content()(function() {
console.log('1,5');
this.ctx.items = items;
console.log('2',this.ctx.items);
return this.ctx.items.map(function(item) {
console.log('3',item);
return {
elem: 'item',
content: [
{
elem: 'title',
content: item.title
}
]
};
});
})
);
};
createBlock([
{
title: 'Один'
},
{
title: 'Два'
},
{
title: 'Три'
}
]); // Если выполнить этот вариант, то блок строится правильно
http.request(options, callback).end(); // Если выполнить этот вариант, то в консоль выводится только '1', [....] и на этом останавливается, и блок выходит пустой.
Для работы с динамическими данными следует использовать https://github.com/bem/bem-express
За данными ходить в серверной части (папка
server
в репозитории) и уже готовый ответ передавать для шаблонизации.Подробнее о схеме шаблонизации в
bem-express
можно прочитать в https://ru.bem.info/forum/716/@tadatuta А почему бы не сам шаблон «научить» (на примере того же
bem-express
)? Чтобы не дублировать код для клиентской стороны.@Realetive изначально BEMTREE-шаблоны именно по этой причине и были сделаны асинхронными. Но на практике оказалось, что удобнее держать логику про поход за данными отдельно от слоя про преобразование данных.
Избавиться от дублирования между клиентом и сервером в любом случае не проблема, только лежать общий код будет вне шаблонов.
@tadatuta, но как? Есть пример? Пытался сделать это в рамках bemtree-шаблона — словил ошибку.
@Realetive в шаблонах сейчас это по определению невозможно, т.к. от асинхронности отказались.
Решать можно примерно так: взять какой-нибудь
fetch
(для старых браузеров — полифил, для сервера — npm-пакет), так что код похода за данными перестанет зависеть от окружения.Написать его в отдельных файлах (например,
*.vanilla.js
) и подключать их как на клиент, так и на сервер. Вариантов тут несколько, я бы предложил заворачивать код в CommonJS-модули, а для клиента в момент сборки либо прогонять черезbrowserify
, либо тупо регекспами проходиться, как вenb-bh
сделано.Но если говорить про схему, которая мне кажется более удобной — это всегда без исключения ходить за данными только в серверной части, а с клиента AJAX-ом дергать те же серверные роуты, что и при обычных запросах, но либо опираясь на тот факт, что это XHR-запрос, либо по какому-нибудь query-параметку отдавать не всю страницу целиком, а только нужные чанки готового отшаблонизированного на сервере HTML.
В частности в
bem-express
для этого в шаблоне написана такая строка: https://github.com/bem/bem-express/blob/master/common.blocks/root/root.bemtree.js#L7@tadatuta печалити… Хотел обойтись банальным
this.require('axios')
вapi.bemtree.js
. Ясно, ушёл экспериментировать.Решил проблему: #1388