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()
?
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
É 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.
Comentários muito úteis
Já existe um
renderSync
? Caso contrário, existe uma solução alternativa para umrender
síncrono?Editar: Nvm. Para qualquer pessoa futura que tropeçar nisso, é o que eu fiz: