javascript - español - ¿Cómo encadeno una secuencia de funciones diferidas en jQuery 1.8.x?
jquery deferred example (3)
Teniendo en cuenta estas funciones:
function func1() {
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve(''Password'');
}, 1000);
return dfd.promise();
}
function func2(message) {
var dfd = $.Deferred();
setTimeout(function() {
if (message == ''Password'') {
dfd.resolve(''Hello World'');
}
}, 1000);
return dfd.promise();
}
Me gustaría encontrar una mejor manera de hacer lo siguiente. Tenga en cuenta que esto está usando jQuery 1.8.x.
var promise = func1();
promise.done(function(message1) {
var promise2 = func2(message1);
promise2.done(function(message2) {
alert(message2);
});
});
¿Algunas ideas? Pensé que usar jQuery #pipe o #then funcionaría, pero no puedo entenderlo. Aquí hay un violín para jugar: http://jsfiddle.net/Z7prn/
No es tan complicado (ya sea usar .then
o .pipe
, ambos son iguales desde jQuery 1.8, creo).
promise.then(func2).done(function(message) {
alert(message);
});
Como func2
devuelve un nuevo objeto diferido, la .done
llamada .done
se adjunta a ese lugar.
Tuve un caso de uso similar, así que creo que esto debería ayudarte.
El siguiente método tomará una serie de métodos (que pueden o no devolver Promesas) y los ejecutará en secuencia, esperando hasta que se complete cada aplazamiento antes de continuar. El comportamiento predeterminado es detenerse en caso de fallo; El segundo argumento le permite continuar si la llamada falla o no.
las firmas de controlador de hecho / fallar son (Array < contexto >) Función (Array <Objeto {rechazado | resuelto: argumentos }>), donde contexto es el contexto de cada resolución con llamada / rechazo con llamada, o el diferido en cuestión, y argumentos es el argumento Conjunto que se pasó en la resolución / rechazo.
(function ($) {
"use strict";
var copy = function (a) {
return Array.prototype.slice.call(a);
};
/**
Handle a sequence of methods, stopping on failure by default
@param Array<Function> chain List of methods to execute. Non-deferred return values will be treated as successful deferreds.
@param Boolean continueOnFailure Continue executing even if one of the returned deferreds fails.
@returns Deferred
*/
$.sequence = function (chain, continueOnFailure) {
var handleStep, handleResult,
steps = copy(chain),
def = new $.Deferred(),
defs = [],
results = [];
handleStep = function () {
if (!steps.length) {
def.resolveWith(defs, [ results ]);
return;
}
var step = steps.shift(),
result = step();
handleResult(
$.when(result).always(function () {
defs.push(this);
}).done(function () {
results.push({ resolved: copy(arguments) });
}).fail(function () {
results.push({ rejected: copy(arguments) });
})
);
};
handleResult = continueOnFailure ?
function (result) {
result.always(function () {
handleStep();
});
} :
function (result) {
result.done(handleStep)
.fail(function () {
def.rejectWith(defs, [ results ]);
});
};
handleStep();
return def.promise();
};
}(this.jQuery));
Un ejemplo simple de uso: http://jsfiddle.net/rG9rA/
function func1() {
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve(''Password'');
}, 1000);
return dfd.promise();
}
function func2(message) {
var dfd = $.Deferred();
setTimeout(function() {
if (message == ''Password'') {
dfd.resolve(''Hello World'');
}
}, 1000);
return dfd.promise();
}
$.sequence([func1, func2, function () { alert(''done''); }]);
Utilice JQuery.when() . Es exactamente lo que desea encadenar a una serie de aplazados y ejecutar una función cuando todos hayan terminado.
Actualización 2017 (después de ver downvotes):
Lo que quería OP era una versión mejorada de su código para ejecutar promesas secuencialmente. Aquí está mi versión usando $.when
:
function func1() {
var dfd = $.Deferred();
setTimeout(function() {
dfd.resolve(''Password'');
}, 1000);
return dfd.promise();
}
function func2(message) {
var dfd = $.Deferred();
setTimeout(function() {
if (message == ''Password'') {
dfd.resolve(''Hello World'');
}
}, 1000);
return dfd.promise();
}
// ~~~~~~~~~~ using $.when here ~~~~~~~~~~~~
$.when(func1()).then(function(result1) {
$.when(func2(result1)).then(function(result2) {
alert(result2);
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>