Що означають подвійні дужки в javascript і як отримати до них доступ


77

Ситуація

У мене є така функція, яка використовує Promise .

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

var definitions = getDefinitions()

Зміст definitions:

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

Доступ до PromiseValueвластивості безпосередньо повертається невизначеним

var value = definitions.PromiseValue; // undefined

Питання

Що означають подвійні дужки [[ ]]та як я отримую значення [[PromiseValue]].


2
Це допомогло б знати, якою бібліотекою ви користуєтесь.
JJJ

4
Мда, я думаю, я використовую вбудовану бібліотеку javascript з Chrome (??)
Джефф,

2
Схоже, саме так описується стан обіцянки. Ви можете спробувати це в консолі Chrome: new Promise(function(){}). [[PromiseStatus]]Хром може бути по порівнянні з <state>з Firefox. Я насправді не розумію, у чому тут питання (якщо OP знає, що таке обіцянка).
Денис Сегурет

1
@Jeff, наскільки я можу зрозуміти, саме так Chrome показує вам стан обіцянки. Ці властивості навмисно не видно зовні для об’єкта. Якщо ви подивитесь на об’єкт Promise у Firefox, він не представляє його таким чином. Думаю, це, мабуть, просто призначене як діагностична допомога.
Пойнті

1
Що ContactManager.request("definition:entities")?
Бенджамін Груенбаум

Відповіді:


104

Які речі всередині [[]]

Моє питання полягає в тому, що означають подвійні дужки [[]], і як я отримую значення [[PromiseValue]].

Це внутрішня властивість. Ви не можете отримати до нього безпосередній доступ. Власні обіцянки можуть розгортатися лише thenз обіцянками або взагалі асинхронно - див. Як повернути відповідь з асинхронного дзвінка . Цитування специфікації:

Вони визначаються цією специфікацією виключно для ознайомчих цілей. Реалізація ECMAScript повинна вести себе так, ніби вона створює та працює на внутрішніх властивостях, як описано тут. Назви внутрішніх властивостей укладені у подвійні квадратні дужки [[]] . Коли алгоритм використовує внутрішню властивість об'єкта, а об'єкт не реалізує вказану внутрішню властивість, виникає виняток TypeError.

Ти не можеш

Хоча серйозно - які вони?

Дуже мило! Як зазначено у наведеній вище цитаті, вони просто використовуються в специфікації - тому немає жодної причини для того, щоб вони дійсно з’являлися у вашій консолі.

Не кажіть нікому, але це справді приватні символи . Причиною їх існування є доступ до інших внутрішніх методів [[PromiseValue]]. Наприклад, коли io.js вирішує повернути обіцянки замість зворотних викликів - це дозволить йому швидко отримати доступ до цих властивостей, якщо це гарантовано. Вони не піддаються впливу зовні.

Чи можу я отримати до них доступ?

Якщо ви не зробите власну версію Chrome або V8. Можливо, у ES7 з модифікаторами доступу. На сьогоднішній день немає жодного способу, оскільки вони не є частиною специфікації, і вони будуть розбиватися в браузерах - вибачте.

То як я можу отримати свою вартість?

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

Але що, якщо він повертає помилку? Напередодні цих випадків додайте наступне в кінці (та поза) вашого .then ().

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

Хоча, якби мені довелося здогадуватися - для початку ви не перетворюєте API правильно, оскільки це перетворення буде працювати лише в тому випадку, якщо метод синхронний (у такому випадку не повертайте обіцянку) або він повертає обіцянку, яка вже зробить це вирішено (що означає, що перетворення вам зовсім не потрібне - просто return.


Крім того, слід сказати, що він повністю суперечить меті a Promiseотримати доступ до його загорнутого значення поза then. Призначення a Promiseполягає у абстрагуванні від відсутнього повертаного значення неблокуючої функції, тобто a Promiseявляє собою "майбутнє значення". Як тільки хтось викриє це "майбутнє значення" (поза then), ця абстракція буде негайно втрачена для всього обчислення.

Якщо обіцянку відхилено, тоді значення будуть доступні, .catch((values) => {})а не через.then(() => {})
jony89

@Benjamin, ти мав на увазі, що внутрішні слоти та внутрішні методи реалізовані механізмом JS відповідно до специфікації? Я прочитав одну відповідь, в якій говорилося, що це просто слова і не мають реалізації. (Можливо, я тут непорозумію) Крім того, я не питаю в контексті обіцянок, оскільки я зараз не дуже про це знаю. Просто запитую загалом, як [[PUT]] [[Prototype]] тощо
Number945

@ Number945, як правило, [[PromiseValue]]в devtools фактично генерується devtools - коли ви натискаєте клавішу enter на консолі, це робить a evaluateOnCallFrame, надсилає повідомлення на V8, який повертає RemoteObject підтипу promise. Для цього існує явна спеціальна підтримка. Наведена вище відповідь є правильною (звідти інспектор отримує ці властивості), але не точною (не так вони потрапляють туди - вони потрапляють туди за допомогою явної підтримки відладчика)
Бенджамін Груенбаум,

18

Я також сьогодні зайнявся цією проблемою і знайшов рішення.

Моє рішення виглядає так:

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

Тут, dataWrappedByPromiseє Promiseекземпляром. Щоб отримати доступ до даних в Promiseекземплярі, я виявив, що мені просто потрібно розгорнути цей екземпляр .json()методом.

Сподіваюся, це допоможе!


через каррі then(dataWrappedByPromise => dataWrappedByPromise.json())===then(resp.json())
jymbob

@jymbob Я не можу зрозуміти твій коментар. Ви говорите, що там, де cafemike визначає функцію стрілки, це визначення можна замінити константою; конкретно, ви кажете, що його "then ()" еквівалентно "then (resp.json ())". По-перше, звідки взявся "resp"? Що ще важливіше, аргумент "resp.json ()" виконується негайно, тому аргумент, переданий в ".then ()", є тим, якою константою (рядок, об'єкт або число) є результат виконання, поки обіцянка ще не вирішена. Можливо, ви не розумієте, що ".then ()" очікує функцію як аргумент.
IAM_AL_X

@IAM_AL_X га. Я теж не можу зрозуміти свій коментар. Єдине, що я можу думати через два роки, це те, що я мав на увазі посилання на рядок "console.log" і повністю помилково введено. Правда, це .then(data => { console.log(data)})можна спростити, .then(console.log)але ви абсолютно праві, що функція потрібна для доступу до константи цієї функції. Вибачте за будь-яку плутанину
jymbob

5

Цей приклад з реакцією, але здебільшого він повинен бути однаковим.

Замініть this.props.url на вашу url для отримання, щоб він працював для більшості інших фреймворків.

Розбір res.json () повертає [[promisValue]], однак якщо потім повернути його до іншого методу .then () нижче, ви можете повернути його як загальний масив.

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

0

Читаючи сторінку , ми бачимо, що:

За задумом миттєвий стан та значення обіцянки не можуть перевірятися синхронно з коду без виклику then()методу.

Щоб допомогти з налагодженням, лише під час перевірки об'єкта обіцянки ви можете бачити більше інформації як спеціальні властивості, недоступні з коду (це, на даний момент, реалізується шляхом рандомізації імені властивості, за відсутності більш досконалої підтримки мови та налагоджувача) ).

Акцент мій. Тому те, що ви хочете зробити, неможливо зробити. Краще питання полягає в тому, чому вам потрібен такий доступ до стану обіцянки?


0

Спробуйте використати await .

Замість

var value = definitions.PromiseValue 

використання

var value =  await definiton;

Це може вирішити вашу мету, отримавши обіцяне значення.

Зауважте, що await можна використовувати лише в асинхронних функціях, і це функція ES2016.


Ви можете пояснити, як це вирішується. Дякую!
Shanteshwar Inde

-1

Я думаю, що це буде добре поєднуватися з цим.

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

-4

У випадку, коли у відповідь повертається HTML, а не JSON

fetch('http://localhost:3000/hello')
  .then(response => response.text())
  .then(data => {
    // you can see your PromiseValue data here
    console.log(data)
  })
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.