pagina mostrar mientras funcion ejecutar despues cargar carga asincrona antes javascript jquery jquery-deferred

javascript - mostrar - ¿Cómo se puede usar jQuery diferido?



ejecutar javascript despues de cargar pagina (11)

1) Utilícelo para garantizar una ejecución ordenada de devoluciones de llamada:

var step1 = new Deferred(); var step2 = new Deferred().done(function() { return step1 }); var step3 = new Deferred().done(function() { return step2 }); step1.done(function() { alert("Step 1") }); step2.done(function() { alert("Step 2") }); step3.done(function() { alert("All done") }); //now the 3 alerts will also be fired in order of 1,2,3 //no matter which Deferred gets resolved first. step2.resolve(); step3.resolve(); step1.resolve();

2) Úsalo para verificar el estado de la aplicación:

var loggedIn = logUserInNow(); //deferred var databaseReady = openDatabaseNow(); //deferred jQuery.when(loggedIn, databaseReady).then(function() { //do something });

jQuery 1.5 trae el nuevo objeto diferido y los métodos adjuntos .Deferred , .Deferred y ._Deferred .

Para aquellos que no han usado. .Deferred antes, he anotado la fuente para it

¿Cuáles son los posibles usos de estos nuevos métodos? ¿Cómo hacemos para encajarlos en patrones?

Ya he leído la .Deferred y la source , así que sé lo que hace. Mi pregunta es ¿cómo podemos usar estas nuevas funciones en el código de todos los días?

Tengo un example simple de una clase de búfer que llama la solicitud de AJAX en orden. (Siguiente comienzo después de que termine uno anterior).

