2013-12-19 6 views
1

Мой код:Как вызывать отложенные функции последовательно?

<?php 
if(isset($_GET['m'])) { 
    $m = $_GET['m']; 
    sleep($m); 
    print "done, m=$m"; 
    die; 
} 
?> 

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" ></script> 
<script> 

    function w(s) { 
     document.body.innerHTML = document.body.innerHTML+ "<br>" + s 
    } 

    function aaa(def) { 
     w("begin aaa"); 
     $.ajax({ 
      type: "GET", 
      data: { 
       m: 5 
      } 
     }).done(function(html) { 
      w(html); 
      def.resolve(); 
     }); 
    } 


    function bbb(def) { 
     w("begin bbb"); 
     $.ajax({ 
      type: "GET", 
      data: { 
       m: 1 
      } 
     }).done(function(html) { 
      w(html); 
      def.resolve(); 
     }); 
    } 

    $(function() { 

     $.when(
      $.Deferred(function(d) { aaa(d) }).promise(), 
      $.Deferred(function(d) { bbb(d) }).promise() 
     ).done(function() { 
      w("OK") 
     }); 
    }) 
</script> 

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

begin aaa 
    <--pause 
done, m=1 
begin bbb 
    <--pause 
done, m=5 
OK 

Вместо этого я получаю

begin aaa 
begin bbb 
    <--pause 
done, m=1 
    <--pause 
done, m=5 
OK 

Я думаю, что я неправильно понимаю, что-то фундаментальное о том, как работает отсрочка - может ли кто-нибудь пролить свет?

ответ

7

Как вы ожидаете, что они будут выполнены в порядке, если между ними нет зависимости? $.when не имеет и не может влиять на оценку обещания, он просто ждет, пока каждое из обещаний не будет разрешено.

Ваш код намного сложнее, чем это должно быть. $.ajax уже возвращает обещание, которое разрешается при получении ответа Ajax, поэтому вы можете просто вернуть его из функций. Если вы хотите, чтобы выполнить их в последовательности, вы можете приковать их через .then:

Эти функции фильтра могут возвращать новое значение, которое будет передано по обетованию в .done() или .fail() обратных вызовов, или они могут вернуть другой наблюдаемый объект («Отсрочка», «Обещание» и т. Д.), Которые передадут свои разрешенные/отклоненные статус и ценности для обратных вызовов обещания.

Так что ваш код упрощается:

function aaa() { 
    w("begin aaa"); 
    return $.ajax({ 
     type: "GET", 
     data: { 
      m: 5 
     } 
    }).done(w); 
} 


function bbb() { 
    w("begin bbb"); 
    return $.ajax({ 
     type: "GET", 
     data: { 
      m: 1 
     } 
    }).done(w); 
} 

aaa().then(bbb).done(function() { w('ok'); }); 

Здесь aaa().then(bbb) создает зависимость вам нужно. В основном это означает, что «однажды решение aaa будет разрешено, выполните bbb». Кроме того, .then возвращает новое обещание, которое разрешается, когда устраняется обещание, возвращаемое bbb, что позволяет выполнять функцию, когда обещаются обе стороны, aaa и bbb.

Может быть, это поможет вам понять обещания (и deferreds) лучше:


Пример без $.ajax:

function aaa() { 
    var def = new $.Deferred(); 
    setTimeout(function() { 
     def.resolve(21); 
    }, 3000); 
    return def.promise(); 
} 

function bbb(v) { 
    var def = new $.Deferred(); 
    setTimeout(function() { 
     def.resolve(v * 2); 
    }, 1000); 
    return def.promise(); 
} 

// aaa -> bbb -> console.log 
// The value is logged after 3 + 1 seconds 
aaa().then(bbb).done(function(v) { console.log(v); }); // 42 

// (aaa | bbb) -> console.log 
// The value is logged after max(3, 1) seconds and both resolved values are 
// passed to the final promise 
$.when(aaa(), bbb(5)).done(function(v) { console.log(v); }); // [21, 10] 
+0

Perfect, спасибо! – georg

+0

Итак, если вы хотите связать цепочку, 'A -> B -> C', используйте' .then'. Если вы хотите запустить их параллельно и сделать что-то, когда все будет готово, '(A | B) -> C', используйте' $ .when' :) И ваш приветствуем! –

+0

Для моего лучшего понимания вы могли бы добавить пример с чем-то вместо '$ .ajax', который не является отложенным per se, например, например. 'SetTimeout'. – georg

1

$.when() не налагает никакого порядка на свои аргументы - они фактически являются «неупорядоченным списком».

Однако , .fail() и .then() действительно наложите заказ.

Во-первых, упростить вещи путем внесения поправок aaa() и bbb() вернуть Promise-совместимый объект, возвращаемый $.ajax().done() цепи, следующим образом:

function aaa() { 
    w("begin aaa"); 
    return $.ajax({ 
     type: "GET", 
     data: { m: 5 } 
    }).done(w);//without changing anything, w can be passed rather than called from an anonymous function. 
} 

function bbb() { 
    w("begin bbb"); 
    return $.ajax({ 
     type: "GET", 
     data: { m: 1 } 
    }).done(w);//without changing anything, w can be passed rather than called from an anonymous function. 
} 

Теперь, чтобы получить эффект вы стремитесь использовать .then() к последовательности aaa и bbb:

$(function() { 
    aaa().then(bbb).done(function() { 
     w("OK"); 
    }); 
}); 

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

Чтобы поставить aaa и bbb на одном уровне друг с другом, вы могли бы написать что-то вроде:

$(function() { 
    $.Deferred().resolve().then(aaa).then(bbb).done(function() { 
     w("OK"); 
    }); 
}); 
+0

Спасибо, очень полезно. Надеюсь, ваши ответы и ответы Феликса сделают это хорошей справочной темой. – georg

Смежные вопросы