#javascript #jquery #jquery-deferred
#javascript #jquery #jquery-отложенный
Вопрос:
Я скачал библиотеку, призванную jsdeferred
попытаться помочь мне с некоторыми проблемами с потоком кода, но я немного запутался, так как ее примеры и … «документация» немного неясны в некоторых вещах. Но по мере того, как я продолжал читать и копать, и, конечно, гуглил все под солнцем, я также обнаружил, что у jQuery есть своя собственная Deferred()
система. Я связываю оба здесь для правильного контекста.
Ссылка на библиотеку jsDeferred
Ссылка на jQuery.Отложенный ()
Проблема
Мне нужно найти способ указать странице «держаться, пока не будет сделано последнее».
Это то, что сделал thought jsdeffered
. Итак, часть моего вопроса заключается в том, что я должен использовать? jsDeferred или jQuery.Deferred(); а затем, как его использовать, как я изложил ниже.
Ситуация
Мой сценарий таков, в двух словах, мне нужно выполнить следующее поведение.
- страница загружается,
view model
определяется
Это используется kendo ui mvvm
для объявления моей модели представления, поэтому это kendo.data.ObservableObject
- для
$.ajax
получения некоторых данных модели по умолчанию выполняется вызов базы данных
Вот где у меня больше всего проблем. Мне нужно, чтобы все «держалось», пока это $.ajax
не будет сделано. Но я не хочу оборачивать все в $.ajax().done(r)
, если я могу с этим поделать. Для меня это выглядит / кажется очень неаккуратным и иногда сбивает с толку.
- другие виджеты на странице отображаются, они выполняют соответствующие запросы к базе
kendo ui Remote DataSource
данных.
На самом деле они работают так, как задумано.
jQuery Validate
подключен к представлению, при этом значения по умолчанию уже установлены.
Это также работает по назначению.
kendo.bind('body', viewModel);
вызывается для выполнения привязки модели.
Теперь я сталкиваюсь с проблемой, возвращаясь к step 2
тому месту, где я делал $.ajax
вызов. Что продолжает происходить, так это то, что kendo.bind
запускается до $.ajax
завершения. Я могу поместить это в $.ajax({}).done();
функцию, и для этой конкретной конкретной страницы, которая действительно работает, но будет много других ситуаций, когда это не подходит.
Что я пробовал
Во-первых, я поясню, что jsdeferred
документация для меня очень неясна, поскольку дословное выполнение ее примеров на самом деле не работает. Мне постоянно говорят об этом next is not defined
и тому подобное. В конце концов я понял, что Deferred.
перед первым вызовом у вас должно быть неявное next
значение.
Итак, вот что, как я думал, произойдет…
var viewModel = new kendo.data.ObservableObject({
// various view model properties defined
});
Deferred.define();
next(function() { // let's call this STEP 1
$.ajax({
// data for ajax to controller
}).done(function(result) {
// perform operations with result
});
}).
next(function() { // let's call this STEP 2
$('#dropdownlist_target').kendoDropDownList({
// parameters, remote data source for drop down list, etc.
}).data("kendoDropDownList");
}).
next(function() { // let's call this STEP 3
$('form').validate({
// any extra form validation stuff
});
}).
next(function(){ // let's call this STEP 4
kendo.bind('body', viewModel);
});
Я полагал, что каждый из них будет выполняться один за другим, когда предыдущий будет завершен. Но это не то, что происходит. STEP 1
все еще находится в процессе выборки во время STEP 2, 3
и 4
выполняется.
Похоже, это ничем не отличается от способа выполнения кода без jsdeferred
библиотеки. Так что я очень смущен и был бы очень рад некоторой помощи здесь. В принципе, мне нужно STEP 1
быть полностью законченным до STEP 2
запуска.
Ответ №1:
Проблема в том, что next()
ожидается, что вы вернете то, что вы хотите, чтобы оно ожидало. На первом шаге вы ничего не возвращаете. jsdeferred
поэтому предполагается, что вы выполняли синхронную операцию (которая уже завершена), и поэтому она продолжается с шага 2.
Вместо этого верните jQuery.Deferred()
возвращенное из $.ajax()
вызова. затем jsdeferred будет ждать завершения, прежде чем выполнить шаг 2.
Независимо от этого, я бы сбросил jsdeferred
. Как вы поняли, jQuery имеет полноценную отложенную реализацию. Я не уверен, что jsdeferred привносит в вечеринку.
Использование $.ajax().done(r)
не является небрежным. Асинхронное поведение является ядром языков, управляемых событиями, и JavaScript является одним из них. Примите это, или вы очень рано облысеете, пытаясь избежать этого.
Если вы вернетесь к отложенной реализации jQuery, возможно, вам захочется then()
предоставить вам семантику next()
;
$.ajax({
// data for ajax to controller
}).done(function(result) {
// perform operations with result
}).then(function () {
$('#dropdownlist_target').kendoDropDownList({
// parameters, remote data source for drop down list, etc.
}).data("kendoDropDownList");
$('form').validate({
// any extra form validation stuff
});
kendo.bind('body', viewModel);
}).then(function () {
// Note you can chain then()'s as well.
});
Комментарии:
1. Когда я говорю
"sloppy"
, я не имею в виду плохой код . Я имею в виду, что лично у меня много проблем с пониманием того, когда что-то запускается — я еще не очень хорошо разбираюсь во всех асинхронных вещах, поэтому для меня это получается неаккуратно, потому что я все еще учусь правильно управлять этим.2. И да, мне нужно научиться делать это чаще. Я полностью согласен — иногда это просто сложный процесс.
3. Привет, @Matt, это было идеально. Вы точно поняли, чего я пытался достичь, и презентация легко читается. Я думал
done
, что это эксклюзивно для$.ajax
, и именно здесь я заблудился. Это упростит написание большого количества кода!4. @Ciel: Ах, извините… Я неверно истолковал то, что вы имели в виду :). Объект jqXHR (который возвращает метод ajax() jQuery) предоставляет те же методы, что и jQuery. Обещание Deferred() будет. У jQuery есть документация для всех этих методов и типов, которые могут помочь ему разобраться, хотя я признаю, что документация jQuery для Deferreds в целом — дерьмо. Однако хорошей новостью является то, что концепция promise и deferreds довольно стандартизирована, поэтому любая документация, которую вы можете найти по этому вопросу, может помочь понять идею. Извините, я не могу предоставить никаких ссылок, я нахожусь на своем телефоне, но я надеюсь, что это поможет!
5. Да, я попытался прочитать их документацию
deferred
, иpromise
, и я думаю, что кровь начала стрелять из моих ушей.
Ответ №2:
Вы можете просто использовать then
метод для своего $.ajax()
результата так же, как вы используете next
помощник jsDeferred. Вообще говоря, then
это более гибкий метод, чем done
. И, как отметил Мэтт в своем ответе, в программировании на основе обещаний распространенной ошибкой является забывание return
нового обещания в обработчике, что приводит к его преждевременному разрешению undefined
вместо ожидания нового обещания.
$.ajax({ // let's call this STEP 1
// data for ajax to controller
}).
then(function(result) {
// perform operations with result
}).
then(function() { // let's call this STEP 2
$('#dropdownlist_target').kendoDropDownList({
// parameters, remote data source for drop down list, etc.
}).data("kendoDropDownList");
}).
then(function() { // let's call this STEP 3
$('form').validate({
// any extra form validation stuff
});
}).
done(function(){ // let's call this STEP 4
kendo.bind('body', viewModel);
});
Обратите внимание, что в моем рефакторинге все эти then
s будут выполняться немедленно подряд, если не будет возвращено новое обещание. Так что вы можете также объединить их.
then
принимает функцию, которая либо возвращает значение, либо обещание, и возвращает новое обещание. Если его функция возвращает значение, новое обещание немедленно разрешается с этим значением. Если его функция вернула обещание, то это обещание передается как новое обещание. Обратите внимание, что jQuery then
работает только таким образом, начиная с версий jQuery> = 1.8.
Комментарии:
1. Эй, это также было полезно в сочетании с принятым ответом. Большое вам спасибо. Если я могу спросить, возможно ли выполнить такую цепочку с любым другим типом объекта, кроме простого
$.ajax
вызова?2. Абсолютно! Объект jqXHR, возвращаемый с помощью
ajax
, отвечает на те же методы, что и обещание jQuery. Вы можете сделать это самостоятельно, используя$.Deferred
.3. Да, я пытаюсь прочитать
$.Deferred
, но, черт возьми, у меня кружится голова. Я начинаю понимать, почемуjsdeferred
было написано. Я думаю, чтоjsdeferred
это было сделано до$.Deferred
того, как стало большей частью jQuery (хотя я не могу это доказать).4. Я настоятельно рекомендую прочитать gist.github.com/domenic/3889970 чтобы по-настоящему усвоить, как работают обещания. Тогда вам действительно просто нужно понять два основных способа создания promise. Существует функциональный способ, с помощью которого вам передаются разрешающие и отклоняющие обратные вызовы, как показано здесь ( github.com/cujojs/when/blob/master/docs/api.md#whenpromise ). Тогда есть способ ООП, типичный
$.Deferred
для и здесь ( github.com/cujojs/when/blob/master/docs/api.md#whendefer ), в котором вы используете методы отложенного объекта с методами для разрешения и отклонения обещания.5. @Ciel ^ (чтобы привлечь ваше внимание)