Что означает функция then() в JavaScript?

Я видел код, который выглядит так:

myObj.doSome("task").then(function(env) {
    // logic
});

Где же then() родом из?

9 ответов

Традиционный способ обработки асинхронных вызовов в JavaScript - обратные вызовы. Скажем, нам нужно было сделать три звонка на сервер, один за другим, чтобы настроить наше приложение. С обратными вызовами код может выглядеть примерно так (при условии, что функция xhrGET выполняет вызов сервера):

// Fetch some server configuration
    xhrGET('/api/server-config', function(config) {
        // Fetch the user information, if he's logged in
        xhrGET('/api/' + config.USER_END_POINT, function(user) {
            // Fetch the items for the user
            xhrGET('/api/' + user.id + '/items', function(items) {
                // Actually display the items here
            });
        });
    });

В этом примере мы сначала выбираем конфигурацию сервера. Затем на основе этого мы извлекаем информацию о текущем пользователе и, наконец, получаем список элементов для текущего пользователя. Каждый вызов xhrGET принимает функцию обратного вызова, которая выполняется, когда сервер отвечает.

Конечно, чем больше у нас уровней вложенности, тем сложнее код читать, отлаживать, обслуживать, обновлять и в основном работать. Это обычно известно как ад обратного вызова. Кроме того, если нам нужно было обработать ошибки, нам, возможно, нужно передать другую функцию каждому вызову xhrGET, чтобы сообщить ему, что нужно делать в случае ошибки. Если мы хотим иметь только один общий обработчик ошибок, это невозможно.

API Promise был разработан для решения этой проблемы с вложенностью и обработки ошибок.

API Promise предлагает следующее:

  1. Каждая асинхронная задача будет возвращать promise объект.
  2. каждый promise объект будет иметь then функция, которая может принимать два аргумента, success обработчик и error обработчик.
  3. Успех или обработчик ошибок в then Функция будет вызываться только один раз, после завершения асинхронной задачи.
  4. then Функция также вернет promise, чтобы разрешить цепочку из нескольких вызовов.
  5. Каждый обработчик (успех или ошибка) может вернуть value, который будет передан следующей функции как argument в цепи promise s.
  6. Если обработчик возвращает promise (делает другой асинхронный запрос), тогда следующий обработчик (успех или ошибка) будет вызван только после того, как этот запрос будет завершен.

Таким образом, предыдущий пример кода может перевести что-то вроде следующего, используя обещания и $http сервис (в AngularJs):

$http.get('/api/server-config').then(
    function(configResponse) {
        return $http.get('/api/' + configResponse.data.USER_END_POINT);
    }
).then(
    function(userResponse) {
        return $http.get('/api/' + userResponse.data.id + '/items');
    }
).then(
    function(itemResponse) {
        // Display items here
    }, 
    function(error) {
        // Common error handling
    }
);

Распространение успеха и ошибки

Цепные обещания - очень мощный метод, который позволяет нам выполнять множество функций, например, когда служба выполняет серверный вызов, выполняет некоторую постобработку данных и затем возвращает обработанные данные контроллеру. Но когда мы работаем с promise цепи, есть несколько вещей, которые мы должны иметь в виду.

Рассмотрим следующую гипотетическую promise цепь с тремя обещаниями, P1, P2 и P3. каждый promise имеет обработчик успеха и обработчик ошибок, поэтому S1 и E1 для P1, S2 и E2 для P2 и S3 и E3 для P3:

xhrCall()
  .then(S1, E1) //P1
  .then(S2, E2) //P2
  .then(S3, E3) //P3

В нормальном потоке вещей, где нет ошибок, приложение будет проходить через S1, S2 и, наконец, S3. Но в реальной жизни все не так гладко. P1 может столкнуться с ошибкой, или P2 может столкнуться с ошибкой, вызвав E1 или E2.

Рассмотрим следующие случаи:

• Мы получили успешный ответ от сервера в P1, но возвращенные данные неверны, или на сервере нет доступных данных (например, пустой массив). В таком случае для следующего обещания P2 он должен вызвать обработчик ошибок E2.

• Мы получаем ошибку для обещания P2, запускающего E2. Но внутри обработчика у нас есть данные из кеша, благодаря чему приложение может загружаться как обычно. В этом случае мы можем захотеть убедиться, что после E2 вызывается S3.

