我希望更好地理解以下示例为什么按预期工作的内部结构:
describe('async await', () => {
it('resolves without return', async () => {
await asyncOperation();
});
});
function asyncOperation() {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 123);
});
}
通常,异步mocha测试必须返回一个promise(或执行完成的回调),但在此示例中没有返回任何内容,但mocha测试仍然有效。这究竟是如何工作的?
答案 0 :(得分:6)
async函数声明定义了一个异步函数,它返回一个AsyncFunction对象。
<强>描述强>
调用异步函数时,会返回Promise 。当异步函数返回一个值时,将使用返回的值解析Promise。当异步函数抛出异常或某个值时,将使用抛出的值拒绝Promise。
这意味着,在您的情况下,会返回Promise
,这就是您的测试有效的原因。
答案 1 :(得分:1)
当您使用async
关键字时,您隐式返回Promise
实际使用的return
函数的Promise
语句中的Promise<void>
(在这种情况下,您不返回任何事情,所以这只是async/await
什么都没有,或await
如果你是TypeScript)。
在内部,使用await
的函数会展开到多个异步延续中,并在每次使用function asyncOperation() {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 123);
});
}
async () => {
await asyncOperation();
}
关键字时进行拆分。当您{4}}的承诺完成时,函数的其余部分将恢复。看看像Babel这样的转发器如何展开你的代码可能是有益的。
此代码:
"use strict";
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
function asyncOperation() {
return new Promise(function (resolve) {
setTimeout(function () {
resolve();
}, 123);
});
}
_asyncToGenerator(regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return asyncOperation();
case 2:
case "end":
return _context.stop();
}
}
}, _callee, undefined);
}));
被转换为简单的ES5:
_asyncToGenerator
那个丑陋的cursor:pointer
调用曾经是你美丽的异步函数。它已经展开为显式延续(you can try为函数添加更多等待点和逻辑,并查看转换后的代码如何更改。)