Javascript.RU

Вложенные асинхронные вызовы. Объект Deferred в деталях.

Объект Deferred инкапсулирует последовательность обработчиков для еще не существующего результата, чем сильно упрощает сложные AJAX-приложения. Он предоставляется различными фреймворками (Dojo Toolkit, Mochikit) и отдельными библиотечками (jsDeferred, Promises etc).

С его помощью можно добавлять обработчики не в момент запуска метода (например, посылки запроса XMLHTTPRequest() , а в любой момент после этого.

Основные методы объекта Deferred:

  • addCallback(функция-обработчик)
  • addErrback(функция-обработчик)
  • callback(результат)
  • errback(результат)

Обычно, когда функция возвращает Deferred, т.е "обещание результата в некоторый момент", программист затем цепляет к нему обработчики результата, которые будут вызваны в той же последовательности, через addCallback/addErrback.

Код, который управляет объектом Deferred, т.е тот код, который дал обещание предоставить результат, должен вызвать callback() или errback() методы в тот момент, когда результат появится. Например, после завершения некоторой асинхронной операции.

При этом будет вызван первый в цепочке обработчик, добавленный при помощи addCallback() или addErrback() соответственно.

Каждый следующий обработчик получит результат, который вернул предыдущий.

Вот - самый простой пример обработчика:

var deferred = new Deferred()
deferred.addCallback(function(result) { return result })
Важный принцип при работе с Deferred: каждый обработчик должен возвращать результат. Так что затем всегда можно продолжить работу с этим результатом.

Например, вот wrapper для XmlHTTPRequest, который возвращает объект Deferred:

function xhrGet(url) {	
	var deferred = new Deferred()
	var xhr = new XmlHttpRequest()
	xhr.open("GET", url, true); 
	xhr.onreadystatechange = function() {
		if (xhr.readyState!=4) return
		if (xhr.status==200) {
			deferred.callback(xhr.responseText)  
		} else {
			deferred.errback(xhr.statusText)
		}
	}
	xhr.send(null)

	return deferred
}

А внешний код может добавить к нему обработчики для успешно полученного результата и для ошибки:

var deferred = xhrGet("http://someurl")
deferred.addCallback(function(res) { alert("Result: "+res); return res })
deferred.addErrback(function(err) { alert("Error: "+err); return err })

Внутри Deferred - это просто упорядоченный список пар callback/errback. Методы addCallback, addErrback, addBoth и addCallbacks добавляют в него элементы.

Например, последовательность обработчиков

var deferred = new Deferred()
deferred.addCallback(myCallback)
deferred.addErrback(myErrbac)
deferred.addBoth(myBoth)
deferred.addCallbacks(myCallback, myErrback)

внутри объекта Deferred становится списком:

[
	[myCallback, null],
	[null, myErrback],
	[myBoth, myBoth],
	[myCallback, myErrback]
]

Каждый вызов add* добавляет один элемент в список, как показано выше.

Внутри у Deferred есть одно из трех состояний (свойство "fired"):

  • -1, еще нет результата
  • 0, есть результат "success"
  • 1, произошла ошибка "error"

Deferred приходит в состояние "error" в одном из трех случаев:

  1. аргумент callback или errback является instanceof Error
  2. из последнего обработчика выпал exception
  3. последний обработчик вернул значение instanceof Error

Во всех остальных случаях, Deferred находится в состоянии "success".

Состояние Deferred определяет, какой обработчик будет вызван из следующего элемента последовательности. Если соответствующее значение равно null (например, надо вызвать errback, а элемент имеет вид [callback, null]), то этот элемент пропускается.

В случае с обработчиками выше, результат будет обработан примерно так (представьте, что все exceptions перехватываются и возвращаются):

// d.callback(result) or d.errback(result)
if(!(result instanceof Error)){
	result = myCallback(result);
}
if(result instanceof Error){
	result = myErrback(result);
}
result = myBoth(result);
if(result instanceof Error){
	result = myErrback(result);
}else{
	result = myCallback(result);
}

Полученный результат затем хранится на тот случай, если к последовательности обработчиков будет добавлен новый элемент. Так как результат уже есть, то при добавлении нового обработчика - он тут же будет активирован.

Обработчики, в свою очередь, могут возвращать объекты Deferred.

При этом остальная часть цепочки исходного Deferred ждет, пока новый Deferred не вернет значение, чтобы, в зависимости от этого значения, вызвать callback или errback.

Таким способом можно сделать реализовать последовательность вложенных асинхронных вызовов.

При создании объекта Deferred можно задавать "canceller" - функцию, которая будет вызвана, если до появления результата произойдет вызов Deferred.cancel.

С помощью canceller можно реализовать "чистый" обрыв XMLHTTPRequest, и т.п.

Вызов cancel запустит последовательность обработчиков Deferred с ошибкой CancelledError (если canceller не вернет другой результат), поэтому обработчики errback должны быть готовы к такой ошибке, если, конечно, вызов cancel в принципе возможен.

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

Например, вместо того, чтобы регистрировать callback-функцию, которая будет вызвана при окончании операции рендеринга, можно просто вернуть Deferred.

// объявление с callback
function renderLotsOfData(data, callback){
	var success = false
	try{
		for(var x in data){
			renderDataitem(data[x]);
		}
		success = true;
	}catch(e){ }
	if(callback){
		callback(success);
	}
}

// использование объявления с callback
renderLotsOfData(someDataObj, function(success){
	// handles success or failure
	if(!success){
		promptUserToRecover();
	}
})

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

Кроме того, Deferred освобождает от беспокойства на тему "а, может, вызов уже произошел?", например, в случае возврата результата из кеша. С Deferred, новые обработчики могут быть добавлены в любой момент, даже если результат уже получен.

function renderLotsOfData(data){
	var d = new Deferred();
	try{
		for(var x in data){
			renderDataitem(data[x]);
		}
		d.callback(true);
	}catch(e){ 
		d.errback(new Error("rendering failed"));
	}
	return d;
}

// использование Deferred 
renderLotsOfData(someDataObj).addErrback(function(){
	promptUserToRecover();
});
// NOTE: addErrback и addCallback возвращают тот же Deferred,
// так что мы можем тут же добавить в цепочку новые обработчики
// или сохранить deferred для добавления обработчиков позже.

В этом примере renderLotsOfData работает синхронно, так что оба варианта довольно-таки искусственные. Поставим отображение данных в setTimeout (типа идет анимация), чтобы почувствовать, как крут Deferred:

// Deferred и асинхронная функция
function renderLotsOfData(data){
	var d = new Deferred()
	setTimeout(function(){
		try{
			for(var x in data){
				renderDataitem(data[x]);
			}
			d.callback(true);
		}catch(e){ 
			d.errback(new Error("rendering failed"));
		}
	}, 100);
	return d;
}

// используем Deferred для вызова
renderLotsOfData(someDataObj).addErrback(function(){
	promptUserToRecover()
})

// Заметим, что вызывающий код не потребовалось исправлять
// для поддержки асинхронной работы

Благодаря Deferred - почти не пришлось ничего менять, порядок обработчиков соответствует реально происходящему, в общем - все максимально удобно и наглядно!

Объект DeferredList расширяет Deferred.

Он позволяет ставить каллбек сразу на пачку асинхронных вызовов.

Это полезно, например, для асинхронной загрузки всех узлов на одном уровне javascript-дерева, когда хочется сделать что-то после окончания общей загрузки.

Объект Deferred есть в javascript-фреймворках Dojo и Mochikit. Кроме того, и там и там есть вспомогательный объект DeferredList.

Собственно, эта статья написана частично по документации dojo. Автор считает, что имеет на это право, т.к сам приложил руку к этой части разработки данного фреймворка . Впрочем, из обоих фреймворков Deferred можно легко вынуть и приспособить к собственной библиотеке, если таковая у вас имеется.

Успешной асинхронной разработки.


Автор: Гость (не зарегистрирован), дата: 29 августа, 2008 - 15:32
#permalink

Что-то я дочитал до конца и понял, что Deffered только при наличии фреймворков есть. Можно было это в начале написать))


