Як отримати доступ до вартості обіцянки?


146

Я дивлюся на цей приклад з документів Angular, $qале думаю, що це, мабуть, стосується і обіцянок. Наведений нижче приклад копіюється дослівно з їхніх документів із їхнім коментарем:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

// promiseB will be resolved immediately after promiseA is resolved and its value
// will be the result of promiseA incremented by 1

Мені не ясно, як це працює. Якщо я можу зателефонувати .then()на результат першого .then(), прикувши їх, що я знаю, що можу, то promiseBце об'єкт обіцянки типу Object. Це не а Number. Отже, що вони означають під "цінністю, що є результатом обіцянки, збільшеного на 1"?

Я повинен отримати доступ до цього як promiseB.valueщось подібне? Яким чином зворотний виклик успіху може повернути обіцянку І повернути "результат + 1"? Я щось пропускаю.


Я задав відповідне запитання: Чому Promise не має функції get ()?
Roland


На це запитання 5 років, і він прийняв відповідь ...
тимчасовий_користувач

@temporary_user_name: це нормально, коли люди можуть голосувати близькими голосами в будь-який час, навіть за старими питаннями.
половина

Відповіді:


141

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

У цьому випадку promiseAрозв'язується зі значенням - resultа потім негайно розв'язується promiseBзі значенням result + 1.

Отримання доступу до значення promiseBвиконано так само, як ми отримали доступ до результату promiseA.

promiseB.then(function(result) {
    // here you can use the result of promiseB
});

Редагувати грудень 2019 : async/ awaitтепер є стандартною в JS, що дозволяє альтернативному синтаксису описаному вище підходу. Тепер ви можете написати:

let result = await functionThatReturnsPromiseA();
result = result + 1;

Тепер немає жодних обіцянокB, тому що ми розгорнули результат використання obeA await, і ви можете працювати з ним безпосередньо.

Однак awaitможна використовувати лише всередині asyncфункції. Отже, щоб трохи зменшити зображення, вищезазначене повинно міститись так:

async function doSomething() {
    let result = await functionThatReturnsPromiseA();
    return result + 1;
}

2
Обіцянки теоретично є власними об'єктами. вони містять результат, до якого можна отримати доступ через функцію успіху обіцянки.
Nachshon Schwartz

2
Отже, якщо ви хочете працювати з зворотним значенням асинхронного зворотного виклику обіцянки, це потрібно зробити всередині іншого асинхронного зворотного виклику. Має сенс. Я шукав спосіб отримати якесь кінцеве примітивне значення повернення, але, мабуть, це не спричинить причин з огляду на контекст.
тимчасовий_користувач

2
@Aerovistae насправді ES6 представляє генератори, які роблять це можливим, а ES7 запроваджує функції асинхронізації - обидва вони надають вам синтаксичний цукор за обіцянками, що робить його схожим на синхронний код (за допомогою запуску державної машини у фоновому режимі) - тож тримайтесь на жорсткому :)
Бенджамін Грюенбаум

25

Коли обіцянка буде вирішена / відхилена, вона викличе обробник успіху / помилки:

var promiseB = promiseA.then(function(result) {
   // do something with result
});

thenМетод також повертає обіцянку: promiseB, який буде дозволений / відкинутим в залежності від значення, що повертається з обробника успіху / помилок з promiseA .

Є три можливі значення, які обробники успіху / помилок obeA можуть повернути, які вплинуть на результат obeB:

1. Return nothing --> PromiseB is resolved immediately, 
   and undefined is passed to the success handler of promiseB
2. Return a value --> PromiseB is resolved immediately,
   and the value is passed to the success handler of promiseB
3. Return a promise --> When resolved, promiseB will be resolved. 
   When rejected, promiseB will be rejected. The value passed to
   the promiseB's then handler will be the result of the promise

Озброївшись цим розумінням, ви можете зрозуміти наступне:

promiseB = promiseA.then(function(result) {
  return result + 1;
});

Тоді виклик повертає обещанняB негайно. Коли обережність вирішена, він передасть результат обробнику успіху. Оскільки значення повернення є результатом promisA + 1, обробник успіху повертає значення (варіант 2 вище), тожBB негайно вирішиться, а обробник успіху promisB буде переданий результатом promisA + 1.


4

.thenФункція promisB отримує те, що повертається з .thenфункції promisA.

тут obeA повертається - це число, яке буде доступне як numberпараметр у функції успіху promisB. який потім збільшиться на 1


3

Аналіз коментаря трохи інакше, ніж ваше поточне розуміння, може допомогти:

// promiseB will be resolved immediately after promiseA is resolved

Це стверджує, що promiseBце обіцянка, але буде вирішено відразу після того, як promiseAбуде вирішено. Інший спосіб дивитися на це означає, що promiseA.then()повертає обіцянку, яка призначена promiseB.

