Когда я должен использовать jQuery отложенные на "потом" способ и когда я должен использовать "метод трубы"?


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

then()

deferred.then( doneCallbacks, failCallbacks ) Returns: Deferred

doneCallbacks функция или массив функций, вызываемых при разрешении отложенной операции.
failCallbacks функция или массив функций, вызываемых при отложенном отвергнутый.

pipe()

deferred.pipe( [doneFilter] [, failFilter] ) Returns: Promise

doneFilter необязательная функция, которая вызывается при разрешении отложенной операции.
failFilter необязательная функция, которая вызывается, когда отложенный отклоняется.

я знаю then() был вокруг немного дольше, чем pipe() Так что последний должен добавить некоторую дополнительную выгоду, но что разница точно ускользает от меня. Оба принимают в значительной степени те же параметры обратного вызова, хотя они отличаются по имени и разнице между возвращением a Deferred и возврат Promise покажется легким.

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

так когда же лучше использовать then а когда лучше использовать pipe?


дополнение

отличный ответ Феликса действительно помог прояснить как эти две функции отличаются. Но мне интересно, есть ли времена, когда функциональность then() предпочтительнее, чем pipe().

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

но есть ли прецедент, который требует then()возвращает оригинал Deferred Это не может быть сделано с помощью pipe() из-за него возвращается новый Promise?

3 94

3 ответа:

С jQuery 1.8.then аналогично .pipe:

Уведомление Об Устаревании: по состоянию на jQuery 1.8,deferred.pipe() метод устарел. Элемент deferred.then() метод, который заменяет его, следует использовать вместо этого.

и

по состоянию на jQuery 1.8 на deferred.then() метод возвращает новое обещание, которое может фильтровать статуса и значения отложенного через функцию, заменяя теперь-устарел deferred.pipe() метод.

приведенные ниже примеры могут быть полезны для некоторых.


они служат разным целям:

  • .then() должна использоваться всякий раз, когда вы хотите работать с результатом процесса, т. е. как сказано в документации, когда отложенный объект разрешен или отклонен. Это то же самое, что использовать .done() или .fail().

  • вы могли бы использовать .pipe() to (предварительно)фильтр результат как-то. Возвращаемое значение обратного вызова .pipe() будет передано в качестве аргумента в done и fail обратные вызовы. Он также может возвращать другой отложенный объект, и на этом отложенном объекте будут зарегистрированы следующие обратные вызовы.

    это не так с .then() (или .done(),.fail()), возвращаемые значения зарегистрированных обратных вызовов просто игнорируются.

так это не то, что вы используете или.then()или.pipe(). Ты может использовать .pipe() для тех же целей, что .then() но обратное не держится.


Пример 1

результатом некоторой операции является массив объектов:

[{value: 2}, {value: 4}, {value: 6}]

и вы хотите, чтобы вычислить минимальное и максимальное значения. Предположим, мы используем два done обратные вызовы:

deferred.then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var min = Math.min.apply(Math, values);

   /* do something with "min" */

}).then(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    var max = Math.max.apply(Math, values);

   /* do something with "max" */ 

});

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

не лучше ли каким-то образом извлечь значения заранее, чтобы вам не пришлось делать это в обоих обратных вызовах по отдельности? Да! И это то, что мы можем использовать .pipe() для:

deferred.pipe(function(result) {
    // result = [{value: 2}, {value: 4}, {value: 6}]

    var values = [];
    for(var i = 0, len = result.length; i < len; i++) {
        values.push(result[i].value);
    }
    return values; // [2, 4, 6]

}).then(function(result) {
    // result = [2, 4, 6]

    var min = Math.min.apply(Math, result);

    /* do something with "min" */

}).then(function(result) {
    // result = [2, 4, 6]

    var max = Math.max.apply(Math, result);

    /* do something with "max" */

});

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


Пример 2

рассмотрим вызовы Ajax. Иногда вы хотите инициировать один вызов Ajax после завершения предыдущего. Один из способов-сделать второй вызов внутри done обратного вызова:

$.ajax(...).done(function() {
    // executed after first Ajax
    $.ajax(...).done(function() {
        // executed after second call
    });
});

теперь предположим, что вы хотите отделить свой код и поместить эти два вызова Ajax внутри функции:

function makeCalls() {
    // here we return the return value of `$.ajax().done()`, which
    // is the same deferred object as returned by `$.ajax()` alone

    return $.ajax(...).done(function() {
        // executed after first call
        $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

вы хотели бы использовать отложенный объект, чтобы разрешить другой код, который вызывает makeCalls чтобы прикрепить обратные вызовы для второй AJAX-вызов, но

makeCalls().done(function() {
    // this is executed after the first Ajax call
});

не было бы желаемого эффект как второй вызов производится внутри done обратный вызов и не доступны снаружи.

решение было бы использовать .pipe() вместо:

function makeCalls() {
    // here we return the return value of `$.ajax().pipe()`, which is
    // a new deferred/promise object and connected to the one returned
    // by the callback passed to `pipe`

    return $.ajax(...).pipe(function() {
        // executed after first call
        return $.ajax(...).done(function() {
            // executed after second call
        });
    });
}

makeCalls().done(function() {
    // this is executed after the second Ajax call
});

С помощью .pipe() теперь вы можете добавить обратные вызовы к "внутреннему" вызову Ajax, не раскрывая фактический поток/порядок вызовов.


в общем, отложенные объекты предоставляют интересный способ развязать ваш код:)

нет случая, когда вы должны использовать then() over pipe(). Вы всегда можете игнорировать значение, которое pipe() пройдет. Там может быть небольшой производительности для использования pipe -- но это вряд ли важно.

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

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

так что используйте then() когда надо, и pipe() когда вы должны...

на самом деле оказывается, что разница между .then() и .pipe() было сочтено ненужным, и они были сделаны так же, как и в jQuery версии 1.8.

С комментарий jaubourg в трекере ошибок jQuery билет № 11010 " СДЕЛАТЬ ОТЛОЖЕННЫМ.ТОГДА = = ОТЛОЖЕНО.ТРУБА, КАК ОБЕЩАНИЕ / A":

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

(подчеркиваю мое)