Автор: chebur (не зарегистрирован), дата: 18 февраля, 2009 - 22:46
#permalink

> С помощью canceller можно реализовать "чистый" обрыв XMLHTTPRequest, и т.п.
что такое "чистый обрыв XHR"?
не совсем понятно зачем нужен canceler, можете привести пример?


Автор: Илья Кантор, дата: 16 января, 2011 - 18:32
#permalink

Для отмены любого асинхронного события.


Автор: Гость (не зарегистрирован), дата: 30 марта, 2009 - 12:44
#permalink

Часто необходимо для работы с вводом в Text-box'ы - когда человек нажал 1ую букву пошёл первый запрос, через несколько миллисекунд человек нажал вторую букву - пошёл второй запрос. Если, например на сервере идёт select с условием where text like '<введённые символы>%' то результат с 2ми буквами может вернуть гораздо меньше строк (в разы) да и выполнится быстрее, скорее всего - в результате получается, что ответ от запроса 2 может придти раньше 1-го, а первый, в свою очередь, может "затереть" второй. Для пользователя это будет выглядеть, так, как будто 2ой запрос не выполнился.


Автор: Гость (не зарегистрирован), дата: 13 июня, 2009 - 20:42
#permalink

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


Автор: Гость (не зарегистрирован), дата: 6 июля, 2009 - 17:39
#permalink

