Come posso creare una funzione asincrona in Javascript?

Voglio dire, dai un’occhiata a questo codice :

Link Moving $('#link').click(function () { console.log("Enter"); $('#link').animate({ width: 200 }, 2000, function() { console.log("finished"); }); console.log("Exit"); }); 

come puoi vedere in console, la funzione “animate” è Asincrona e “fork” il stream del codice di blocco del gestore eventi. Infatti :

 $('#link').click(function () { console.log("Enter"); asyncFunct(); console.log("Exit"); }); function asyncFunct() { console.log("finished"); } 

segui il stream del codice di blocco!

Se desidero creare la mia function asyncFunct() { } con questo comportamento, come posso farlo con javascript / jquery? Penso che ci sia una strategia senza usare setTimeout()

Non è ansible creare una funzione asincrona veramente personalizzata. Alla fine dovrai fare leva su una tecnologia fornita in modo nativo, come ad esempio:

  • setInterval
  • setTimeout
  • requestAnimationFrame
  • XMLHttpRequest
  • WebSocket
  • Worker
  • Alcune API HTML5 come l’API file, l’API del database Web
  • Tecnologie che supportano l’ onload
  • … molti altri

In effetti, per l’animazione jQuery usa setInterval .

Puoi usare un timer:

 setTimeout( yourFn, 0 ); 

(dove yourFn è un riferimento alla tua funzione)

o, con Lodash :

 _.defer( yourFn ); 

Defers che richiama la func finché lo stack di chiamate corrente non è stato cancellato. Eventuali argomenti aggiuntivi vengono forniti a func quando viene richiamato.

qui hai una soluzione semplice (altri scrivi a riguardo) http://www.benlesh.com/2012/05/calling-javascript-function.html

E qui hai la soluzione pronta sopra:

 function async(your_function, callback) { setTimeout(function() { your_function(); if (callback) {callback();} }, 0); } 

TEST 1 ( può produrre ‘1 x 2 3’ o ‘1 2 x 3’ o ‘1 2 3 x’ ):

 console.log(1); async(function() {console.log('x')}, null); console.log(2); console.log(3); 

TEST 2 ( emetterà sempre ‘x 1’ ):

 async(function() {console.log('x');}, function() {console.log(1);}); 

Questa funzione viene eseguita con timeout 0: simula un’attività asincrona

Ecco una funzione che accetta un’altra funzione e genera una versione che esegue async.

 var async = function (func) { return function () { var args = arguments; setTimeout(function () { func.apply(this, args); }, 0); }; }; 

È usato come un modo semplice per creare una funzione asincrona:

 var anyncFunction = async(function (callback) { doSomething(); callback(); }); 

Questo è diverso dalla risposta di @ fider perché la funzione stessa ha una propria struttura (non è stata aggiunta la funzione di callback, è già nella funzione) e anche perché crea una nuova funzione che può essere utilizzata.

Questa pagina ti guida attraverso le basi della creazione di una funzione javascript asincrona.

L’esecuzione di chiamate di funzioni asincrone in JavaScript utilizzando argomenti comporta normalmente la costruzione dell’argomento dell’espressione su setTimeout o setInterval manualmente.

Se questo non lo risolve, consulta la documentazione sulla funzione animate .

Edit: ho completamente frainteso la domanda. Nel browser, setTimeout . Se fosse importante che funzionasse in un altro thread, userei Web Worker .