// and its value will be the result of promiseA incremented by 1

Це означає, що значення, яке було promiseAвирішено, - це значення, яке promiseBотримає як своє значення valueCallback:

promiseB.then(function (val) {
  // val is now promiseA's result + 1
});

2

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

Однак існує спосіб отримати доступ до значення обіцянки безпосередньо після її вирішення за допомогою наступного непідтримуваного внутрішнього прив'язки node.js:

process.binding('util').getPromiseDetails(myPromise)[1]

ПОПЕРЕДЖЕННЯ: process.binding ніколи не використовувався поза ядром nodejs, і основна команда nodejs активно шукає його застаріти

https://github.com/nodejs/node/pull/22004 https://github.com/nodejs/node/isissue/22064


1

Цей приклад я вважаю само собою зрозумілим. Зауважте, як очікуєте на очікування результату, і так ви пропустите повернення Обіцянки.

cryA = crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
Promise {<pending>}
cryB = await crypto.subtle.generateKey({name:'ECDH', namedCurve:'P-384'}, true, ["deriveKey", "deriveBits"])
{publicKey: CryptoKey, privateKey: CryptoKey}

Це повинно бути у функції асинхронізації.
Самед

0
promiseA(pram).then(
     result => { 
     //make sure promiseA function allready success and response
     //do something here
}).catch(err => console.log(err)) => {
     // handle error with try catch
}

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

0

Ви можете легко зробити це, використовуючи метод очікування асинхронізації в JavaScript.

Нижче наводиться приклад отримання значення обіцянки WebRTC за допомогою тайм-ауту.

function await_getipv4(timeout = 1000) {
    var t1 = new Date();
    while(!window.ipv4) {
        var stop = new Date() - t1 >= timeout;
        if(stop) {
            console.error('timeout exceeded for await_getipv4.');
            return false;
        }
    }
    return window.ipv4;
}

function async_getipv4() {
    var ipv4 = null;
    var findIP = new Promise(r=>{var w=window,a=new (w.RTCPeerConnection||w.mozRTCPeerConnection||w.webkitRTCPeerConnection)({iceServers:[]}),b=()=>{};a.createDataChannel("");a.createOffer(c=>a.setLocalDescription(c,b,b),b);a.onicecandidate=c=>{try{c.candidate.candidate.match(/([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g).forEach(r)}catch(e){}}})
    findIP.then(ip => window.ipv4 = ip);
    return await_getipv4();
};


Важливо запустити цей фрагмент не тут, а в реальному браузері, я вважаю, що це пов'язано з пісочницею.
OxFEEDFACE

0

У вузлі REPL, щоб отримати з'єднання БД, яке було значенням обіцянки, я взяв такий підхід:

let connection
try {
  (async () => {
    connection = await returnsAPromiseResolvingToConnection()
  })()
} catch(err) {
  console.log(err)
}

Рядок з await, як правило, повертає обіцянку. Цей код можна вставити у вузол REPL або якщо зберегти index.jsйого, можна запустити в Bash

node -i -e "$(< index.js)"

який залишає вас у вузлі REPL після запуску сценарію з доступом до встановленої змінної. Щоб підтвердити, що асинхронна функція повернулася, ви можете увійти, connectionнаприклад, і тоді ви готові використовувати змінну. Звичайно, не хотілося б розраховувати, що асинхронна функція вирішена ще для будь-якого коду в сценарії поза асинхронною функцією.


0

Вище є хороша відповідь, і ось функція стрілки ES6

var something = async() => {
   let result = await functionThatReturnsPromiseA();
   return result + 1;
}

0

Я повільно вивчаю обіцянки javascript, за замовчуванням всі функції асинхронізації повертають обіцянку, ви можете перетворити результат як:

(async () => {
//Optional "await"
  await yourAsyncFunctionOrPromise()
    .then(function (result) {
      return result +1;
    })
    .catch(function (error) {
      return error;
    })()
})

" Вираз очікування призводить до того, що виконання функції асинхронізації буде призупинено, поки Обіцяння не буде вирішено (тобто виконано або відхилено), і відновити виконання функції асинхронізації після виконання. При поновленні значення виразу очікування - значення виконаного Обіцяння Якщо Обіцянка відхилена, вираз очікування кидає відхилене значення ".

Детальніше про очікування та обіцянки читайте в веб-документах MDN


-5

Можливо, цей невеликий приклад коду Typescript допоможе.

private getAccount(id: Id) : Account {
    let account = Account.empty();
    this.repository.get(id)
        .then(res => account = res)
        .catch(e => Notices.results(e));
    return account;
}

Тут repository.get(id)повертається a Promise<Account>. Я присвоюю її змінної accountв thenоператорі.


1
Ваш код повертає обліковий запис до того, як обіцянка може бути вирішена, і саме тому за недійсне голосування ваш код завжди повертає Account.empty ();
Феліпе
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.