【问题标题】:How does an async mocha test resolve without returning a promise or invoking the done callback异步摩卡测试如何在不返回承诺或调用完成回调的情况下解决
【发布时间】:2017-07-17 07:28:14
【问题描述】:

我很想更好地理解为什么以下示例按预期工作的内部原理:

describe('async await', () => {
    it('resolves without return', async () => {
        await asyncOperation();
    });
});

function asyncOperation() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, 123);
    });
}

通常,异步 mocha 测试必须返回一个 promise(或执行 done 回调),但在此示例中没有返回任何内容,但 mocha 测试仍然有效。这具体是如何工作的?

【问题讨论】:

    标签: javascript promise async-await mocha.js


    【解决方案1】:

    来自async documentation

    async 函数声明定义了一个异步函数,它返回一个 AsyncFunction 对象。

    说明

    当调用异步函数时,它会返回一个 Promise。当 async 函数返回一个值时,Promise 将使用返回的值进行解析。当异步函数抛出异常或某个值时,Promise 将被抛出的值拒绝。

    这意味着在您的情况下,会返回 Promise,这就是您的测试有效的原因。

    【讨论】:

      【解决方案2】:

      当您使用 async 关键字时,您将隐式返回 Promise,无论您在函数的 return 语句中实际使用的任何类型(在这种情况下,您不会返回任何内容,所以这很简单Promise 什么都没有,或者 Promise<void> 如果你喜欢 TypeScript)。

      在内部,使用async/await 的函数会展开为多个异步延续,在每次使用await 关键字时进行拆分。当你是await-ing 的承诺完成时,函数的其余部分将恢复。看看像 Babel 这样的编译器如何展开你的代码可能会很有启发性。

      这段代码:

      function asyncOperation() {
          return new Promise((resolve) => {
              setTimeout(() => {
                  resolve();
              }, 123);
          });
      }
      
      async () => {
          await asyncOperation();
      }
      

      被转译为普通的 ES5:

      "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);
      }));
      

      那个丑陋的_asyncToGenerator 调用曾经是你漂亮的异步函数。它已展开为显式延续(you can try 为函数添加更多等待点和逻辑,并查看转译代码如何变化)。

      【讨论】:

        猜你喜欢
        • 2019-01-22
        • 1970-01-01
        • 2023-04-03
        • 1970-01-01
        • 1970-01-01
        • 2017-05-21
        • 2021-12-26
        • 1970-01-01
        • 2014-03-03
        相关资源
        最近更新 更多