Как получить доступ к стоимости обещания?


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 ()?
Роланд


На этот вопрос 5 лет, и на него есть принятый ответ ...
временное_имя_февраля

@tevent_user_name: люди могут голосовать в любое время, даже по старым вопросам.
halfer

Ответы:


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, потому что мы развернули результат от использования обещания A await, и вы можете работать с ним напрямую.

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

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

2
Обещания теоретически являются их собственными объектами. они содержат результат, к которому можно получить доступ через функцию успеха обещания.
Нахшон Шварц

2
Поэтому, если вы хотите работать с возвращаемым значением асинхронного обратного вызова обещания, это должно быть сделано внутри другого асинхронного обратного вызова. Имеет смысл. Я искал способ получить какое-то окончательное примитивное возвращаемое значение, но я полагаю, что это не поддается разуму с учетом контекста.
временное_имя_пользователя

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

25

Когда обещание разрешено / отклонено, оно вызовет свой обработчик успеха / ошибки:

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

thenМетод также возвращает обещание: promiseB, который будет разрешен / отвергнутым в зависимости от возвращаемого значения из обработчика успеха / ошибок из promiseA .

Есть три возможных значения, которые могут возвращать обработчики success / error в Proma, что повлияет на результат обещания B:

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

Вызов then немедленно возвращает обещание B. После того, как PromiseA будет решен, он передаст результат обработчику успеха обещания. Так как возвращаемое значение - результат + 1 PromiseA, обработчик успеха возвращает значение (опция 2 выше), так что promIBB разрешится немедленно, и обработчику успеха обещания B будет передан результат Proma + 1.


4

.thenФункция обещания B получает то, что возвращается из .thenфункции обещания.

здесь обещание, которое возвращает обещание: число, которое будет доступно в качестве numberпараметра в функции успеха обещания. который затем будет увеличен на 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которое получит в качестве значения successCallback:

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

2

Ответ pixelbits правильный, и вы всегда должны использовать его .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/issues/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 после запуска скрипта с доступом к переменной set. Чтобы подтвердить, что асинхронная функция вернулась, вы можете войти, 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;
    })()
})

« Выражение await заставляет выполнение асинхронной функции приостанавливаться до тех пор, пока не будет выполнено обещание (то есть выполнено или отклонено), и возобновить выполнение асинхронной функции после выполнения. При возобновлении значение выражения await совпадает со значением выполненного обещания. Если обещание отклонено, выражение await выбрасывает отклоненное значение. . "

Узнайте больше об ожидании и обещаниях в MDN Web Docs


-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)возвращается Promise<Account>. Я назначаю это переменной accountв thenзаявлении.


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