Как правильно использовать $ .deferred с ненаблюдаемыми функциями? - PullRequest
5 голосов
/ 19 марта 2011

Скажем, например, что у меня есть две функции со случайным кодом внутри, а также что на основе системы пользователя (медленная, средняя или быстрая) нет способа определить, сколько времени потребуется для выполнения двух функций, поэтомуиспользование setTimeout нецелесообразно при попытке выстрелить function2 только после завершения function1.

Как можно использовать jQuery.deferred, чтобы сделать function2 огонь только после function1 независимо от того, каковы временные требования, и учитывая, что обе функции являются на 100% не-jQuery-функциями без кода jQuery внутри и, следовательно, совершенно не наблюдаемы jQuery?Самое большее, функции могут включать в себя методы jQuery, такие как .css(), которые не имеют временной связи и могут работать медленнее на старых компьютерах.

Как убедиться, что function2 не выполняется одновременновремя как function1, если я назову их так:

function1(); function2();

, используя $.deferred?Любые другие ответы, кроме вопросов, касающихся $.deferred, также приветствуются!

ДОБАВЛЕНО 20 марта: Что если function1 () является лямбда-функцией, где, в зависимости от пользовательского ввода, функция может или можетнет асинхронных вызовов, и невозможно определить, сколько операций будет выполнять функция?Это была бы функция, в которой у вас не было бы никакой подсказки о том, что произойдет дальше, но, несмотря ни на что, вы все равно хотели бы, чтобы функция function2 выполняла только после всего из функции lambda (function1)выполняется, независимо от того, сколько времени это займет, но до тех пор, пока асинхронные аспекты завершены.Как этого достичь?

ДОБАВЛЕНО 22 марта: Так что я думаю, что единственный способ сделать то, что я прошу, - передать анонимные функции в качестве обратных вызовов асинхронным функциям, которые выполняют обратные вызовы послеони сделаны, или для создания прослушивателей событий, которые будут выполнять то, что вы хотите, когда событие, наконец, сработает.

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

Хорошим примером таких механизмов является метод .queue() jQuery и объект $.Defferred.

Ответы ниже, а также чтение API jQuery по .queue() ing и использование $.Deferred помогли прояснить это.

Tgr привел отличный пример ниже о том, как создавать собственные цепочки функцийиспользуя объект $.Deferred в jQuery, а сами пользовательские функции не требуютсяобязательно должен быть какой-либо код jQuery внутри, именно это я и искал.

Ответы [ 2 ]

6 голосов
/ 19 марта 2011
function first(deferred) {
    // do stuff
    deferred.resolve();
}
function second() {
    // do stuff
}

$.Deferred(first).then(second);

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

Обновление :

Основная идея заключается в том, что всякий раз, когда вы делаете что-то, что не является немедленным, вы создаете отложенный объект и возвращаете его.(Вызовы JQuery AJAX уже делают это.) Затем вы можете использовать Deferred.then для задержки последующих операций.

function first() {
    var deferred = $.Deferred();
    var callback = function() {
        deferred.resolve();
    }
    // do immediate stuff
    someAsyncOperation(callback);
    return deferred.promise(); // turns the Deferred into a Promise, which
                               // means that resolve() will not be accessible
}

function second() {
    // do stuff
}

first().then(second); // or: $.when(first).then(second)

Если second также является асинхронной операцией, вы можете использовать $.when.возможности объединения:

function second() {
    var anotherDeferred = $.Deferred();
    // do stuff with anotherDeferred
    return anotherDeferred.promise();
}

$.when(first(), second()).then(third); // third will run at the moment when 
                                   // both first and second are done
5 голосов
/ 19 марта 2011

Сам JavaScript является не асинхронным. Однопоточный, синхронный.

function1();
function2();

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

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


РЕДАКТИРОВАТЬ Ваш пример jsFiddle , исправлено ( посмотреть ):

function foo() {
  $('#foo')
  .html('<span>foo1</span>')
  .animate(
    {              /* properties */
      left: '100px' 
    },      
    360,           /* duration */
    'swing',       /* easing */
    function () {  /* "complete" callback */
      $('#foo').append('<span>foo2</span>');
      bar();
    } 
  );
}

Как я уже сказал. Вы всегда сможете перезвонить.

...