Таким образом, каждый раз, когда мы пишем успех или обработчик ошибок, нам нужно сделать вызов - учитывая нашу текущую функцию, является ли это обещание успехом или неудачей для следующего обработчика в цепочке обещаний?

Если мы хотим запустить обработчик успеха для следующего обещания в цепочке, мы можем просто вернуть значение из обработчика успеха или ошибки

Если, с другой стороны, мы хотим запустить обработчик ошибок для следующего обещания в цепочке, мы можем сделать это, используя deferred объект и называя его reject() метод

Теперь, что такое отложенный объект?

Отложенные объекты в jQuery представляют собой единицу работы, которая будет выполнена позже, как правило, асинхронно. Как только единица работы завершается, deferred объект может быть установлен на разрешение или сбой.

deferred объект содержит promise объект. Через promise В объекте вы можете указать, что должно произойти, когда единица работы завершится. Вы делаете это, устанавливая функции обратного вызова на promise объект.

Отложенные объекты в Jquery: https://api.jquery.com/jquery.deferred/

Отложенные объекты в AngularJs: https://docs.angularjs.org/api/ng/service/ $ q

Функция then() относится к "обещаниям JavaScript", которые используются в некоторых библиотеках или инфраструктурах, таких как jQuery или AngularJS.

Обещание - это шаблон для обработки асинхронных операций. Обещание позволяет вам вызывать метод с именем "then", который позволяет вам указать функции, которые будут использоваться в качестве обратных вызовов.

Для получения дополнительной информации см.: http://wildermuth.com/2013/8/3/JavaScript_Promises

И для угловых обещаний: http://liamkaufman.com/blog/2013/09/09/using-angularjs-promises/

Насколько мне известно, нет встроенного then() метод в javascript (на момент написания этой статьи).

Похоже, что бы это ни было doSome("task") возвращается имеет метод с именем then,

Если вы регистрируете результат возврата doSome() на консоли вы должны увидеть свойства того, что было возвращено.

console.log( myObj.doSome("task") ); // Expand the returned object in the
                                     //   console to see its properties.

ОБНОВЛЕНИЕ (Начиная с ECMAScript6): -

.then() Функция была включена в чистый JavaScript.

Из документации Mozilla здесь,

Метод then() возвращает Promise. Он принимает два аргумента: функции обратного вызова для случаев успеха и неудачи Обещания.

Объект Promise, в свою очередь, определяется как

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

Это Promise действует как заполнитель для значения, которое еще не вычислено, но должно быть разрешено в будущем. И .then() Функция используется, чтобы связать функции, которые будут вызваны в Обещании, когда это будет решено - либо как успех, либо как сбой.

Вот что я сделал для себя, чтобы выяснить, как все работает. Я думаю, что другие тоже могут найти этот конкретный пример полезным:

doit().then(function() { log('Now finally done!') });
log('---- But notice where this ends up!');

// For pedagogical reasons I originally wrote the following doit()-function so that 
// it was clear that it is a promise. That way wasn't really a normal way to do 
// it though, and therefore Slikts edited my answer. I therefore now want to remind 
// you here that the return value of the following function is a promise, because 
// it is an async function (every async function returns a promise). 
async function doit() {
  log('Calling someTimeConsumingThing');
  await someTimeConsumingThing();
  log('Ready with someTimeConsumingThing');
}

function someTimeConsumingThing() {
  return new Promise(function(resolve,reject) {
    setTimeout(resolve, 2000);
  })
}

function log(txt) {
  document.getElementById('msg').innerHTML += txt + '<br>'
}
<div id='msg'></div>

Вот маленький JS_Fiddle.

затем это стек обратного вызова метода, который доступен после разрешения обещания, он является частью библиотеки, такой как jQuery, но теперь он доступен в собственном JavaScript, а ниже приведено подробное объяснение его работы.

Вы можете выполнить Обещание в собственном JavaScript: так же, как в jQuery есть обещания, Каждое обещание может быть сложено и затем вызываться с помощью обратных вызовов Resolve и Reject. Так вы можете связывать асинхронные вызовы.

Я разветвлялся и редактировал документы MSDN о состоянии зарядки аккумулятора.

