
alexander molinos
Leí que las funciones asíncronas marcadas por el async
palabra clave devuelve implícitamente una promesa:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
pero eso no es coherente… suponiendo doSomethingAsync()
devuelve una promesa, y la palabra clave await devolverá el valor de la promesa, no la promesa en sí, luego mi función getVal deberían devolver ese valor, no una promesa implícita.
Entonces, ¿cuál es exactamente el caso? ¿Las funciones marcadas por la palabra clave asíncrona implícitamente devuelven promesas o controlamos lo que devuelven?
¿Quizás si no devolvemos algo explícitamente, entonces implícitamente devuelven una promesa…?
Para ser más claro, hay una diferencia entre lo anterior y
function doSomethingAync(charlie) {
return new Promise(function (resolve) {
setTimeout(function () {
resolve(charlie || 'yikes');
}, 100);
})
}
async function getVal(){
var val = await doSomethingAync(); // val is not a promise
console.log(val); // logs 'yikes' or whatever
return val; // but this returns a promise
}
var ret = getVal();
console.log(ret); //logs a promise
En mi sinopsis, el comportamiento es de hecho inconsistente con las declaraciones de devolución tradicionales. Parece que cuando devuelve explícitamente un valor no prometido de un async
función, obligará a envolverlo en una promesa. No tengo un gran problema con eso, pero desafía a JS normal.

nathan pared
El valor de retorno siempre será una promesa. Si no devuelve explícitamente una promesa, el valor que devuelva se incluirá automáticamente en una promesa.
async function increment(num) {
return num + 1;
}
// Even though you returned a number, the value is
// automatically wrapped in a promise, so we call
// `then` on it to access the returned value.
//
// Logs: 4
increment(3).then(num => console.log(num));
¡Lo mismo aunque no haya retorno! (Promise { undefined }
es regresado)
async function increment(num) {}
Lo mismo incluso si hay un await
.
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function incrementTwice(num) {
const numPlus1 = await defer(() => num + 1);
return numPlus1 + 1;
}
// Logs: 5
incrementTwice(3).then(num => console.log(num));
Las promesas se desenvuelven automáticamente, por lo que si devuelve una promesa por un valor dentro de un async
función, recibirá una promesa por el valor (no una promesa por una promesa por el valor).
function defer(callback) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(callback());
}, 1000);
});
}
async function increment(num) {
// It doesn't matter whether you put an `await` here.
return defer(() => num + 1);
}
// Logs: 4
increment(3).then(num => console.log(num));
En mi sinopsis, el comportamiento es de hecho inconsistente con las declaraciones de devolución tradicionales. Parece que cuando devuelve explícitamente un valor no prometido de una función asíncrona, lo forzará a envolverlo en una promesa. No tengo un gran problema con eso, pero desafía a JS normal.
ES6 tiene funciones que no devuelven exactamente el mismo valor que el return
. Estas funciones se llaman generadores.
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
Eché un vistazo a las especificaciones y encontré la siguiente información. La versión corta es que un async function
desazúcares a un generador que produce Promise
s. Entonces, sí, las funciones asíncronas devuelven promesas.
De acuerdo con la especificaciones tc39lo siguiente es cierto:
async function <name>?<argumentlist><body>
Desazúcares a:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
Donde spawn
“es una llamada al siguiente algoritmo”:
function spawn(genF, self) {
return new Promise(function(resolve, reject) {
var gen = genF.call(self);
function step(nextF) {
var next;
try {
next = nextF();
} catch(e) {
// finished with failure, reject the promise
reject(e);
return;
}
if(next.done) {
// finished with success, resolve the promise
resolve(next.value);
return;
}
// not finished, chain off the yielded promise and `step` again
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
tu pregunta es: Si creo un async
función debe devolver una promesa o no? Responder: solo haz lo que quieras y Javascript lo arreglará por ti.
Suponer doSomethingAsync
es una función que devuelve una promesa. Luego
async function getVal(){
return await doSomethingAsync();
}
es exactamente igual que
async function getVal(){
return doSomethingAsync();
}
Probablemente estés pensando “WTF, ¿cómo pueden ser iguales?” y tienes razón. El async
voluntad por arte de magia envolver un valor con una promesa si necesario.
Aún más extraño, el doSomethingAsync
se puede escribir a a veces devolver una promesa y a veces NO devolver una promesa. Aún así, ambas funciones son exactamente iguales, porque el await
es también magia. Desenvolverá una Promesa si necesario pero no tendrá efecto sobre las cosas que no son Promesas.
Simplemente agregue esperar antes de su función cuando la llame:
var ret = await getVal();
console.log(ret);
async no devuelve la promesa, la palabra clave await espera la resolución de la promesa. async es una función de generador mejorada y await funciona un poco como yield
Creo que la sintaxis (no estoy 100% seguro) es
async function* getVal() {...}
Las funciones del generador ES2016 funcionan un poco así. He creado un controlador de base de datos basado en lo tedioso que programa de esta manera
db.exec(function*(connection) {
if (params.passwd1 === '') {
let sql="UPDATE People SET UserName = @username WHERE ClinicianID = @clinicianid";
let request = connection.request(sql);
request.addParameter('username',db.TYPES.VarChar,params.username);
request.addParameter('clinicianid',db.TYPES.Int,uid);
yield connection.execSql();
} else {
if (!/^\S{4,}$/.test(params.passwd1)) {
response.end(JSON.stringify(
{status: false, passwd1: false,passwd2: true}
));
return;
}
let request = connection.request('SetPassword');
request.addParameter('userID',db.TYPES.Int,uid);
request.addParameter('username',db.TYPES.NVarChar,params.username);
request.addParameter('password',db.TYPES.VarChar,params.passwd1);
yield connection.callProcedure();
}
response.end(JSON.stringify({status: true}));
}).catch(err => {
logger('database',err.message);
response.end(JSON.stringify({status: false,passwd1: false,passwd2: false}));
});
Observe cómo lo programo como sincrónico normal, particularmente en
yield connection.execSql
y en yield connection.callProcedure
La función db.exec es un generador basado en Promise bastante típico
exec(generator) {
var self = this;
var it;
return new Promise((accept,reject) => {
var myConnection;
var onResult = lastPromiseResult => {
var obj = it.next(lastPromiseResult);
if (!obj.done) {
obj.value.then(onResult,reject);
} else {
if (myConnection) {
myConnection.release();
}
accept(obj.value);
}
};
self._connection().then(connection => {
myConnection = connection;
it = generator(connection); //This passes it into the generator
onResult(); //starts the generator
}).catch(error => {
reject(error);
});
});
}
Que hace
console.log
¿show?– Barmar
9 de febrero de 2016 a las 21:24
es el valor pasado por la función de resolución de la promesa, no la promesa en sí
– Alejandro Mills
09/02/2016 a las 21:25
Quizás esperar desenvuelve el resultado de la promesa.
– Hamlet Hakobian
09/02/2016 a las 21:30
Las promesas de JavaScript intentan imitar el comportamiento de espera asíncrona de c#. Sin embargo, históricamente había mucha estructura para respaldar eso con C#, y ninguna en JavaScript. Entonces, si bien en muchos casos de uso puede parecer muy similar, es un nombre algo inapropiado.
– Travis J.
9 de febrero de 2016 a las 21:58
sí, eso es correcto, solo un poco confuso, ya que está implícito … es decir, incluso si no hay una declaración de devolución, todavía devuelve una promesa … ¿visto?
– Alejandro Mills
04/08/2018 a las 23:45