/* Class: Buffer * methods: append * * Constructor: takes a function which will be the task handler to be called * * .append appends a task to the buffer. Buffer will only call a task when the * previous task has finished */ var Buffer = function(handler) { var tasks = []; // empty resolved deferred object var deferred = $.when(); // handle the next object function handleNextTask() { // if the current deferred task has resolved and there are more tasks if (deferred.isResolved() && tasks.length > 0) { // grab a task var task = tasks.shift(); // set the deferred to be deferred returned from the handler deferred = handler(task); // if its not a deferred object then set it to be an empty deferred object if (!(deferred && deferred.promise)) { deferred = $.when(); } // if we have tasks left then handle the next one when the current one // is done. if (tasks.length > 0) { deferred.done(handleNextTask); } } } // appends a task. this.append = function(task) { // add to the array tasks.push(task); // handle the next task handleNextTask(); }; };

Estoy buscando demostraciones y posibles usos de .Deferred y .Deferred .

También sería ._Deferred ver ejemplos de ._Deferred .

Enlazar a la nueva fuente jQuery.ajax para obtener ejemplos es hacer trampa.

Recompensa: nos muestra qué técnicas están disponibles cuando retiramos si una operación se realiza de forma síncrona o asíncrona.


Acabo de usar Deferido en código real. En el proyecto jQuery Terminal , tengo la función exec que llama a los comandos definidos por el usuario (como si lo estuviera ingresando y presionando Intro), agregué los Aplazados a la API y llamé al exec con arreglos. Me gusta esto:

terminal.exec(''command'').then(function() { terminal.echo(''command finished''); });

o

terminal.exec([''command 1'', ''command 2'', ''command 3'']).then(function() { terminal.echo(''all commands finished''); });

los comandos pueden ejecutar código asíncrono, y exec debe llamar al código de usuario en orden. Mi primer api utiliza un par de llamadas de pausa / reanudación y en la nueva API las llamo automáticas cuando el usuario me lo promete. Así que el código de usuario solo puede usar

return $.get(''/some/url'');

o

var d = new $.Deferred(); setTimeout(function() { d.resolve("Hello Deferred"); // resolve value will be echoed }, 500); return d.promise();

Yo uso código como este:

exec: function(command, silent, deferred) { var d; if ($.isArray(command)) { return $.when.apply($, $.map(command, function(command) { return self.exec(command, silent); })); } // both commands executed here (resume will call Term::exec) if (paused) { // delay command multiple time d = deferred || new $.Deferred(); dalyed_commands.push([command, silent, d]); return d.promise(); } else { // commands may return promise from user code // it will resolve exec promise when user promise // is resolved var ret = commands(command, silent, true, deferred); if (!ret) { if (deferred) { deferred.resolve(self); return deferred.promise(); } else { d = new $.Deferred(); ret = d.promise(); ret.resolve(); } } return ret; } },

dalyed_commands se usa en la función de reanudación que llama a exec nuevamente con todos los dalyed_commands.

y parte de la función de comandos (he eliminado partes no relacionadas)

function commands(command, silent, exec, deferred) { var position = lines.length-1; // Call user interpreter function var result = interpreter.interpreter(command, self); // user code can return a promise if (result != undefined) { // new API - auto pause/resume when using promises self.pause(); return $.when(result).then(function(result) { // don''t echo result if user echo something if (result && position === lines.length-1) { display_object(result); } // resolve promise from exec. This will fire // code if used terminal::exec(''command'').then if (deferred) { deferred.resolve(); } self.resume(); }); } // this is old API // if command call pause - wait until resume if (paused) { self.bind(''resume.command'', function() { // exec with resume/pause in user code if (deferred) { deferred.resolve(); } self.unbind(''resume.command''); }); } else { // this should not happen if (deferred) { deferred.resolve(); } } }


Aquí hay una implementación ligeramente diferente de un caché AJAX como en la respuesta de ehynd .

Como se señaló en la pregunta de seguimiento de fortuneRice, la implementación de ehynd en realidad no impidió varias solicitudes idénticas si las solicitudes se realizaron antes de que una de ellas hubiera regresado. Es decir,

for (var i=0; i<3; i++) { getData("xxx"); }

probablemente resultará en 3 solicitudes AJAX si el resultado de "xxx" no se ha almacenado en caché anteriormente.

Esto se puede resolver almacenando en caché los aplazados de la solicitud en lugar del resultado:

var cache = {}; function getData( val ){ // Return a promise from the cache (if available) // or create a new one (a jqXHR object) and store it in the cache. var promise = cache[val]; if (!promise) { promise = $.ajax(''/foo/'', { data: { value: val }, dataType: ''json'' }); cache[val] = promise; } return promise; } $.when(getData(''foo'')).then(function(resp){ // do something with the response, which may // or may not have been retreived using an // XHR request. });


El mejor caso de uso que se me ocurre es en el almacenamiento en caché de las respuestas AJAX. Aquí hay un ejemplo modificado de la publicación de introducción de Rebecca Murphey sobre el tema :

var cache = {}; function getData( val ){ // return either the cached value or jqXHR object wrapped Promise return $.when( cache[ val ] || $.ajax(''/foo/'', { data: { value: val }, dataType: ''json'', success: function( resp ){ cache[ val ] = resp; } }) ); } getData(''foo'').then(function(resp){ // do something with the response, which may // or may not have been retrieved using an // XHR request. });

Básicamente, si el valor ya se ha solicitado una vez antes, se devuelve inmediatamente del caché. De lo contrario, una solicitud AJAX obtiene los datos y los agrega al caché. El $.when .then / .then no se preocupa por nada de esto; todo lo que debe preocuparle es utilizar la respuesta, que se pasa al controlador .then() en ambos casos. .when maneja una Promesa / Aplazada como Completada, ejecutando inmediatamente cualquier .done() o .then() en la cadena.

Los aplazados son perfectos para cuando la tarea puede o no funcionar de forma asíncrona, y desea abstraer esa condición del código.

Otro ejemplo del mundo real usando $.when helper:

$.when($.getJSON(''/some/data/''), $.get(''template.tpl'')).then(function (data, tmpl) { $(tmpl) // create a jQuery object out of the template .tmpl(data) // compile it .appendTo("#target"); // insert it into the DOM });



La respuesta de ehynds no funcionará, ya que almacena en caché los datos de las respuestas. Debe almacenar en caché el jqXHR, que también es una promesa. Aquí está el código correcto:

var cache = {}; function getData( val ){ // return either the cached value or an // jqXHR object (which contains a promise) return cache[ val ] || $.ajax(''/foo/'', { data: { value: val }, dataType: ''json'', success: function(data, textStatus, jqXHR){ cache[ val ] = jqXHR; } }); } getData(''foo'').then(function(resp){ // do something with the response, which may // or may not have been retreived using an // XHR request. });

La respuesta de Julian D. funcionará correctamente y es una mejor solución.


Otro ejemplo de uso de Deferred s para implementar un caché para cualquier tipo de computación (generalmente algunas tareas de alto rendimiento o de ejecución prolongada):

var ResultsCache = function(computationFunction, cacheKeyGenerator) { this._cache = {}; this._computationFunction = computationFunction; if (cacheKeyGenerator) this._cacheKeyGenerator = cacheKeyGenerator; }; ResultsCache.prototype.compute = function() { // try to retrieve computation from cache var cacheKey = this._cacheKeyGenerator.apply(this, arguments); var promise = this._cache[cacheKey]; // if not yet cached: start computation and store promise in cache if (!promise) { var deferred = $.Deferred(); promise = deferred.promise(); this._cache[cacheKey] = promise; // perform the computation var args = Array.prototype.slice.call(arguments); args.push(deferred.resolve); this._computationFunction.apply(null, args); } return promise; }; // Default cache key generator (works with Booleans, Strings, Numbers and Dates) // You will need to create your own key generator if you work with Arrays etc. ResultsCache.prototype._cacheKeyGenerator = function(args) { return Array.prototype.slice.call(arguments).join("|"); };

Este es un ejemplo del uso de esta clase para realizar algunos cálculos (pesados ​​simulados):

// The addingMachine will add two numbers var addingMachine = new ResultsCache(function(a, b, resultHandler) { console.log("Performing computation: adding " + a + " and " + b); // simulate rather long calculation time by using a 1s timeout setTimeout(function() { var result = a + b; resultHandler(result); }, 1000); }); addingMachine.compute(2, 4).then(function(result) { console.log("result: " + result); }); addingMachine.compute(1, 1).then(function(result) { console.log("result: " + result); }); // cached result will be used addingMachine.compute(2, 4).then(function(result) { console.log("result: " + result); });

La misma memoria caché subyacente podría usarse para almacenar en caché las solicitudes Ajax:

var ajaxCache = new ResultsCache(function(id, resultHandler) { console.log("Performing Ajax request for id ''" + id + "''"); $.getJSON(''http://jsfiddle.net/echo/jsonp/?callback=?'', {value: id}, function(data) { resultHandler(data.value); }); }); ajaxCache.compute("anID").then(function(result) { console.log("result: " + result); }); ajaxCache.compute("anotherID").then(function(result) { console.log("result: " + result); }); // cached result will be used ajaxCache.compute("anID").then(function(result) { console.log("result: " + result); });

Puedes jugar con el código anterior en este jsFiddle .


Otro uso que he estado dando a un buen propósito es obtener datos de múltiples fuentes. En el ejemplo a continuación, obtengo múltiples objetos de esquema JSON independientes utilizados en una aplicación existente para validación entre un cliente y un servidor REST. En este caso, no quiero que la aplicación del lado del navegador comience a cargar datos antes de que tenga todos los esquemas cargados. $ .when.apply (). then () es perfecto para esto. Gracias a Raynos por los punteros sobre el uso de then (fn1, fn2) para monitorear las condiciones de error.

fetch_sources = function (schema_urls) { var fetch_one = function (url) { return $.ajax({ url: url, data: {}, contentType: "application/json; charset=utf-8", dataType: "json", }); } return $.map(schema_urls, fetch_one); } var promises = fetch_sources(data[''schemas'']); $.when.apply(null, promises).then( function () { var schemas = $.map(arguments, function (a) { return a[0] }); start_application(schemas); }, function () { console.log("FAIL", this, arguments); });


Puede usar un objeto diferido para hacer un diseño fluido que funcione bien en los navegadores webkit. Los navegadores Webkit activarán el evento de cambio de tamaño para cada píxel en el que la ventana cambie de tamaño, a diferencia de FF e IE, que activan el evento solo una vez para cada tamaño. Como resultado, no tiene control sobre el orden en que se ejecutarán las funciones vinculadas al evento de cambio de tamaño de la ventana. Algo como esto resuelve el problema:

var resizeQueue = new $.Deferred(); //new is optional but it sure is descriptive resizeQueue.resolve(); function resizeAlgorithm() { //some resize code here } $(window).resize(function() { resizeQueue.done(resizeAlgorithm); });

Esto serializará la ejecución de su código para que se ejecute como usted lo intentó. Tenga cuidado con los escollos al pasar métodos de objetos como devoluciones de llamada a un aplazado. Una vez que dicho método se ejecuta como una devolución de llamada a diferido, la referencia ''this'' se sobrescribirá con referencia al objeto diferido y ya no se referirá al objeto al que pertenece el método.


También puede integrarlo con cualquier biblioteca de terceros que utilice JQuery.

Una de esas bibliotecas es Backbone, que en realidad apoyará a Aplazado en su próxima versión. Lo he hablado también en mi blog


Un diferido puede ser usado en lugar de un mutex. Esto es esencialmente lo mismo que los múltiples escenarios de uso de ajax.

MUTEX

var mutex = 2; setTimeout(function() { callback(); }, 800); setTimeout(function() { callback(); }, 500); function callback() { if (--mutex === 0) { //run code } }

DIFERIDO

function timeout(x) { var dfd = jQuery.Deferred(); setTimeout(function() { dfd.resolve(); }, x); return dfd.promise(); } jQuery.when( timeout(800), timeout(500)).done(function() { // run code });

Cuando utilice un Aplazado solo como exclusión mutua, tenga cuidado con los impactos en el rendimiento (http://jsperf.com/deferred-vs-mutex/2). A pesar de la conveniencia, así como los beneficios adicionales proporcionados por un aplazado, vale la pena, y en el uso real (basado en eventos impulsados ​​por el usuario) el impacto en el rendimiento no debería ser notable.