Что он делает, это пытается выяснить, заряжает ли пользовательский ноутбук или устройство. затем называется, и вы можете сделать свою работу после успеха.

navigator
    .getBattery()
    .then(function(battery) {
       var charging = battery.charging;
       alert(charging);
    })
    .then(function(){alert("YeoMan : SINGH is King !!");});

Другой пример es6

function fetchAsync (url, timeout, onData, onError) {
    …
}
let fetchPromised = (url, timeout) => {
    return new Promise((resolve, reject) => {
        fetchAsync(url, timeout, resolve, reject)
    })
}
Promise.all([
    fetchPromised("http://backend/foo.txt", 500),
    fetchPromised("http://backend/bar.txt", 500),
    fetchPromised("http://backend/baz.txt", 500)
]).then((data) => {
    let [ foo, bar, baz ] = data
    console.log(`success: foo=${foo} bar=${bar} baz=${baz}`)
}, (err) => {
    console.log(`error: ${err}`)
})

Definition:: then - метод, используемый для решения асинхронных обратных вызовов.

это введено в ES6

Пожалуйста, найдите соответствующую документацию здесь Es6 Promises

Другой пример:

new Promise(function(ok) {
   ok( 
      /* myFunc1(param1, param2, ..) */
   )
}).then(function(){
     /* myFunc1 succeed */
     /* Launch something else */
     /* console.log(whateverparam1) */
     /* myFunc2(whateverparam1, otherparam, ..) */
}).then(function(){
     /* myFunc2 succeed */
     /* Launch something else */
     /* myFunc3(whatever38, ..) */
})

Та же логика с использованием сокращенных функций стрелок.

⚠️ Это может вызвать проблемы с несколькими вызовами, см. Комментарии!

Синтаксис первого фрагмента с использованием простого function здесь предпочтительнее.

new Promise((ok) =>
   ok( 
      /* myFunc1(param1, param2, ..) */
)).then(() =>
     /* myFunc1 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc2(whateverparam1, otherparam, ..) */
).then(() =>
     /* myFunc2 succeed */
     /* Launch something else */
     /* Only ONE call or statment can be made inside arrow functions */
     /* For example, using console.log here will break everything */
     /* myFunc3(whatever38, ..) */
)

.then возвращает обещание в асинхронной функции.

Хороший пример:

var doSome = new Promise(function(resolve, reject){
    resolve('I am doing something');
});

doSome.then(function(value){
    console.log(value);
});

Чтобы добавить к нему еще одну логику, вы также можете добавить reject('I am the rejected param') вызовите функцию и войдите в console.log.

Я подозреваю, что doSome возвращает this, это myObj, который также имеет метод then. Стандартный метод цепочки...

если doSome не возвращает это, будучи объектом, на котором был выполнен doSome, будьте уверены, что он возвращает некоторый объект с помощью метода then...

как указывает @patrick, тогда нет () для стандартного js

Функция ".then()" широко используется для обещанных объектов в программировании Asynchoronus для приложений Магазина Windows 8. Насколько я понял, это работает как обратный вызов.

Подробности в этом документе http://msdn.microsoft.com/en-us/library/windows/apps/hh700330.aspx

Конечно, это также может быть имя для любой другой определенной функции.

doSome("задача") должна возвращать объект обещания, и это обещание всегда имеет функцию then. Так что ваш код такой же, как этот

promise.then(function(env) {
    // logic
}); 

и вы знаете, что это просто обычный вызов функции-члена.

В этом случае then() это метод класса объекта, возвращаемого doSome() метод.

Я опоздал примерно на 8 лет, ну... в любом случае, я действительно не знаю, что делает then(), но, возможно, у MDN есть ответ. На самом деле, я мог бы понять это немного больше.

Это покажет вам всю необходимую информацию (надеюсь). Если только кто-то уже не разместил эту ссылку. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

Формат - обещание.prototype.then() Промис и прототип похожи на переменные, но не на переменные в javascript, я имею в виду, как и другие вещи, такие как navigator.getBattery(). Then(), где этот действительно существует, но есть почти не используется в Интернете, он показывает состояние батареи устройства, дополнительную информацию и многое другое на MDN, если вам интересно.

Другие вопросы по тегам