Less.js: Como acionar importações de sincronização e assíncronas

Criado em 7 dez. 2014  ·  26Comentários  ·  Fonte: less/less.js

Como less decide chamar loadFile ou loadFileSync do fileManager atual? De acordo com este código, é necessário definir um parâmetro isSync . Mas uma breve pesquisa por uma chamada para getFileManager revela que essa opção só é usada por lib/less/functions/data-uri.js .

É possível definir essa opção explicitamente ao chamar render() ?

feature request medium priority stale

Comentários muito úteis

Já existe um renderSync ? Caso contrário, existe uma solução alternativa para um render síncrono?

Editar: Nvm. Para qualquer pessoa futura que tropeçar nisso, é o que eu fiz:

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;
};

Todos 26 comentários

isSync pode ser passado no objeto de opções para renderizar. data-uri é sempre
sincronizar porque as funções não podem ser assíncronas.

Mas o importManager não passa nenhuma opção para getFileManager ...

É feito aqui

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

É porque essa opção é ignorada por menos núcleo e é específica apenas para o navegador. Portanto, o navegador sempre é chamado de async e pode, dependendo das opções, usar um mecanismo de sincronização ou async para obter o arquivo.

Eu posso ver como isso é confuso. Isso está causando um problema?

Uma coisa que vejo imediatamente é que só será afetado pelas opções no carregamento da página, portanto, se for definido posteriormente ou passado como uma opção, será ignorado.

Bem, provavelmente eu tenho que explicar meu caso de uso:

Eu escrevi um less-loader para webpack . Como o webpack tem um mecanismo de resolução próprio, estou usando um plug-in para ligar a menos resolução de arquivo por meio de um gerenciador de arquivos.

Webpack oferece suporte a carregadores de sincronização e assíncronos, mas não encontrei uma maneira de dizer menos para processar todos os arquivos de forma sincronizada ou assíncrona. Atualmente, ele sempre chama loadFile . Portanto, usei um hack sujo para chamar loadFileSync quando uma compilação síncrona é solicitada. Felizmente, o less funciona de forma síncrona quando o retorno de chamada é chamado de forma síncrona (o que não deveria ser feito em circunstâncias normais, é claro).

Eu vejo...

Acho que devemos mover uma opção assíncrona para estar no contexto menos e, em seguida, usar isso para determinar qual chamada fazer como você sugere. Pode ser necessário fazer algumas alterações no gerenciador de arquivos do navegador, mas acho que será um bom refatorador.

Legal!

Há apenas um problema: é muito incomum fazer algo de forma síncrona enquanto aceita um callback (como faz a função render ). Você está sugerindo uma sync -opção como esta:

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

?

Imho, é estranho ter o callback sendo chamado de forma síncrona. Eu esperaria uma API como esta:

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

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

Sim, você está certo, isso é melhor.

+1
Parece que também é muito útil considerar a implementação de renderSync para não restringir a execução do código apenas no retorno de chamada. No escopo de retorno de chamada, muitos métodos como console.err ou throw new Error() ou erro deliberado de JavaScript não imprimirão nada no console, apenas interromperão a execução do código, potencialmente levando a bugs que não podem ser rastreados. Eu imagino que esse comportamento não deva acontecer.

No meu caso particular renderSync seria usado em um utilitário de linha de comando e em vez de controlar o fluxo de retorno de chamada usando promessas para garantir que todas as saídas e erros sejam impressos em ordem a cada vez, prefiro apenas usar renderSync e não se preocupar com isso.

(Não rebaixando o problema em si, mas apenas para garantir que não fique ainda mais estranho do que é):

Imho, é estranho ter o callback sendo chamado de forma síncrona.

Isso é um exagero ... Nesta linha do código, você não está assumindo que a configuração está definida de forma assíncrona, está?
Callbacks são apenas callbacks, por si só eles não têm nada a ver com coisas sincronizadas / assíncronas.

Ok, então precisamos falar sobre o termo callback : wink :

Eu sei, alguns chamam funções passadas para forEach a callback (como MDN ). Eu não chamaria assim, porque para mim um retorno de chamada é algo que é chamado quando uma tarefa é concluída.

E se o retorno de chamada segue a convenção de erro do nó com o primeiro argumento sendo null ou um erro, então há boas razões para _sempre_ chamá-lo de forma assíncrona.

Eu sei, alguns chamam funções passadas para forEach a callback`

Alguém está usando muito node ;) Todo mundo chama isso de "retorno de chamada". Portanto, se se trata de "uma função de retorno de chamada chamada quando uma tarefa foi concluída", não é mais nada menos do que "retorno de chamada assíncrono".

Mas não importa, desculpe, eu não queria soar como um CO e começar este debate puramente linguístico (só queria garantir que falamos a mesma língua e que os documentos realmente mencionam que less.render é síncrono).

PS Só para esclarecer mais:

@kwketh

Este formulário less.render esteve lá por anos, você não pode simplesmente pegar e transformá-lo do nada para quebrar zilhões de fragmentos por aí.

@ sete fases-máx.

Muito obrigado por suas respostas, todas são úteis. Eu concordo com todos os seus pontos sobre retornos de chamada. Dei uma olhada rápida no código .render e você está certo, a forma como está escrito, tudo gira em torno dos callbacks e não parece nem fácil nem razoável ter renderSync .

Meu problema é de alguma forma diferente, mas relacionado (https://github.com/less/less.js/issues/2546). Implementar o recurso renderSync resolveria meu problema, mas não seria a solução definitiva.

Você se importa em dar uma olhada rápida? Eu realmente apreciaria.

Obrigado.

Alguém está usando muito nó

Bem, isso é verdade: sorriso:

Mas a convenção de retorno de chamada do nó está bem estabelecida. Eu presumo que o retorno de chamada seja sempre chamado de forma assíncrona neste caso.

Além disso: como os erros são tratados quando há um erro? É lançado (como a maioria das APIs de sincronização) ou passado como argumento para o retorno de chamada?

É que a API atual é ambígua (pelo menos imho)

Já existe um renderSync ? Caso contrário, existe uma solução alternativa para um render síncrono?

Editar: Nvm. Para qualquer pessoa futura que tropeçar nisso, é o que eu fiz:

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;
};

Este recurso está realmente implementado? Existe alguma documentação? Só consigo encontrar a opção async .

Eu sei se é realmente compatível, mas sei que o que fiz funciona para mim atualmente, então ... encolher os ombros

@Aarilight muito obrigado, seu código ajudou muito

Esse comportamento de retorno de chamada síncrono é realmente contra-intuitivo: confused:

@Aarilight não funciona para mim = (
eu tentei

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

        output = result;
        return result
    });

e registrou 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')

E eu vejo 1, 8 e 2,3,4,5,6,7 para alguns arquivos

-1 para dividir a renderização em render e renderSync . É uma convenção do Node.js que é estranha. E não permite o envio de uma opção de sincronização para grunhir / engolir / concordar ou outros fluxos de trabalho integrados em menos que passam em um objeto JS para uma função designada. IMO, não há problema em passar um retorno de chamada opcional ao usar uma opção assíncrona.

Outra opção: o que vi as bibliotecas começarem a fazer é, na verdade, retornar uma promessa em ambos os casos. Então, tudo o que muda entre sync / async é quando a promessa é cumprida, mas o código que trata o resultado é exatamente o mesmo.

E aliás:

{sync: true}

Essa opção não existe .

-1 para dividir render em render e renderSync. É uma convenção do Node.js que é estranha.

Não é um ponto de vista totalmente subjetivo? IMHO combinando async e sync em uma única função é (com poucas exceções) um anti-padrão terrível. Ele cria um código cheio de instruções condicionais, é mais difícil de manter e ainda mais confuso para o usuário do que uma função claramente definida e documentada que faz uma coisa bem. apenas meu 2c

Não é um ponto de vista totalmente subjetivo?

sim.

Independentemente disso, meu outro ponto não é subjetivo. Ou seja, esse Less é usado em processos de construção que podem precisar ser atualizados se uma função for dividida. Por exemplo: Accord (https://github.com/jenius/accord), que atualmente uso para um projeto, abstrai diferentes compiladores em uma única API e normalmente passa em um objeto para qualquer função que o mecanismo requer. Portanto, provavelmente não é um grande negócio alternar qual função é usada com base nas opções de Menos que um desenvolvedor especifica, mas não tenho certeza de quantas bibliotecas isso afetaria. É apenas algo a ter em conta.

A partir de agora, adicionar syncImport: true às minhas opções corrigiu isso para mim.

(Não está na documentação ... Tive a sorte de topar com isso no código-fonte)

Este problema foi marcado automaticamente como obsoleto porque não teve atividades recentes. Ele será fechado se nenhuma outra atividade ocorrer. Obrigado por suas contribuições.

Esta página foi útil?
0 / 5 - 0 avaliações