Was bedeuten doppelte Klammern in Javascript und wie kann man darauf zugreifen?


76

Lage

Ich habe die folgende Funktion, die Promise verwendet .

var getDefinitions = function() {
    return new Promise(function(resolve) {
        resolve(ContactManager.request("definition:entities"));
    });
}

var definitions = getDefinitions()

Der Inhalt von definitionsist:

Promise {
    [[PromiseStatus]]: "resolved",
    [[PromiseValue]]: child
}

Der PromiseValuedirekte Zugriff auf die Eigenschaft gibt undefiniert zurück

var value = definitions.PromiseValue; // undefined

Frage

Was bedeuten die doppelten Klammern [[ ]]bedeuten, und wie rufe ich den Wert [[PromiseValue]].


2
Es wäre hilfreich zu wissen, welche Bibliothek Sie verwenden.
JJJ

4
Ähm, ich glaube, ich verwende die eingebaute Javascript-Bibliothek mit Chrome (??)
Jeff

2
Es sieht so aus, als würde der Versprechenszustand genau so beschrieben. Sie können dies in der Konsole von Chrome versuchen : new Promise(function(){}). Das [[PromiseStatus]]von Chrome kann mit dem <state>von Firefox verglichen werden . Ich verstehe nicht wirklich, worum es hier geht (vorausgesetzt, OP weiß, was ein Versprechen ist).
Denys Séguret

1
@ Jeff soweit ich das beurteilen kann, zeigt Chrome Ihnen auf diese Weise den Stand des Versprechens. Diese Eigenschaften sind außerhalb des Objekts absichtlich nicht sichtbar. Wenn Sie sich ein Promise-Objekt in Firefox ansehen, wird es nicht so dargestellt. Ich denke, es ist wahrscheinlich nur als diagnostische Hilfe gedacht.
Pointy

1
Was ist ContactManager.request("definition:entities")?
Benjamin Gruenbaum

Antworten:


105

Was ist das Zeug drin? [[]]

Meine Frage ist, was die doppelten Klammern [[]] bedeuten und wie ich den Wert von [[PromiseValue]] abrufe.

Es ist eine interne Eigenschaft. Sie können nicht direkt darauf zugreifen. Native Versprechungen können nur thenmit Versprechungen oder allgemein asynchron ausgepackt werden - siehe So geben Sie die Antwort von einem asynchronen Aufruf zurück . Zitieren der Spezifikation:

Sie werden durch diese Spezifikation ausschließlich zu Expository-Zwecken definiert. Eine Implementierung von ECMAScript muss sich so verhalten, als würde sie interne Eigenschaften auf die hier beschriebene Weise erzeugen und bearbeiten. Die Namen der internen Eigenschaften sind in doppelten eckigen Klammern [[]] eingeschlossen . Wenn ein Algorithmus eine interne Eigenschaft eines Objekts verwendet und das Objekt die angegebene interne Eigenschaft nicht implementiert, wird eine TypeError-Ausnahme ausgelöst.

Du kannst nicht

Im Ernst - was sind sie?

Sehr schön! Wie aus dem obigen Zitat hervorgeht, werden sie nur in der Spezifikation verwendet. Es gibt also keinen Grund, warum sie wirklich in Ihrer Konsole angezeigt werden.

Sagen Sie es niemandem, aber dies sind wirklich private Symbole . Der Grund dafür ist, dass andere interne Methoden darauf zugreifen können [[PromiseValue]]. Wenn io.js beispielsweise beschließt, Versprechen zurückzugeben, anstatt Rückrufe entgegenzunehmen, kann io.js schnell auf diese Eigenschaften zugreifen, wenn dies garantiert ist. Sie sind nicht nach außen ausgesetzt.

Kann ich darauf zugreifen?

Nur wenn Sie Ihren eigenen Chrome- oder V8-Build erstellen. Möglicherweise in ES7 mit Zugriffsmodifikatoren. Ab sofort gibt es keine Möglichkeit, da sie nicht Teil der Spezifikation sind und über alle Browser hinweg funktionieren - sorry.

Wie bekomme ich meinen Wert?

getDefinitions().then(function(defs){
    //access them here
});

Was aber, wenn ein Fehler zurückgegeben wird? Fügen Sie in Bezug auf diese Fälle Folgendes am Ende (und außerhalb) Ihrer .then () hinzu.

.catch(function(defs){
    //access them here
});

