async/await含蓄returns承诺?
async/await implicitly returns promise?
我读到由 async
关键字标记的异步函数隐式 return 一个承诺:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
但这不连贯...假设 doSomethingAsync()
return 是一个承诺,并且 await 关键字将 return 来自承诺的值,而不是承诺本身,那么我的getVal 函数应该return那个值,而不是隐含的承诺。
那么到底是怎么回事呢?由 async 关键字标记的函数是隐式 return 承诺还是我们控制它们 return?
也许如果我们不明确地 return 某些东西,那么他们就隐含地 return 承诺...?
说得更清楚一点,上面和
是有区别的
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
在我的概要中,行为确实与传统的 return 陈述不一致。看起来,当您从 async
函数中显式 return 一个非承诺值时,它会强制将其包装在一个承诺中。
我对它没有什么大问题,但它确实违背了普通的 JS。
return价值永远是一个承诺。如果您没有明确 return 承诺,您 return 的值将自动包装在承诺中。
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));
即使没有return也是一样! (Promise { undefined }
是 returned)
async function increment(num) {}
即使有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));
Promises auto-unwrap,因此如果您在 async
函数中对某个值执行 return promise,您将收到该值的 promise(不是对 promise 的 promise值)。
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));
In my synopsis the behavior is indeed inconsistent with traditional
return statements. It appears that when you explicitly return a
non-promise value from an async function, it will force wrap it in a
promise. I don't have a big problem with it, but it does defy normal
JS.
ES6 的函数 return 与 return
的值不完全相同。这些函数称为生成器。
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
async 没有 return 承诺,await 关键字等待承诺的解决。 async 是一个增强的生成器函数,await 的工作方式有点像 yield
我认为语法(我不是 100% 确定)是
async function* getVal() {...}
ES2016 生成器函数有点像这样。我已经制作了一个基于繁琐的数据库处理程序,你可以像这样编程
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}));
});
注意我是如何像普通同步一样编程的,特别是在
yield connection.execSql
和 yield connection.callProcedure
db.exec 函数是一个相当典型的基于 Promise 的生成器
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);
});
});
}
我查看了规范并找到了以下信息。简短的版本是 async function
脱糖到产生 Promise
s 的生成器。所以,是的,异步函数return promises。
根据tc39 spec,以下是正确的:
async function <name>?<argumentlist><body>
脱糖至:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
其中 spawn
"is a call to the following algorithm":
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); });
});
}
只需在调用函数前添加 await :
var ret = await getVal();
console.log(ret);
你的问题是:如果我创建一个async
函数,它是否应该return一个承诺? 回答:随便你怎么办,Javascript会帮你解决的。
假设 doSomethingAsync
是一个函数,return 是一个 promise。那么
async function getVal(){
return await doSomethingAsync();
}
与
完全一样
async function getVal(){
return doSomethingAsync();
}
您可能在想“WTF,这些怎么可能相同?”,您是对的。 async
将 神奇地 用 Promise 包装一个值 如有必要。
更奇怪的是,doSomethingAsync
有时可以写成return一个承诺,有时NOTreturn一个承诺。这两个功能仍然完全相同,因为 await
也是 magic。它会解包一个 Promise 如有必要 但它不会对不是 Promise 的事物产生影响。
我读到由 async
关键字标记的异步函数隐式 return 一个承诺:
async function getVal(){
return await doSomethingAync();
}
var ret = getVal();
console.log(ret);
但这不连贯...假设 doSomethingAsync()
return 是一个承诺,并且 await 关键字将 return 来自承诺的值,而不是承诺本身,那么我的getVal 函数应该return那个值,而不是隐含的承诺。
那么到底是怎么回事呢?由 async 关键字标记的函数是隐式 return 承诺还是我们控制它们 return?
也许如果我们不明确地 return 某些东西,那么他们就隐含地 return 承诺...?
说得更清楚一点,上面和
是有区别的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
在我的概要中,行为确实与传统的 return 陈述不一致。看起来,当您从 async
函数中显式 return 一个非承诺值时,它会强制将其包装在一个承诺中。
我对它没有什么大问题,但它确实违背了普通的 JS。
return价值永远是一个承诺。如果您没有明确 return 承诺,您 return 的值将自动包装在承诺中。
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));
即使没有return也是一样! (Promise { undefined }
是 returned)
async function increment(num) {}
即使有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));
Promises auto-unwrap,因此如果您在 async
函数中对某个值执行 return promise,您将收到该值的 promise(不是对 promise 的 promise值)。
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));
In my synopsis the behavior is indeed inconsistent with traditional return statements. It appears that when you explicitly return a non-promise value from an async function, it will force wrap it in a promise. I don't have a big problem with it, but it does defy normal JS.
ES6 的函数 return 与 return
的值不完全相同。这些函数称为生成器。
function* foo() {
return 'test';
}
// Logs an object.
console.log(foo());
// Logs 'test'.
console.log(foo().next().value);
async 没有 return 承诺,await 关键字等待承诺的解决。 async 是一个增强的生成器函数,await 的工作方式有点像 yield
我认为语法(我不是 100% 确定)是
async function* getVal() {...}
ES2016 生成器函数有点像这样。我已经制作了一个基于繁琐的数据库处理程序,你可以像这样编程
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}));
});
注意我是如何像普通同步一样编程的,特别是在
yield connection.execSql
和 yield connection.callProcedure
db.exec 函数是一个相当典型的基于 Promise 的生成器
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);
});
});
}
我查看了规范并找到了以下信息。简短的版本是 async function
脱糖到产生 Promise
s 的生成器。所以,是的,异步函数return promises。
根据tc39 spec,以下是正确的:
async function <name>?<argumentlist><body>
脱糖至:
function <name>?<argumentlist>{ return spawn(function*() <body>, this); }
其中 spawn
"is a call to the following algorithm":
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); });
});
}
只需在调用函数前添加 await :
var ret = await getVal();
console.log(ret);
你的问题是:如果我创建一个async
函数,它是否应该return一个承诺? 回答:随便你怎么办,Javascript会帮你解决的。
假设 doSomethingAsync
是一个函数,return 是一个 promise。那么
async function getVal(){
return await doSomethingAsync();
}
与
完全一样async function getVal(){
return doSomethingAsync();
}
您可能在想“WTF,这些怎么可能相同?”,您是对的。 async
将 神奇地 用 Promise 包装一个值 如有必要。
更奇怪的是,doSomethingAsync
有时可以写成return一个承诺,有时NOTreturn一个承诺。这两个功能仍然完全相同,因为 await
也是 magic。它会解包一个 Promise 如有必要 但它不会对不是 Promise 的事物产生影响。