В таком случае callback будет вызван сразу же после его добавления к объекту Deferred.


Автор: oleg2, дата: 17 сентября, 2010 - 10:20
#permalink

Если у Deferred вызвать errback с "не ошибкой", например .errback(10) - по описанию получается что Deferred будет в состоянии "success" и вызовы начнутся с callback- в не errback-функций.

Так ли это? Правильно ли это?


Автор: Ilya Kharlamov, дата: 26 марта, 2011 - 01:16
#permalink

С простыми Deferred всё просто и понятно. Но проблемы начинаются когда начинается вложенность и циклы.
К примеру, есть массив id юзеров

var userIds = [3, 18, 10];

Нужно к примеру, асинхронно вернуть названия групп в которых состоят эти юзеры. (Пример придуман из головы чтобы показать проблему).

var groupNames = ['Admin', 'Guest', 'User']

предположим, есть в наличии два XMLHttpRequest : getGroupIdByUserId и getGroupNameByGroupId
Просто, не правда ли? Но попробуйте написать код, который бы это делал асинхронно, используя Deferred и остался читабельным.


Автор: Гость (не зарегистрирован), дата: 29 октября, 2014 - 02:05
#permalink

console.log('hello')


Автор: Sheryl Webb (не зарегистрирован), дата: 18 апреля, 2019 - 09:53
#permalink

Можно конечно использовать существующие библиотеки, но мне нравится этот вариант. happy wheels free play


Автор: ashenshakily (не зарегистрирован), дата: 1 мая, 2019 - 16:41
#permalink

Объект Deferred инкапсулирует последовательность обработчиков для еще не существующего результата, чем сильно упрощает сложные AJAX-приложения. Он предоставляется различными фреймворками (Dojo Toolkit, Mochikit) и отдельными библиотечками (madalin stunt cars 2, Promises etc).


Автор: katedaisy (не зарегистрирован), дата: 14 мая, 2019 - 12:06
#permalink

Thanks for this wonderful article and continue sharing more topics like this.
cool math games


Автор: happywheelspace (не зарегистрирован), дата: 13 июня, 2019 - 15:23
#permalink

Thanks for this all detailed information. Providing all the coding and coding errors and telling us the proper way of doing it, happy wheels unblocked free online.


Автор: jimmu, дата: 2 июля, 2019 - 02:19
#permalink

Thanks for sharing this wonderful article.


Автор: RoBerti Berti (не зарегистрирован), дата: 6 января, 2020 - 07:26
#permalink

In stressful working hours, your work is too stressful. We always create a sense of comfort for you so you have a relaxing time. You try dinosaur game an extremely fun game. thank you!


Автор: the impossible quiz (не зарегистрирован), дата: 7 января, 2020 - 11:38
#permalink

This is such a great resource that you are providing and you give it away for free.


Автор: the impossible quiz (не зарегистрирован), дата: 7 января, 2020 - 11:38
#permalink

This is such a great resource that you are providing and you give it away for free.


Автор: Гость (не зарегистрирован), дата: 10 февраля, 2020 - 09:38
#permalink

java is best useable programming language if you want to learn how to reinstall onedrive just visit windowsclassroom website and learan about OneDrive


Автор: spaces (не зарегистрирован), дата: 8 марта, 2020 - 08:40
#permalink

Why it is so hard to understand coding process. Thanks for sharing this geometry dash unblocked


Автор: Гость (не зарегистрирован), дата: 21 марта, 2020 - 06:05
#permalink

My friend's blog I read, I am very impressed with your blog, I hope you will have more blogs or more posts to bring to readers.
vex 3


Автор: Amel Cindy (не зарегистрирован), дата: 21 мая, 2020 - 05:34
#permalink

Excellent post. Please keep up the great work. You may check our website also Visit: free fonts


Автор: Molly (не зарегистрирован), дата: 21 мая, 2020 - 18:21
#permalink

offshore hosting with 100% DMCA ignored Hosting, Offshore Dedicated Server, Offshore VPS Hosting. offshorededi.com is the Most Secure Offshore Hosting. Providing Offshore Streaming Servers as well.


Автор: webcare360 (не зарегистрирован), дата: 4 июня, 2020 - 00:31
#permalink

Hi there, I found your website via Google while searching for a related topic, your website came up, it looks great. I have bookmarked it in my google bookmarks.


Автор: davidnwhitfield (не зарегистрирован), дата: 24 июля, 2020 - 10:04
#permalink

Мне нужно работать с этим кодированием, я могу полностью понять, возможно, сделав несколько попыток, спасибо за предоставленную информацию.
bubbles


Автор: lindadhansen (не зарегистрирован), дата: 24 августа, 2020 - 13:22
#permalink

Хотя я пытаюсь работать с этими кодировками, иногда я не могу понять, и это заставляет меня очень стараться. basketball legends