Obwohl, wenn ich raten müsste - Sie konvertieren die API zunächst nicht richtig, da diese Konvertierung nur funktionieren würde, wenn die Methode synchron ist (in diesem Fall kein Versprechen zurückgeben) oder wenn sie bereits ein Versprechen zurückgibt, das gemacht wird es wurde behoben (was bedeutet, dass Sie die Konvertierung überhaupt nicht benötigen - nur return.


Darüber hinaus sollte gesagt werden, dass es vollständig gegen den Zweck von a läuft Promise, auf seinen umschlossenen Wert außerhalb von zuzugreifen then. Der Zweck von a Promisebesteht darin, vom fehlenden Rückgabewert einer nicht blockierenden Funktion zu abstrahieren, dh a Promiserepräsentiert einen "zukünftigen Wert". Sobald man diesen "zukünftigen Wert" (außerhalb von then) offenlegen würde, würde diese Abstraktion sofort für die gesamte Berechnung verloren gehen.

Wenn das Versprechen abgelehnt wird, sind die Werte .catch((values) => {})nicht über in.then(() => {})
jony89,

@ Benjamin, haben Sie gemeint, dass interne Slots und interne Methoden von der JS-Engine gemäß den Spezifikationen implementiert werden? Ich habe eine Antwort gelesen , die besagt, dass es sich nur um Worte handelt und keine Implementierung hat. (Vielleicht verstehe ich das hier falsch.) Außerdem frage ich nicht im Zusammenhang mit Versprechungen, da ich momentan nicht viel Ahnung davon habe. Fragen Sie einfach allgemein wie [[PUT]] [[Prototyp]] usw.
Nummer 945

@ Number945 Im Allgemeinen wird [[PromiseValue]]in den devtools tatsächlich von den devtools generiert. Wenn Sie auf der Konsole die Eingabetaste drücken evaluateOnCallFrame, wird die Nachricht an V8 gesendet, wodurch ein RemoteObject vom Subtyp zurückgegeben wird promise. Es gibt explizite Ad-hoc-Unterstützung dafür, dass dies funktioniert. Die obige Antwort ist richtig (daher erhält der Inspektor diese Eigenschaften), aber nicht genau (so gelangen sie nicht dorthin - sie gelangen über explizite Debugger-Unterstützung dorthin)
Benjamin Gruenbaum

18

Ich bin heute auch auf dieses Problem gestoßen und habe zufällig eine Lösung gefunden.

Meine Lösung sieht folgendermaßen aus:

fetch('http://localhost:3000/hello')
.then(dataWrappedByPromise => dataWrappedByPromise.json())
.then(data => {
    // you can access your data here
    console.log(data)
})

Hier dataWrappedByPromiseist eine PromiseInstanz. Um auf die Daten in der PromiseInstanz zuzugreifen , musste ich diese Instanz nur mit der Methode auspacken.json() .

Hoffentlich hilft das!


wegen Currying then(dataWrappedByPromise => dataWrappedByPromise.json())===then(resp.json())
Jymbob

@jymbob Ich kann Ihren Kommentar nicht verstehen. Sie sagen, wenn cafemike eine Pfeilfunktion definiert, kann diese Definition durch eine Konstante ersetzt werden. Insbesondere sagen Sie, dass sein "then ()" gleichbedeutend mit "then (resp.json ())" ist. Erstens, woher kam "resp"? Noch wichtiger ist, dass das Argument "resp.json ()" sofort ausgeführt wird, sodass das an ".then ()" übergebene Argument die Konstante (Zeichenfolge, Objekt oder Zahl) ist, die sich aus der Ausführung ergibt, während das Versprechen noch ungelöst ist. Vielleicht verstehen Sie nicht, dass ".then ()" eine Funktion als Argument erwartet.
IAM_AL_X

@IAM_AL_X huh. Ich kann meinen Kommentar auch nicht verstehen. Das einzige, was ich zwei Jahre später denken kann, ist, dass ich mich auf die Zeile "console.log" beziehen soll und völlig falsch geschrieben bin. Es stimmt, das .then(data => { console.log(data)})kann vereinfacht werden, .then(console.log)aber Sie haben absolut Recht, dass die Funktion benötigt wird, um auf eine Konstante für diese Funktion zuzugreifen. Entschuldigen Sie die Verwirrung
jymbob

5

Dieses Beispiel ist mit reagieren, aber zum größten Teil sollte es das gleiche sein.

Ersetzen Sie this.props.url durch Ihre URL, um sie abzurufen, damit sie für die meisten anderen Frameworks funktioniert.

Wenn Sie die Datei res.json () analysieren, wird der Versprechen- Wert zurückgegeben. Wenn Sie ihn jedoch an eine andere .then () -Methode weiter unten zurückgeben, können Sie ihn als Gesamtarray zurückgeben.

let results = fetch(this.props.url)
        .then((res) => {
            return res.json();
        })
        .then((data) => {
            return data;
        })

0

Wenn wir die Manpage lesen , können wir Folgendes sehen:

Der sofortige Status und Wert eines Versprechens kann nicht synchron vom Code aus überprüft werden, ohne die then()Methode aufzurufen .

Um das Debuggen zu erleichtern, können Sie nur bei der manuellen Überprüfung eines Versprechungsobjekts weitere Informationen als spezielle Eigenschaften anzeigen, auf die über Code nicht zugegriffen werden kann (dies wird derzeit durch Randomisierung des Eigenschaftsnamens implementiert, da keine komplexere Sprach- oder Debuggerunterstützung vorhanden ist ).

Hervorhebung von mir. Daher kann das, was Sie tun möchten, nicht ausgeführt werden. Die bessere Frage ist, warum Sie so auf den Versprechen-Status zugreifen müssen.


0

Versuchen Sie es mit await .

Anstatt

var value = definitions.PromiseValue 

verwenden

var value =  await definiton;

Dies könnte Ihren Zweck lösen, indem Sie den Versprechenswert liefern.

Beachten Sie, dass await nur in asynchronen Funktionen verwendet werden kann und eine ES2016-Funktion ist.


Können Sie bitte erklären, wie dies den Zweck löst? Vielen Dank!
Shanteshwar Inde

-1

Ich denke, dass es gut damit gehen wird.

(async () => {
  let getDefinitions = await ( () => {
    return new Promise( (resolve, reject) => {
      resolve(ContactManager.request("definition:entities"));
    });
  })();
)();

-4

Für den Fall, dass die zurückgegebene Antwort HTML ist, kein JSON

fetch('http://localhost:3000/hello')
  .then(response => response.text())
  .then(data => {
    // you can see your PromiseValue data here
    console.log(data)
  })
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.