Si te das cuenta
setTimeout ya devuelve un valor. Es el identificador del timer. La realidad es que no hay forma de regresar un valor en una función que se ejecuta después. Lo más cercano a esto es:
await.
function miFuncion(){
//han pasado 3000 msecs desde que la función setTimeout se llamo
//miFuncion hace algo importante aquí y lo guarda en una variable
let miValorImportante = 'muyimportante';
//puedo trabajar con el valor importante de aquí en adelante.
}
setTimeout(miFuncion, 3000);
Para que entiendas mejor, el runtime de JS lo va a procesar así:
1. El runtime ve la declaración de la función, evalua, hace el hoisting, etc, etc.
2. Se ejecuta la función
setTimeout y le dice al runtime: "En 3 segundos corre la función
miFuncion".
3. Pasan 3 segundos y el runtime corre la función
miFuncion4. La función genera el valor que es importante para seguir el script.
Es imposible que
setTimeout regrese un valor que se calcula después.
Si tu quieres trabajar con ese valor, la única forma es trabajarlo desde ese punto, tal y como lo comente en el script. Por ejemplo, puedes crear otra función fuera y llamarla desde la función agendada por setTimeout:
function procesaValorImportante(importante){
//sigo procesando el valor muy importante
}
function miFuncion(){
//han pasado 3000 msecs desde que la función setTimeout se llamo
//miFuncion hace algo importante aquí y lo guarda en una variable
let miValorImportante = 'muyimportante';
//puedo trabajar con el valor importante de aquí en adelante.
procesaValorImportante(miValorImportante);
}
setTimeout(miFuncion, 3000);
Y así sigues el flujo de tu script, dentro de la función. Se vuelve un poco complicado manejar el flujo de está manera porque lo tienes que continuar desde la función.
Para eso se inventaron las promesas. Una promesa es simplemente un objeto que maneja un valor eventual. No todas las APIs asincronas manejan promesas, para eso puedes usar el constructor de las promesas:
let timeoutP = function(ms){
return new Promise(function(f, r){ setTimeout(f, ms); });
};
Y para usarlo es muy sencillo:
let miValorImportante = timeoutP(3000).then(function(){ /* han pasado 3000 msecs desde entonces */ return 'muyimportante' });
importanteP.then(function(importante){ importante == 'muyImportante' });
Y finalmente, como ya trabajamos con promesas podemos usar async/await (nada más considera que quizás no todos los navegadores soportan este syntax).
async function miFuncion(){
await timeoutP(3000);
//3000 msecs han pasado
let miValorImportante = 'muyimportante';
};
miFuncion();