节点光纤的运行与产量有什么区别
我找不到任何好的文档(或者有关SO的任何问题),这些文档解释了yield
和run
确切程度。
我无法findasynchronous方法将如何使用Fibers/futures
来返回值。
例如(代码不是语法正确的),我怎样才能让这个函数同步返回response
function findData( param ) { var fiber = Fiber( function(){ var currentFiber = Fiber.current; Model.findOne({ "param" : param}, function (err, data) { response = { err : err, data : data }; }); }); return fiber; }
就像是
var value = findData("1");
这个Model
是我从Mongoose
模式类获得的一个对象(不知道它是否相关)。
提前致谢。
纤维不是新发明
节点光纤使得可以通过以最低级别以平台相关方式保存当前执行环境的状态来暂停任何function的运行(例如,windows具有纤维概念,没有被广泛使用,比线程更轻量级,而不是抢先)。
其他库模拟使用语言function的协同例程
所有其他js库通过使用callback函数来实现协同例程的继续,将执行状态存储在作用域variables中。 这意味着你有callback金字塔,承诺链或asynchronous/等待(我把装饰的发电机放在同一个桶async / await)。
纤维也是协同程序的一个可能的实现。 光纤应该很快,并且将它们集成到代码中不需要用不同的代码风格来编写代码,也不需要引入新的语法。 执行上下文(堆栈,寄存器等),可以根据自己的代码随意更改。
这不能在纯JavaScript中完成,节点光纤使用本地库来实现这一点!
节点光纤限制你,所以你不阻止事件循环
节点光纤特定的概念是:javascript事件循环在所有光纤之外,因此您的初始代码在没有光纤的情况下运行。 如果你有一个光纤引用,你可以通过fiber.run();
传递给它的fiber.run();
。 当你在光纤中时,可以通过调用Fiber.yield();
来放弃运行的权利Fiber.yield();
(有效地挂起当前正在运行的代码),JavaScript事件循环将继续。 所有内置callback( setTimeout
, Promise.then
,事件处理程序,http请求callback)都将在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
的第一个产量被调用之后, Outside fiber finished
会立即被logging下来。
正如你所看到的,我们必须立即开始一种纤维才能yield
。 如果您尝试在第三方库中使用光纤,则必须通过调用setTimeout
或发出asynchronoushttp请求来确保库不会将当前的执行上下文“重置”到javascript事件循环中。
改变你的function:
function findData(param) { var currentFiber = Fiber.current; Model.findOne({ "param" : param }, function(err, data) { if (err) fiber.throwInto(err); else fiber.run(data); }); return Fiber.yield(); }
那么你可以写:
function doSomething() { var param = ...; var data = findData(param); processData(data); } function doLotsOfThings() { ...; doSomething(); doSomethingElse(); }
等等,等等…你可以写所有的代码,就好像Model.findOne
是同步的。
唯一的问题是你不能直接从节点的事件循环中调用这些函数。 你必须在光纤内调用它们。 通常,您将在HTTP侦听器(或TCP侦听器或其他)中创build光纤。 典型代码:
http.createServer(function(request, response) { // you cannot call doLotsOfThings() here Fiber(function() { // but you can call it here try { doLotsOfThings(); } // and this the right place to catch exceptions too! catch (ex) { handleException(ex); } }).run(); }).listen(8124);
简而言之,在调用asynchronous函数(上面的第一个模式)时,您将在低级调用Fiber.yield
,并且将在顶级侦听器(上面的第二个模式)中创build光纤。 它们之间的所有代码都可以同步编写。
注意:使用这些代码模式,您不需要在每个函数中捕获/testing错误。 相反,你可以使用经典的结构化exception处理(让exception冒泡)。
- 承诺解决子stream标准输出和拒绝子stream标准错误
- 节点child_process.spawn多个命令
- Nodejs总是不能完全捕获subprocess的stdout数据,除非subprocessfllush(stdout)
- 错误:使用非root用户使用Node.js child_process时,在errnoException(child_process.j2:980:11)处产生ENOENT
- 如何检测节点产生的进程是否仍在运行?
- 如果脚本被杀死,node.js产生的进程将继续存在
- 如何在请求中使用child_process spawn的结果(获取ENOENT)
- 使用生成器函数next()作为node.js中的callback函数
- child_process在node.js安全/转义中产生