节点光纤的运行与产量有什么区别

我找不到任何好的文档(或者有关SO的任何问题),这些文档解释了yieldrun确切程度。

我无法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( setTimeoutPromise.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冒泡)。