Чтобы отредактировать код и исправить ошибку:
while True:
try:
age = int(input("Please enter your age: "))
if age >= 18:
print("You are able to vote in the United States!")
break
else:
print("You are not able to vote in the United States.")
break
except ValueError:
print("Please enter a valid response")
Обещания не являются обратными вызовами. Обещание представляет собой будущий результат асинхронной операции. Конечно, записывая их так, как вы, вы получаете небольшую выгоду. Но если вы напишете их так, как они предназначены для использования, вы можете написать асинхронный код так, чтобы он напоминал синхронный код, и его гораздо проще:
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
});
Конечно, не намного меньше кода , но гораздо более удобочитаемым.
Но это еще не конец. Давайте обнаружим истинные преимущества: что, если вы хотите проверить какую-либо ошибку на любом из шагов? Было бы чертовски сделать это с помощью обратных вызовов, но с обещаниями - кусок торта:
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
}).catch(function(error) {
//handle any error that may occur before this point
});
Совсем так же, как блок try { ... } catch
.
Еще лучше:
api().then(function(result){
return api2();
}).then(function(result2){
return api3();
}).then(function(result3){
// do work
}).catch(function(error) {
//handle any error that may occur before this point
}).then(function() {
//do something whether there was an error or not
//like hiding an spinner if you were performing an AJAX request.
});
И еще лучше: что делать, если эти 3 вызова api
, api2
, api3
могут выполняться одновременно (например, если они были AJAX звонки), но вам нужно было подождать три? Без обещаний вам нужно создать какой-то счетчик. С обещаниями, использующими нотацию ES6, это еще один кусок торта и довольно аккуратный:
Promise.all([api(), api2(), api3()]).then(function(result) {
//do work. result is an array contains the values of the three fulfilled promises.
}).catch(function(error) {
//handle the error. At least one of the promises rejected.
});
Надеюсь, вы увидите обещания в новом свете.
Никакие обещания не являются просто оболочкой для обратных вызовов
. Вы можете использовать собственные обещания javascript с узлом js
my cloud 9 code link : https://ide.c9.io/adx2803/native-promises-in-node
/**
* Created by dixit-lab on 20/6/16.
*/
var express = require('express');
var request = require('request'); //Simplified HTTP request client.
var app = express();
function promisify(url) {
return new Promise(function (resolve, reject) {
request.get(url, function (error, response, body) {
if (!error && response.statusCode == 200) {
resolve(body);
}
else {
reject(error);
}
})
});
}
//get all the albums of a user who have posted post 100
app.get('/listAlbums', function (req, res) {
//get the post with post id 100
promisify('http://jsonplaceholder.typicode.com/posts/100').then(function (result) {
var obj = JSON.parse(result);
return promisify('http://jsonplaceholder.typicode.com/users/' + obj.userId + '/albums')
})
.catch(function (e) {
console.log(e);
})
.then(function (result) {
res.end(result);
}
)
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
//run webservice on browser : http://localhost:8081/listAlbums
В дополнение к удивительным ответам выше, можно добавить еще 2 точки:
1. Семантическая разница:
Обещания могут быть уже решены при создании. Это означает, что они гарантируют условия, а не события . Если они уже решены, разрешенная функция, переданная ей, все еще вызывается.
И наоборот, обратные вызовы обрабатывают события. Итак, если событие, которое вас интересует, произошло до того, как обратный вызов был зарегистрирован, обратный вызов не вызывается.
2. Инверсия управления
Обратные вызовы включают инверсию управления. Когда вы регистрируете функцию обратного вызова с любым API, среда выполнения Javascript хранит функцию обратного вызова и вызывает ее из цикла событий, когда она готова к запуску.
См. Цикл событий Javascript для объяснения.
С помощью Promises управление выполняется с вызывающей программой. Метод .then () может быть вызван в любое время , если мы сохраним объект-обещание.
Да, обещания - это асинхронные обратные вызовы. Они не могут делать ничего, что не могут сделать обратные вызовы, и вы сталкиваетесь с теми же проблемами с асинхронностью, что и с обычными обратными вызовами.
Однако, обещания больше , чем просто обратные вызовы. Они - очень мощная абстракция, обеспечивают более чистый и улучшенный функциональный код с менее склонным к ошибкам шаблоном.
Итак, в чем главная идея?
blockquote>Обещания объекты, представляющие результат одного (асинхронного) вычисления. Они разрешают этот результат только один раз. Есть несколько вещей, что это означает:
Обещает реализовать шаблон наблюдателя:
- Вам не нужно знать обратные вызовы, которые будут использовать значение до завершения задачи.
- Вместо того, чтобы ожидать обратных вызовов в качестве аргументов для ваших функций, вы можете легко
return
объект Promise- Обещание сохранит это значение, и вы можете прозрачно добавьте обратный вызов, когда захотите. Он будет вызываться, когда результат будет доступен. «Transparency» подразумевает, что когда у вас есть обещание и добавление обратного вызова к нему, для вашего кода не имеет значения, достиг ли результат: API и контракты одинаковы, что упрощает кэширование / memoisation.
- Вы можете легко добавить несколько обратных вызовов
Обещания связаны с цепью ( monadic , если хотите):
- Если вам нужно преобразовать значение, представляемое обещанием, вы map преобразуете функцию над обещанием и получите новое обещание, которое представляет преобразованный результат. Вы не можете синхронно получить значение, чтобы использовать его каким-то образом, но вы можете легко снять преобразование в контексте обещания. Нет обратных вызовов шаблонов.
- Если вы хотите связать две асинхронные задачи, вы можете использовать метод
.then()
.Звучит сложно? Ответ на этот вопрос будет вызван первым результатом и даст обещание получить обещание вернуться. Время для примера кода.
var p1 = api1(); // returning a promise var p3 = p1.then(function(api1Result) { var p2 = api2(); // returning a promise return p2; // The result of p2 … }); // … becomes the result of p3 // So it does not make a difference whether you write api1().then(function(api1Result) { return api2().then(console.log) }) // or the flattened version api1().then(function(api1Result) { return api2(); }).then(console.log)
Сглаживание не приходит волшебным образом, но вы можете легко это сделать. Для вашего сильно вложенного примера эквивалент (ближайший) будет
api1().then(api2).then(api3).then(/* do-work-callback */);
. Если просмотр кода этих методов помогает понять, - это самое основное обещание lib в нескольких строках .
Что представляет собой большая проблема с обещаниями?
blockquote>Абстракция Promise позволяет значительно улучшить компоновку функций. Например, рядом с
then
для цепочки функцияall
создает обещание для комбинированного результата нескольких обещаний с параллельным ожиданием.И последнее, но не менее важное: обещания с интегрированной обработкой ошибок. Результатом вычисления может быть то, что либо обещание выполнено со значением, либо отклонено с причиной. Все функции композиции обрабатывают это автоматически и распространяют ошибки в цепочках обещаний, так что вам не нужно заботиться об этом явно везде - в отличие от реализации простого обратного вызова. В конце вы можете добавить выделенный обратный вызов ошибки для всех произошедших исключений.
Не говоря уже о необходимости конвертировать вещи в обещания.
blockquote>Это довольно тривиально на самом деле с хорошими библиотеками обещаний, см. Как мне преобразовать существующий API обратного вызова в обещания?
.then(console.log)
, поскольку console.log зависит от контекста консоли. Таким образом, это приведет к ошибке незаконного вызова. Используйте console.log.bind(console)
или x => console.log(x)
для привязки контекста.
– Tamas Hegedus
20 November 2015 в 12:07
console
методы уже связаны. И, конечно же, я только сказал, что оба гнезда имеют точно такое же поведение, а не то, что любой из них будет работать: -P
– Bergi
20 November 2015 в 12:46
В дополнение к другим ответам синтаксис ES2015 плавно сочетается с обещаниями, уменьшая еще больший код шаблона:
// Sequentially:
api1()
.then(r1 => api2(r1))
.then(r2 => api3(r2))
.then(r3 => {
// Done
});
// Parallel:
Promise.all([
api1(),
api2(),
api3()
]).then(([r1, r2, r3]) => {
// Done
});
В дополнение к уже установленным ответам, с функциями стрелок ES6 Обещания превращаются из скромно сияющего маленького синего карлика прямо в красного гиганта. Это собирается свернуться с сверхновой:
api().then(result => api2()).then(result2 => api3()).then(result3 => console.log(result3))
Как указал oligofren , без аргументов между вызовами api вам вообще не нужны анонимные функции-обертки:
api().then(api2).then(api3).then(r3 => console.log(r3))
И, наконец, если вы хотите достичь уровня сверхмассивной черной дыры, можно ожидать обещаний:
async function callApis() {
let api1Result = await api();
let api2Result = await api2(api1Result);
let api3Result = await api3(api2Result);
return api3Result;
}
apiX
, вы также можете пропустить все функции стрелок: api().then(api2).then(api3).then(r3 => console.log(r3))
.
– oligofren
7 November 2017 в 19:55
Обещания не являются обратными вызовами, оба являются идиомами программирования, которые облегчают асинхронное программирование. Использование асинхронного / ожидаемого стиля программирования с помощью сопрограмм или генераторов, которые возвращают обещания, можно рассматривать как третью подобную идиому. Сравнение этих идиом на разных языках программирования (включая Javascript) находится здесь: https://github.com/KjellSchubert/promise-future-task
api2
иapi3
есть асинхронные операции? будет ли последний.then
вызываться только после завершения этих асинхронных операций? – NiCk Newman 24 January 2016 в 20:45