Less.js: So lösen Sie Synchronisierungs- und asynchrone Importe aus

Erstellt am 7. Dez. 2014  ·  26Kommentare  ·  Quelle: less/less.js

Wie entscheidet sich weniger, loadFile oder loadFileSync der aktuellen fileManager callen? Gemäß diesem Code muss ein isSync -Parameter gesetzt werden. Aber eine kurze Suche nach einem Aufruf von getFileManager zeigt, dass diese Option nur von lib/less/functions/data-uri.js .

Ist es möglich, diese Option beim Aufruf von render() explizit zu setzen?

feature request medium priority stale

Hilfreichster Kommentar

Gibt es schon ein renderSync ? Wenn nicht, gibt es eine Problemumgehung für ein synchrones render ?

Edit: Nvm. Für jeden zukünftigen Menschen, der darüber stolpert, habe ich Folgendes getan:

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

Alle 26 Kommentare

isSync kann im Optionsobjekt zum Rendern übergeben werden. data-uri ist immer
synchronisieren, da Funktionen nicht asynchron sein können.

Aber das importManager übergibt keine Option an getFileManager ...

Hier ist es fertig

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

Das liegt daran, dass diese Option von weniger Kern ignoriert wird und nur für den Browser gilt. Der Browser wird also immer als async bezeichnet und kann je nach Option einen Sync- oder Async-Mechanismus verwenden, um die Datei abzurufen.

Ich kann sehen, wie verwirrend das ist. Verursacht es ein Problem?

Eine Sache, die ich sofort sehe, ist, dass es nur durch die Optionen beim Laden der Seite beeinflusst wird, also wenn es danach gesetzt oder als Option übergeben wird, wird es ignoriert.

Nun, wahrscheinlich muss ich meinen Anwendungsfall erklären:

Ich habe einen Less -Loader für webpack geschrieben . Da Webpack über einen eigenen Auflösungsmechanismus verfügt, verwende ich ein Plugin, um sich über einen Dateimanager in weniger Dateiauflösungen einzuklinken.

Webpack unterstützt Sync- und Async-Loader, aber ich habe keine Möglichkeit gefunden, weniger anzugeben, um alle Dateien synchron oder asynchron zu rendern. Derzeit ruft es immer loadFile . Daher habe ich einen schmutzigen Hack verwendet , um loadFileSync aufzurufen, wenn eine synchrone Kompilierung angefordert wird. Weniger funktioniert zum Glück synchron, wenn der Callback synchron aufgerufen wird (was unter normalen Umständen natürlich nicht passieren sollte).

Aha...

Ich denke, wir sollten eine asynchrone Option auf den weniger Kontext verschieben und diese dann verwenden, um zu bestimmen, welcher Aufruf wie von Ihnen vorgeschlagen durchgeführt werden soll. Möglicherweise sind einige Änderungen am Dateimanager des Browsers erforderlich, aber ich denke, es wird eine gute Umgestaltung sein.

Cool!

Es gibt nur ein Problem: Es ist sehr ungewöhnlich, etwas synchron zu tun, während ein callback akzeptiert wird (wie es die render -Funktion tut). Sie schlagen eine sync -Option wie folgt vor:

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

?

Imho ist es komisch, dass der Rückruf synchron aufgerufen wird. Ich würde eine API wie diese erwarten:

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

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

Ja du hast recht, das ist besser.

+1
Es scheint auch sehr nützlich zu sein, die Implementierung von renderSync in Betracht zu ziehen, um die Codeausführung nicht nur im Callback einzuschränken. Im Callback-Bereich geben viele Methoden wie console.err oder throw new Error() oder absichtliche JavaScript-Fehler nichts an die Konsole aus, sondern stoppen nur die Codeausführung, was möglicherweise zu Fehlern führt, die nicht verfolgt werden können. Ich könnte mir vorstellen, dass dieses Verhalten nicht passieren sollte.

In meinem speziellen Fall würde renderSync in einem Befehlszeilen-Dienstprogramm verwendet und anstatt den Callback-Flow mithilfe von Versprechungen zu steuern, um sicherzustellen, dass alle Ausgaben und Fehler jedes Mal in der richtigen Reihenfolge gedruckt werden, würde ich lieber nur renderSync verwenden und nicht haben sich darum zu kümmern.

(Nicht das Problem selbst erniedrigen, sondern nur um sicherzustellen, dass es nicht noch seltsamer wird, als es ist):

Imho ist es komisch, dass der Rückruf synchron aufgerufen wird.

Das ist eine Übertreibung... In dieser Codezeile gehen Sie nicht davon aus, dass die Konfiguration asynchron eingestellt wird, oder?
Rückrufe sind nur Rückrufe, für sich genommen haben sie nichts mit sync/async-Zeug zu tun.

Ok, dann müssen wir über den Begriff callback sprechen: zwinker:.

Ich weiß, einige rufen Funktionen auf, die an forEach a callback (wie MDN ). Ich würde es nicht so nennen, denn für mich ist ein Callback etwas, das aufgerufen wird, wenn eine Aufgabe erledigt ist.

Und wenn der Callback der Fehlerkonvention des Knotens folgt, wobei das erste Argument null oder ein Fehler ist, dann gibt es gute Gründe , ihn _immer_ asynchron aufzurufen.

