usar sincronas node funciones example ejemplo cuando callbacks await async asincronia javascript async-await

sincronas - Cómo ejecutar async/await en paralelo en Javascript



cuando usar callbacks (6)

Finalmente, async / await se await pronto en todos los principales navegadores, excepto IE. Así que ahora podemos comenzar a escribir código más legible con async / await pero hay un problema. Mucha gente usa async espera así:

const userResponse = await fetchUserAsync(); const postsResponse = await fetchPostsAsync();

Si bien este código es legible, tiene un problema, ejecuta las funciones en serie, no comenzará a buscar publicaciones hasta que finalice la recuperación del usuario. La solución es simple, necesitamos buscar los recursos en paralelo.

Entonces, lo que quiero hacer es (en pseudo lenguaje):

fn task() { result-1 = doAsync(); result-2 = doAsync(); result-n = doLongAsync(); // handle results together combinedResult = handleResults(result-1, result-2); lastResult = handleLastResult(result-n); }



El pseudocódigo se puede escribir de la siguiente manera:

fn async task() { result-1 = doAsync(); result-2 = doAsync(); result-n = doLongAsync(); try{ // handle results together combinedResult = handleResults(await result-1, await result-2); lastResult = handleLastResult(await result-n); } catch(err){ console.error(err) } }

result-1, result-2, result-n se ejecutará en paralelo. combineResult y lastResult también se ejecutarán en paralelo. Sin embargo, el valor combinado de resultados, es decir, el retorno de la función handleResults, se devolverá una vez que el resultado-1 y el resultado-2 estén disponibles, y el valor lastResult, es decir, handleLastResult, se devolverá una vez que el resultado-n esté disponible.

Espero que esto ayude


Para aquellos que preguntan cómo extender esto a un número determinado de llamadas en tiempo de ejecución, pueden usar 2 bucles. El primero comienza todas las tareas, el segundo espera a que todo termine

console.clear(); function wait(ms, data) { return new Promise( resolve => setTimeout(resolve.bind(this, data), ms) ); } /** * While here we call the functions first, * then wait for the result later, so * this will finish in 500ms. */ async function runTasks(timings) { let tasks = []; for (let i in timings) { tasks.push(wait(timings[i], `Result of task ${i}`)); } /* Want fast fail? use Promise.All */ //return Promise.All(tasks); let results = []; for (let task of tasks) { results.push(await task); } return results; } async function taskRunner(fn, arg, label) { const startTime = performance.now(); console.log(`Task ${label} starting...`); let result = await fn(arg); console.log(`Task ${label} finished in ${ Number.parseInt(performance.now() - startTime) } miliseconds with,`, result); } void taskRunner(runTasks, [50,100,200,60,500], ''Task List'');


Puedes escribir algo como esto:

const responses = await Promise.all([ fetchUserAsync(), fetchPostsAsync(), ]); const userResponse = responses[0]; const postsResponse = responses[1];

Esto es fácil ¿verdad? Pero hay una trampa. Promise.all tiene un comportamiento a prueba de fallas, lo que significa que lo rechazará tan pronto como una de las promesas rechazadas. Probablemente desee una solución más robusta donde nos encarguemos de manejar los rechazos de cualquiera de las recuperaciones. Afortunadamente hay una solución, se puede lograr simplemente con async / Promise.all sin la necesidad de usar Promise.all . Un ejemplo de trabajo:

console.clear(); function wait(ms, data) { return new Promise( resolve => setTimeout(resolve.bind(this, data), ms) ); } /** * This will run in series, because * we call a function and immediately wait for it''s result, * so this will finish in 1s. */ async function series() { return { result1: await wait(500, ''seriesTask1''), result2: await wait(500, ''seriesTask2''), } } /** * While here we call the functions first, * then wait for the result later, so * this will finish in 500ms. */ async function parallel() { const task1 = wait(500, ''parallelTask1''); const task2 = wait(500, ''parallelTask2''); return { result1: await task1, result2: await task2, } } async function taskRunner(fn, label) { const startTime = performance.now(); console.log(`Task ${label} starting...`); let result = await fn(); console.log(`Task ${label} finished in ${ Number.parseInt(performance.now() - startTime) } miliseconds with,`, result); } void taskRunner(series, ''series''); void taskRunner(parallel, ''parallel''); /* * The result will be: * Task series starting... * Task parallel starting... * Task parallel finished in 500 milliseconds with, { "result1": "parallelTask1", "result2": "parallelTask2" } * Task series finished in 1001 milliseconds with, { "result1": "seriesTask1", "result2": "seriesTask2" } */

Nota: Necesitará un navegador que tenga async / await supported para ejecutar este fragmento (o nodejs v7 y superior)

De esta manera, puede usar simplemente try / catch para manejar sus errores y devolver resultados parciales dentro de la función parallel .


Si está de acuerdo con el comportamiento a prueba de fallas de Promise.all y la sintaxis de asignación de desestructuración:

const [userResponse, postsResponse] = await Promise.all([ fetchUserAsync(), fetchPostsAsync(), ]);


Primero, ¿es su código un código de bloqueo?

En caso afirmativo, recuerde que javascript es un solo subproceso, por lo que no puede ejecutar dos códigos síncronos, por ejemplo, dos bucles (durante o mientras) al mismo tiempo.

Pero, es posible lograr que usando Web Workers , logré ejecutar funciones en trabajadores web genéricos y sin usar archivos js separados.

setInterval(()=>{console.log("non blocked " + Math.random())}, 900) console.log("start blocking code in parallel in web Worker") console.time("blocked") genericWorker(window, ["blockCpu", function (block){ block(10000) //This blockCpu function is defined below return "/n/nbla bla/n" //This is catched in the resolved promise }]).then(function (result){ console.timeEnd("blocked") console.log("End of blocking code", result) }) .catch(function(error) { console.log(error) }) /* A Web Worker that does not use a File, it create that from a Blob @cb_context, The context where the callback functions arguments are, ex: window @cb, ["fn_name1", "fn_name2", function (fn1, fn2) {}] The callback will be executed, and you can pass other functions to that cb */ function genericWorker(cb_context, cb) { return new Promise(function (resolve, reject) { if (!cb || !Array.isArray(cb)) return reject("Invalid data") var callback = cb.pop() var functions = cb if (typeof callback != "function" || functions.some((fn)=>{return typeof cb_context[fn] != "function"})) return reject(`The callback or some of the parameters: (${functions.toString()}) are not functions`) if (functions.length>0 && !cb_context) return reject("context is undefined") callback = fn_string(callback) //Callback to be executed functions = functions.map((fn_name)=> { return fn_string( cb_context[fn_name] ) }) var worker_file = window.URL.createObjectURL( new Blob(["self.addEventListener(''message'', function(e) { var bb = {}; var args = []; for (fn of e.data.functions) { bb[fn.name] = new Function(fn.args, fn.body); args.push(fn.name)}; var callback = new Function( e.data.callback.args, e.data.callback.body); args = args.map(function(fn_name) { return bb[fn_name] }); var result = callback.apply(null, args) ;self.postMessage( result );}, false)"]) ) var worker = new Worker(worker_file) worker.postMessage({ callback: callback, functions: functions }) worker.addEventListener(''error'', function(error){ return reject(error.message) }) worker.addEventListener(''message'', function(e) { resolve(e.data), worker.terminate() }, false) //From function to string, with its name, arguments and its body function fn_string (fn) { var name = fn.name, fn = fn.toString() return { name: name, args: fn.substring(fn.indexOf("(") + 1, fn.indexOf(")")), body: fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")) } } }) } //random blocking function function blockCpu(ms) { var now = new Date().getTime(), result = 0 while(true) { result += Math.random() * Math.random(); if (new Date().getTime() > now +ms) return; } }