Автор: Гость (не зарегистрирован), дата: 6 октября, 2020 - 10:47
#permalink

You provided a lot of good information, it was good because it was so helpful to me. word finder


Автор: Гость Emily9x (не зарегистрирован), дата: 26 октября, 2020 - 10:07
#permalink

Oh, great, your article provided me with useful information and a fresh perspective on the subject. Check to finish your trip!


Автор: 먹튀검증커뮤니티 (не зарегистрирован), дата: 22 ноября, 2020 - 05:23
#permalink

Your texts on this subject are correct, see how I wrote this site is really very good 먹튀검증커뮤니티


Автор: 소액대출 (не зарегистрирован), дата: 22 ноября, 2020 - 05:24
#permalink

Your texts on this subject are correct, see how I wrote this site is really very good 소액대출


Автор: chin woo (не зарегистрирован), дата: 5 января, 2021 - 05:46
#permalink

do you like that
word counter tool


Автор: hassie (не зарегистрирован), дата: 19 января, 2021 - 10:43
#permalink

Хотя мы можем исправить ошибку, вызвав src.Close () перед оператором return во втором предложении return; Но по мере того, как код становится более сложным, подобные проблемы становится все труднее найти и 2 player games решить. Мы можем использовать предложение defer, чтобы гарантировать, что нормально открытый файл также будет закрыт.


Автор: friday night funkin (не зарегистрирован), дата: 27 июля, 2021 - 10:12
#permalink

Необычный пост! Я не знал об этих активах, и я пойду их сейчас! friday night funkin


Автор: Laura Klemenz (не зарегистрирован), дата: 7 марта, 2022 - 23:28
#permalink

Sex in Dresden Rufen Sie sie an, um das Datum zu bestätigen! Ärzte und Zahnärzte tun das, Sie sollten es auch tun. Da Männer die Frauen, mit denen sie sich verabreden, in der Regel nicht abholen, ist ein Anruf zur Bestätigung einer Verabredung ziemlich einfach und beruhigt die Frauen.


Автор: 안전토토사이트 (не зарегистрирован), дата: 11 марта, 2022 - 07:42
#permalink

Wow, fantastic blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your website is excellent, let alone the content! 안전토토사이트


Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 03:00
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 12:02
#permalink

Автор: Гостьy (не зарегистрирован), дата: 20 июня, 2022 - 11:59
#permalink

Мы все живем в самую стабильную десятилетнюю эпоху. bob the robber 4 - Chapter Thirteen — привлекательная и великолепная игра для Android с характерным дизайном и конструкцией в стиле экшн — приключенческих игр от компании-производителя игр, текущее обновление выходит в бесконечном количестве по вашему запросу. Доставить, оставаясь перед вами!


Автор: Austin Burgess (не зарегистрирован), дата: 30 июня, 2022 - 05:24
#permalink

Complex functions, each having a slew of return keywords, can be used to handle multiple jobs at once. There may be some cleanup to be done after returning from a function. bubble shooter


Автор: Annemiek Verkuijl (не зарегистрирован), дата: 1 августа, 2022 - 20:37
#permalink

Sexdate Gravatar


Автор: where-to-buy-rick-simpson-oil-rso-5g (не зарегистрирован), дата: 25 августа, 2022 - 19:52
#permalink

Wonderful illustrated information. I thank you about that. No doubt it will be very useful for my future projects. Would like to see some other posts on the same subject. where-to-buy-rick-simpson-oil-rso-5g


Автор: Гость (не зарегистрирован), дата: 2 ноября, 2022 - 06:47
#permalink

The drift hunters Game gives you an easy-to-use and efficient management and Drift Hunters allows you to focus on the most important things.


Автор: Nursing Assignment Experts (не зарегистрирован), дата: 8 ноября, 2022 - 16:05
#permalink

Students can experience anxiety when submitting their homework on their own. Lack of understanding and interest in the topic is the problem. We advise that you get hassle-free nursing Nursing Assignment Experts from native specialists to help you deal with this circumstance.


Автор: toto365pro (не зарегистрирован), дата: 28 ноября, 2022 - 07:10
#permalink

Simply desire to say your article is as amazing. 토토


Автор: toto365pro (не зарегистрирован), дата: 28 ноября, 2022 - 07:11
#permalink

"I think youve created some actually interesting points. 스포츠중계


Автор: toto365pro (не зарегистрирован), дата: 28 ноября, 2022 - 07:12
#permalink

Thanks for posting this, it was unbelievably informative and helped me a lot. 토토


Автор: toto365pro (не зарегистрирован), дата: 28 ноября, 2022 - 07:13
#permalink

These are actually impressive ideas in concerning blogging. 슬롯머신


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
1 + 10 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum