Less.js: Как запустить синхронизацию и асинхронный импорт

Созданный на 7 дек. 2014  ·  26Комментарии  ·  Источник: less/less.js

Как less решает вызвать loadFile или loadFileSync из текущего fileManager ? Согласно этому коду требуется установить параметр isSync . Но короткий поиск по вызову getFileManager показывает, что эта опция используется только lib/less/functions/data-uri.js .

Можно ли явно установить эту опцию при вызове render() ?

feature request medium priority stale

Самый полезный комментарий

Есть еще renderSync ? Если нет, есть ли обходной путь для синхронного render ?

Изменить: Nvm. Для любого будущего человека, который наткнется на это, я сделал следующее:

less.renderSync = function (input, options) {
    if (!options || typeof options != "object") options = {};
    options.sync = true;
    var css;
    this.render(input, options, function (err, result) {
        if (err) throw err;
        css = result.css;
    });
    return css;
};

Все 26 Комментарий

isSync можно передать в объекте параметров для рендеринга. data-uri всегда
синхронизировать, потому что функции не могут быть асинхронными.

Это сделано здесь

https://github.com/less/less.js/blob/32dbbee247f76af00eb7577053eccad2ee5f6110/lib/less-browser/file-manager.js#L61

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

Я понимаю, насколько это сбивает с толку. Это вызывает проблемы?

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

Что ж, наверное, мне нужно объяснить свой вариант использования:

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

Webpack поддерживает синхронизирующие и асинхронные загрузчики, но я не нашел способа сказать меньше, чтобы отображать все файлы синхронно или асинхронно. В настоящее время он всегда вызывает loadFile . Таким образом, я использовал грязный прием для вызова loadFileSync когда запрашивается синхронная компиляция. К счастью, less работает синхронно, когда обратный вызов вызывается синхронно (что, конечно, не должно выполняться при нормальных обстоятельствах).

Я понимаю...

Я думаю, мы должны переместить параметр async в контекст less, а затем использовать его, чтобы определить, какой вызов сделать, как вы предлагаете. Возможно, потребуется несколько изменений в файловом менеджере браузера, но я думаю, что это будет хороший рефакторинг.

Прохладный!

Есть только одна проблема: очень необычно делать что-то синхронно, принимая callback (как это делает render -функция). Вы предлагаете такую sync -опцию:

less.render(
    input,
    { ... sync: true ... },
    function (err, result) {
    }
);

?

Имхо странно, что обратный вызов вызывается синхронно. Я бы ожидал, что API будет таким:

// async
less.render(input, option, callback);

// sync
var result = less.renderSync(input, option);

Да вы правы, так лучше.

+1
Кажется, также очень полезно рассмотреть возможность реализации renderSync чтобы не ограничивать выполнение кода только в обратном вызове. В области обратного вызова многие методы, такие как console.err или throw new Error() или преднамеренная ошибка JavaScript, ничего не выводят на консоль, а только останавливают выполнение кода, что может привести к ошибкам, которые невозможно отследить. Я бы предположил, что такого поведения не должно быть.

В моем конкретном случае renderSync будет использоваться в утилите командной строки, и вместо того, чтобы контролировать поток обратного вызова с помощью обещаний, чтобы каждый раз выводить все выходные данные и ошибки, я бы предпочел просто использовать renderSync и не иметь беспокоиться об этом.

(Не умаляя саму проблему, а просто чтобы убедиться, что она не станет еще более странной, чем есть на самом деле):

Имхо странно, что обратный вызов вызывается синхронно.

Это преувеличение ... В этой строке кода вы не предполагаете, что конфигурация установлена ​​асинхронно, не так ли?
Обратные вызовы - это просто обратные вызовы, сами по себе они не имеют ничего общего с синхронизацией / асинхронностью.

Хорошо, теперь нам нужно поговорить о термине callback : wink :.

Я знаю, что некоторые действительно вызывают функции, переданные в forEach a callback (например, MDN ). Я бы не назвал это так, потому что для меня обратный вызов - это то, что вызывается, когда задача завершена.

И если обратный вызов следует соглашению об ошибке узла с первым аргументом null или ошибкой, то есть веские причины _ всегда_ вызывать его асинхронно.

Я знаю, некоторые действительно вызывают функции, переданные в forEach a callback`

Кто-то просто использует слишком много node ;) Все называют это «обратным вызовом». Так что, если речь идет о «функции обратного вызова, вызываемой после завершения задачи», это не более, чем «асинхронный обратный вызов».

Но ничего, извините, я не хотел говорить, как командир, и начинать эту чисто лингвистическую дискуссию (просто хотел убедиться, что мы говорим на одном языке, и в документации действительно упоминается, что less.render является синхронным).

PS Просто чтобы уточнить:

@kwketh

Эта форма less.render существовала годами, вы не можете просто взять и изменить ее на пустом месте, чтобы сломать множество фрагментов.

@ семь фаз-макс

Большое спасибо за ваши ответы, все они полезны. Я согласен со всеми вашими замечаниями по поводу обратных звонков. Я очень кратко взглянул на код .render и вы правы, форма его написания, все вращается вокруг обратных вызовов, и не кажется ни легким, ни разумным иметь renderSync .

Моя проблема как-то отличается, но связана (https://github.com/less/less.js/issues/2546). Реализация функции renderSync решит мою проблему, но не является окончательным решением.

Не могли бы вы быстро взглянуть? Я был бы очень признателен.

Спасибо.

Кто-то просто использует слишком много узлов

Ну это правда

Но соглашение об обратном вызове узла хорошо известно. Я предполагаю, что в этом случае обратный вызов всегда будет вызываться асинхронно.

Кроме того: как обрабатываются ошибки при возникновении ошибки? Выдается ли он (как большинство API синхронизации) или передается в качестве аргумента обратному вызову?

Просто текущий API неоднозначен (по крайней мере, имхо)

Есть еще renderSync ? Если нет, есть ли обходной путь для синхронного render ?

Изменить: Nvm. Для любого будущего человека, который наткнется на это, я сделал следующее:

less.renderSync = function (input, options) {
    if (!options || typeof options != "object") options = {};
    options.sync = true;
    var css;
    this.render(input, options, function (err, result) {
        if (err) throw err;
        css = result.css;
    });
    return css;
};

Реализована ли эта функция на самом деле? Есть ли документация? Я могу найти только вариант async .

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

@Aarilight большое спасибо, ваш код очень помог

Такое поведение синхронного обратного вызова действительно противоречит интуиции: confused:

@Aarilight у меня не работает = (
Я пытался

less.render(css, {sync : true}, (e, result) =>{
        if(e) {
         console.error(e)
    }

        output = result;
        return result
    });

и вошли https://github.com/less/less.js/blob/master/lib/less/render.js

            console.log('1')
            this.parse(input, options, function(err, root, imports, options) {
                console.log('2')
                if (err) { return callback(err); }

                var result;
                console.log('3')
                try {
                    console.log('4')
                    var parseTree = new ParseTree(root, imports);
                    console.log('5')
                    result = parseTree.toCSS(options);
                }
                catch (err) { 
                    console.log('6')
                    return callback(err); 
                }

                console.log('7')
                callback(null, result);
            });
            console.log('8')

И я вижу 1, 8, а затем 2,3,4,5,6,7 для некоторых файлов

-1 для разделения рендера на render и renderSync . Это неудобное соглашение Node.js. И это не позволяет отправлять параметр синхронизации в grunt / gulp / accord или другие рабочие процессы, интегрированные в less, которые передают объект JS в назначенную функцию. ИМО, можно передать дополнительный обратный вызов при использовании параметра async.

Другой вариант: то, что, как я видел, начинают делать библиотеки, в любом случае фактически возвращает обещание. Затем все, что меняется между синхронизацией / асинхронностью, - это когда обещание выполняется, но код, обрабатывающий результат, остается точно таким же.

И кстати:

{sync: true}

Там нет такой опции.

-1 для разделения рендеринга на render и renderSync. Это неудобное соглашение Node.js.

Разве это не полностью субъективная точка зрения? ИМХО, объединение асинхронности и синхронизации в одной функции (за некоторыми исключениями) является ужасным антипаттерном. Он создает код, загроможденный условными операторами, который труднее поддерживать и еще больше сбивает с толку пользователя, чем четко определенная и задокументированная функция, которая хорошо выполняет одну задачу. только мой 2с

Разве это не полностью субъективная точка зрения?

да.

Тем не менее, другая моя точка зрения не является субъективной. То есть Less используется в процессах сборки, которым может потребоваться обновление, если функция разделена. Например: Accord (https://github.com/jenius/accord), который я сейчас использую для одного проекта, абстрагирует разные компиляторы в один API и обычно передает объект любой функции, которую требует движок. Таким образом, вероятно, не так уж и сложно переключить, какая функция используется, на основе параметров Less, указанных разработчиком, но я не уверен, на сколько библиотек это повлияет. Это просто то, о чем нужно знать.

На данный момент добавление syncImport: true к моим параметрам исправило это для меня.

(Этого нет в документации ... Мне просто посчастливилось наткнуться на это в исходном коде)

Эта проблема была автоматически помечена как устаревшая, поскольку в последнее время не было активности. Он будет закрыт, если больше не будет активности. Спасибо за ваш вклад.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги