「提问」Nodejs中babel转译的async/await,执行了一个while(true) {},为啥不会卡住

发布于 1周前 作者 vueper 来自 nodejs/Nestjs

「提问」Nodejs中babel转译的async/await,执行了一个while(true) {},为啥不会卡住

最近对async/await的实现产生了兴趣,看了下babel的转译,调用了regeneratorRuntime的几个函数。

打开源码看了一下午,有很多东西不是很理解。

while (1) {
    switch (_context.prev = _context.next) {
      case 0:
        _context.next = 2;
        return setTimeout(function (v) {
          return console.log(v);
        }, 1000);
  case 2:
  case "end":
    return _context.stop();
}

}

以上代码我目前的理解是执行了个状态监听器,await后的函数执行完毕后会改变_context.next,然后结束这个状态机。

但在 console 中,执行while(true){}页面几乎是秒卡的。

求指教!

以上运行环境为 chrome console 。

async function log (v) {
  await setTimeout(v => console.log(v), 1000)
}

babel =>

"use strict";

var log = function () { var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(v) { return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return setTimeout(function (v) { return console.log(v); }, 1000);

      case 2:
      case "end":
        return _context.stop();
    }
  }
}, _callee, this);

}));

return function log(_x) { return _ref.apply(this, arguments); }; }();

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = genkey; 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”); }); }; }


4 回复

因为有 return ,所以循环只会跑一次……而且 setTimeout() 返回的并不是一个 Promise ,用 await 怪怪的吧。

while (1) 其实是给 loop 里有 await 的用的,比如 for (let i = 10; i–; ) await Promise.resolve();

如果可以直接 goto 到某个 label 的话,就不需要这个 while (1) 了。


我也没研究过 Babel transpile 出来的代码,好像只要 await 在控制流程语句或者 try…catch block 里就没法在 switch 里一路 fallthrough 下去,需要跳转到隔开的某个状态里。


async 内部 return 的好像就是一个 promise:

function _asyncToGenerator(fn) {
return function() {
var gen = fn.apply(this, arguments);
return new Promise(function(resolve, reject) {…
});
};
}

var log = function () {
var _ref = _asyncToGenerator(…);

return function log(_x) {
return _ref.apply(this, arguments);
};
}();

之前没有注意到 while 里面那个 return ,下一步往哪里挖有了许多头绪,谢谢指教!

在Node.js中,使用Babel转译async/await语法时,本质上是通过将async函数转换为返回Promise对象的函数,并将await表达式转换为Promise的.then()调用,从而实现对异步操作的支持。然而,当你在async函数中使用while(true) {}这样的无限循环时,实际上是在同步地阻塞JavaScript的事件循环。

以下是一个示例代码,展示了这种情况:

const babel = require('@babel/core');

const code = `
async function test() {
  while(true) {}
  console.log('This will never run');
}

test();
`;

const { code: transpiledCode } = babel.transformSync(code, {
  presets: ['@babel/preset-env']
});

console.log(transpiledCode);
// 运行transpiledCode,Node.js进程将会被阻塞,因为while(true) {}是同步阻塞的
// 在实际运行环境中,下面的代码不会执行到
// console.log('After test');

在Node.js中,尽管Babel处理了async/await的语法糖,使其看起来像是异步操作,但while(true) {}这样的同步阻塞代码依然会阻塞事件循环,导致Node.js进程无法处理其他事件或执行其他代码。因此,你的程序会“卡住”,不会继续执行后面的代码或响应其他事件。

简而言之,Babel的转译不会改变while(true) {}同步阻塞的本质。

回到顶部