Se si desidera utilizzare i parametri e regolare il numero massimo di funzioni asincrone, è ansible utilizzare un semplice operatore asincrono che ho creato:

 var BackgroundWorker = function(maxTasks) { this.maxTasks = maxTasks || 100; this.runningTasks = 0; this.taskQueue = []; }; /* runs an async task */ BackgroundWorker.prototype.runTask = function(task, delay, params) { var self = this; if(self.runningTasks >= self.maxTasks) { self.taskQueue.push({ task: task, delay: delay, params: params}); } else { self.runningTasks += 1; var runnable = function(params) { try { task(params); } catch(err) { console.log(err); } self.taskCompleted(); } // this approach uses current standards: setTimeout(runnable, delay, params); } } BackgroundWorker.prototype.taskCompleted = function() { this.runningTasks -= 1; // are any tasks waiting in queue? if(this.taskQueue.length > 0) { // it seems so! let's run it x) var taskInfo = this.taskQueue.splice(0, 1)[0]; this.runTask(taskInfo.task, taskInfo.delay, taskInfo.params); } } 

Puoi usarlo in questo modo:

 var myFunction = function() { ... } var myFunctionB = function() { ... } var myParams = { name: "John" }; var bgworker = new BackgroundWorker(); bgworker.runTask(myFunction, 0, myParams); bgworker.runTask(myFunctionB, 0, null); 

In ritardo, ma per mostrare una soluzione semplice usando le promises dopo la loro introduzione in ES6 , gestisce le chiamate asincrone molto più facilmente:

Imposta il codice asincrono in una nuova promise:

 var asyncFunct = new Promise(function(resolve, reject) { $('#link').animate({ width: 200 }, 2000, function() { console.log("finished"); resolve(); }); }); 

Nota per impostare resolve() quando termina la chiamata asincrona.
Quindi aggiungi il codice che vuoi eseguire dopo che la chiamata asincrona termina all’interno di .then() della promise:

 asyncFunct.then((result) => { console.log("Exit"); }); 

Ecco un frammento di esso:

 $('#link').click(function () { console.log("Enter"); var asyncFunct = new Promise(function(resolve, reject) { $('#link').animate({ width: 200 }, 2000, function() { console.log("finished"); resolve(); }); }); asyncFunct.then((result) => { console.log("Exit"); }); }); 
  Link Moving 
 Function.prototype.applyAsync = function(params, cb){ var function_context = this; setTimeout(function(){ var val = function_context.apply(undefined, params); if(cb) cb(val); }, 0); } // usage var double = function(n){return 2*n;}; var display = function(){console.log(arguments); return undefined;}; double.applyAsync([3], display); 

Sebbene non sia fondamentalmente diverso rispetto alle altre soluzioni, penso che la mia soluzione faccia alcune altre cose carine:

  • consente i parametri per le funzioni
  • passa l’output della funzione al callback
  • viene aggiunto a Function.prototype consentendo un modo più carino per chiamarlo

Inoltre, la somiglianza con la funzione integrata Function.prototype.apply mi sembra appropriata.

Accanto all’ottima risposta di @pimvdb, e nel caso tu ti stia chiedendo, async.js non offre nemmeno funzioni veramente asincrone. Ecco una versione (molto) ridotta del metodo principale della libreria:

 function asyncify(func) { // signature: func(array) return function (array, callback) { var result; try { result = func.apply(this, array); } catch (e) { return callback(e); } /* code ommited in case func returns a promise */ callback(null, result); }; } 

Quindi la funzione protegge dagli errori e passa con garbo al callback da gestire, ma il codice è sincrono come qualsiasi altra funzione JS.

Sfortunatamente, JavaScript non fornisce una funzionalità asincrona. Funziona solo in un singolo thread. Ma la maggior parte dei browser moderni fornisce Worker , che sono i secondi script che vengono eseguiti in background e possono restituire un risultato. Quindi, ho raggiunto una soluzione, penso che sia utile per eseguire in modo asincrono una funzione, che crea un worker per ogni chiamata asincrona.

Il codice seguente contiene la funzione async per chiamare in background.

 Function.prototype.async = function(callback) { let blob = new Blob([ "self.addEventListener('message', function(e) { self.postMessage({ result: (" + this + ").apply(null, e.data) }); }, false);" ], { type: "text/javascript" }); let worker = new Worker(window.URL.createObjectURL(blob)); worker.addEventListener("message", function(e) { this(e.data.result); }.bind(callback), false); return function() { this.postMessage(Array.from(arguments)); }.bind(worker); }; 

Questo è un esempio di utilizzo:

 (function(x) { for (let i = 0; i < 999999999; i++) {} return x * 2; }).async(function(result) { alert(result); })(10); 

Questo esegue una funzione che esegue un iter con un numero enorme per prendere tempo come dimostrazione di asincronismo, e quindi ottiene il doppio del numero passato. Il metodo async fornisce una function che chiama la funzione desiderata in background, e in ciò che è fornito come parametro dei callback async il return nel suo parametro univoco. Quindi nella funzione di richiamata alert il risultato.

MDN ha un buon esempio sull’uso di setTimeout preservando “questo”.

Mi piace il seguente:

 function doSomething() { // use 'this' to handle the selected element here } $(".someSelector").each(function() { setTimeout(doSomething.bind(this), 0); });