Ich weiß, einige rufen an forEach als Rückruf auf`

Jemand benutzt einfach zu viel node ;) Jeder nennt dieses Ding "Rückruf". Wenn es also um "eine Callback-Funktion, die aufgerufen wird, wenn eine Aufgabe beendet wurde" geht, ist es nicht weniger als "asynchroner Callback".

Aber egal, sorry, ich wollte nicht wie ein CO klingen und diese rein linguistische Debatte beginnen (wollte nur sicherstellen, dass wir die gleiche Sprache sprechen und in den Dokumenten tatsächlich erwähnt wird, dass less.render synchron ist).

PS Nur um mehr zu verdeutlichen:

@kwketh

Dieses less.render Formular war jahrelang da, man kann es nicht einfach aus dem Nichts nehmen und ändern, um unzählige Schnipsel da draußen zu knacken.

@sieben-phasen-max

Vielen Dank für eure Antworten, sie sind alle hilfreich. Ich stimme allen Ihren Punkten bezüglich Rückrufe zu. Ich habe mir den .render Code ganz kurz angeschaut und du hast recht, die Form, die er geschrieben ist, dreht sich alles um die Rückrufe und scheint weder einfach noch vernünftig renderSync .

Mein Problem ist irgendwie anders, aber verwandt (https://github.com/less/less.js/issues/2546). Die Implementierung der Funktion renderSync würde mein Problem lösen, aber es wäre nicht die ultimative Lösung.

Macht es Ihnen etwas aus, schnell vorbeizuschauen? Ich würde es sehr schätzen.

Vielen Dank.

Jemand verwendet einfach zu viele Knoten

Das stimmt :grins:

Die Callback-Konvention von Node ist jedoch gut etabliert. Ich würde davon ausgehen, dass der Rückruf in diesem Fall immer asynchron aufgerufen wird.

Außerdem: Wie wird mit Fehlern im Fehlerfall umgegangen? Wird es geworfen (wie die meisten Synchronisierungs-APIs) oder als Argument an den Rückruf übergeben?

Es ist nur so, dass die aktuelle API mehrdeutig ist (zumindest imho)

Gibt es schon ein renderSync ? Wenn nicht, gibt es eine Problemumgehung für ein synchrones render ?

Edit: Nvm. Für jeden zukünftigen Menschen, der darüber stolpert, habe ich Folgendes getan:

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

Ist diese Funktion tatsächlich implementiert? Gibt es eine Dokumentation? Ich kann nur die async -Option finden.

Ich weiß, ob es tatsächlich unterstützt wird, aber ich weiß, was ich getan habe, funktioniert derzeit für mich, also.... Achselzucken

@Aarilight vielen Dank, dein Code hat sehr geholfen

Dieses synchrone Callback-Verhalten ist wirklich kontraintuitiv :confused:

@Aarilight es funktioniert nicht für mich =(
Ich habe es versucht

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

        output = result;
        return result
    });

und protokolliert 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')

Und ich sehe 1, 8 und dann 2,3,4,5,6,7 für einige Dateien

-1 zum Aufteilen des Renderns in render und renderSync . Es ist eine Node.js-Konvention, die umständlich ist. Und es erlaubt nicht, eine Synchronisierungsoption an Grunt / Gulp / Accord oder andere in Less integrierte Workflows zu senden, die ein JS-Objekt an eine bestimmte Funktion übergeben. IMO ist es in Ordnung, einen optionalen Rückruf zu übergeben, wenn eine asynchrone Option verwendet wird.

Eine andere Option: Was ich gesehen habe, ist, dass Bibliotheken in beiden Fällen tatsächlich ein Versprechen zurückgeben. Dann ändert sich nur zwischen sync / async, wenn das Versprechen erfüllt ist, aber der Code, der das Ergebnis verarbeitet, ist genau derselbe.

Und übrigens:

{sync: true}

Es gibt keine solche Option.

-1 zum Aufteilen von Rendern in Render und RenderSync. Es ist eine Node.js-Konvention, die umständlich ist.

Ist das nicht eine völlig subjektive Sichtweise? IMHO die Kombination von Async und Sync in einer einzigen Funktion ist (mit wenigen Ausnahmen) ein schreckliches Anti-Muster. Es erzeugt Code, der mit bedingten Anweisungen überladen ist, schwieriger zu warten ist und für den Benutzer noch verwirrender ist als eine klar definierte und dokumentierte Funktion, die eines gut macht. nur meine 2c

Ist das nicht eine völlig subjektive Sichtweise?

Jawohl.

Unabhängig davon ist mein anderer Punkt nicht subjektiv. Das heißt, Less wird in Buildprozessen verwendet, die möglicherweise aktualisiert werden müssen, wenn eine Funktion geteilt wird. Zum Beispiel: Accord (https://github.com/jenius/accord), das ich derzeit für ein Projekt verwende, abstrahiert verschiedene Compiler in eine einzige API und übergibt normalerweise ein Objekt an jede Funktion, die diese Engine benötigt. Es ist also wahrscheinlich keine große Sache zu ändern, welche Funktion basierend auf den Less-Optionen eines Entwicklers verwendet wird, aber ich bin mir nicht sicher, wie viele Bibliotheken das betreffen würde. Es ist nur etwas, dessen man sich bewusst sein sollte.

Ab sofort hat das Hinzufügen von syncImport: true zu meinen Optionen dies für mich behoben.

(Es steht nicht in der Dokumentation ... ich hatte nur das Glück, im Quellcode darüber zu stolpern)

Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivität hatte. Es wird geschlossen, wenn keine weitere Aktivität stattfindet. Vielen Dank für Ihre Beiträge.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen