纤维不是新发明
节点纤程可以通过在最低级别以平台相关的方式保存当前执行环境的状态来暂停任何功能的运行(例如windows有纤程概念,没有广泛使用,比线程更轻量级,不先发制人)。
其他库使用语言特性模拟协同程序
所有其他 js 库通过使用回调函数来实现协程延续,将执行状态存储在范围变量中。这意味着您要么拥有回调金字塔、承诺链或 async/await(我将装饰生成器与 async/await 放在同一个桶中)。
纤维也是协同程序的一种可能实现。Fibers 应该很快,并且将它们集成到您的代码中不需要您以不同的代码样式编写或引入新的语法。可以从您自己的代码随意更改的执行上下文(堆栈、寄存器等)。
这不能在纯 JavaScript 中完成,node-fibers 使用本机库来实现这一点!
节点纤程限制您,因此您不会阻塞事件循环
节点纤程的具体概念是:javascript 事件循环在所有纤程之外,因此您的初始代码也可以在没有纤程的情况下运行。如果你有一个光纤参考,你可以通过fiber.run();
. 当你在一个纤程中时,你可以通过调用放弃运行权Fiber.yield();
(有效地暂停当前正在运行的代码),javascript事件循环将继续。所有内置回调(setTimeout
, Promise.then
, 事件处理程序,http 请求回调)都将在 javascript 事件循环中运行,无需光纤。
看这个例子
const Fiber = require("fibers");
function findDataAsync(param, callback) {
setTimeout(() => {
callback(null, "Async returned data");
}, 100);
}
function findData( param ) {
const currentFiber = Fiber.current;
var response = null;
findDataAsync(param, function (err, data) {
response = { err : err, data : data };
currentFiber.run();
});
Fiber.yield();
if (response.err) {
throw response.err;
} else {
return response.data;
}
}
function main() {
console.log("Inside fiber started");
console.log(findData());
console.log("Inside fiber finished");
}
console.log("Outside fiber started");
Fiber(main).run();
console.log("Outside fiber finished");
这应该输出:
Outside fiber started
Inside fiber started
Outside fiber finished
Async returned data
Inside fiber finished
请注意,Outside fiber finished
在调用光纤中的第一个产量后立即记录。
如您所见,我们必须立即启动光纤才能yield
. 如果您尝试在第三方库中使用纤程,则必须确保该库不会通过调用setTimeout
或发出异步 http 请求将您当前的执行上下文“重置”到 javascript 事件循环。