async / await implícitamente devuelve promise?
He leído que las funciones asincrónicas marcadas por la palabra clave async
implícitamente devuelven una promesa:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
Pero eso no es coherente...suponiendo que doSomethingAsync()
devuelve una promesa, y la palabra clave await devolverá el valor de la promesa, no la promesa itsef, entonces mi función getVal debería devolver ese valor, no una promesa implícita.
Entonces, ¿cuál es exactamente el caso? ¿Las funciones marcadas por la palabra clave async devuelven implícitamente promesas o controlamos lo que ¿volver?
Tal vez si no devolvemos explícitamente algo, 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 inconsistente con las declaraciones de retorno tradicionales. Parece que cuando devuelve explícitamente un valor no promise de una función async
, forzará a envolverlo en una promesa.
No tengo un gran problema con él, pero desafía a los JS normales.
3 answers
El valor de retorno siempre será una promesa. Si no devuelve explícitamente una promesa, el valor que devuelve se envolverá 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 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));
Promete desenvolver automáticamente, por lo que si devuelve una promesa para un valor desde dentro de una función async
, recibirá una promesa para el valor (no una promesa para una promesa para 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 inconsistente con tradicional instrucciones return. Parece que cuando devuelve explícitamente un valor no-promesa de una función asincrónica, forzará envolverlo en un promesa. No tengo un gran problema con él, pero desafía lo normal JS.
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);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-09 21:50:10
Eché un vistazo a la especificación y encontré la siguiente información. La versión corta es que un async function
desugars a un generador que produce Promise
s. Entonces, sí, las funciones asincrónicas devuelven promesas.
De acuerdo con la especificación tc39 , lo siguiente es cierto:
async function <name>?<argumentlist><body>
Desugars 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); });
});
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-09 21:47:19
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 hecho un manejador de base de datos basado en la parte superior de tedioso que programa como este
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 acabo de programarlo como normal síncrono particularmente en
yield connection.execSql
y en yield connection.callProcedure
El db.la función exec es un generador basado en promesas 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);
});
});
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-09 21:34:13