EN
sancho2934489
sancho2934489
13 июля 2017

Здравствуйте. Пытаюсь собрать блок на основе ответа от сервера через модуль 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', [....] и на этом останавливается, и блок выходит пустой.
tadatuta
#tadatuta
16 июля 2017

Для работы с динамическими данными следует использовать https://github.com/bem/bem-express

За данными ходить в серверной части (папка server в репозитории) и уже готовый ответ передавать для шаблонизации.

Подробнее о схеме шаблонизации в bem-express можно прочитать в https://ru.bem.info/forum/716/

Realetive
#Realetive
16 июля 2017

@tadatuta А почему бы не сам шаблон «научить» (на примере того же bem-express)? Чтобы не дублировать код для клиентской стороны.

tadatuta
#tadatuta
16 июля 2017

@Realetive изначально BEMTREE-шаблоны именно по этой причине и были сделаны асинхронными. Но на практике оказалось, что удобнее держать логику про поход за данными отдельно от слоя про преобразование данных.

Избавиться от дублирования между клиентом и сервером в любом случае не проблема, только лежать общий код будет вне шаблонов.

Realetive
#Realetive
16 июля 2017

@tadatuta, но как? Есть пример? Пытался сделать это в рамках bemtree-шаблона — словил ошибку.

tadatuta
#tadatuta
16 июля 2017

@Realetive в шаблонах сейчас это по определению невозможно, т.к. от асинхронности отказались.

Решать можно примерно так: взять какой-нибудь fetch (для старых браузеров — полифил, для сервера — npm-пакет), так что код похода за данными перестанет зависеть от окружения.

Написать его в отдельных файлах (например, *.vanilla.js) и подключать их как на клиент, так и на сервер. Вариантов тут несколько, я бы предложил заворачивать код в CommonJS-модули, а для клиента в момент сборки либо прогонять через browserify, либо тупо регекспами проходиться, как в enb-bh сделано.

tadatuta
#tadatuta
16 июля 2017

Но если говорить про схему, которая мне кажется более удобной — это всегда без исключения ходить за данными только в серверной части, а с клиента AJAX-ом дергать те же серверные роуты, что и при обычных запросах, но либо опираясь на тот факт, что это XHR-запрос, либо по какому-нибудь query-параметку отдавать не всю страницу целиком, а только нужные чанки готового отшаблонизированного на сервере HTML.

В частности в bem-express для этого в шаблоне написана такая строка: https://github.com/bem/bem-express/blob/master/common.blocks/root/root.bemtree.js#L7

Realetive
#Realetive
16 июля 2017

@tadatuta печалити… Хотел обойтись банальным this.require('axios') в api.bemtree.js. Ясно, ушёл экспериментировать.

Realetive
#Realetive
21 июля 2017

Решил проблему: #1388