node-fibers

时间:2016-09-26 12:43:33

标签: javascript node.js yield node-fibers

我无法找到任何有关yieldrun如何运作的良好文档(或任何有关SO的问题)。

我无法找到异步方法如何使用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架构类获得的对象(不确定它是否相关)。

提前致谢。

2 个答案:

答案 0 :(得分:1)

纤维不是新发明

节点光纤可以通过在最低级别以平台相关的方式保存当前执行环境的状态来暂停任何功能的运行(例如,窗口具有光纤概念,没有广泛使用,比a更轻量级线程,而不是先发制人的。)

其他库使用语言功能模拟协同例程

所有其他js库通过使用回调函数实现协同例程继续,将执行状态存储在作用域变量中。这意味着您要么具有回调金字塔,承诺链,要么async / await(我将装饰的生成器放在与async / await相同的桶中)。

光纤也是协同例程的可能实现。光纤应该很快,并且将它们集成到代码中不需要您使用不同的代码类型或引入新语法。执行上下文(堆栈,寄存器等等),可以从您自己的代码中随意更改。

  

这不能在纯JavaScript中完成,node-fiber使用本机库来实现这一点!

节点光纤会限制您,因此您不会阻止事件循环

特定于节点光纤的概念是:javascript事件循环在所有光纤之外,因此您的初始代码也在没有光纤的情况下运行。如果您有光纤参考,则可以通过setTimeout传递权限。当你在光纤内时,你可以通过调用Promise.then放弃运行的权利(有效地暂停当前运行的代码),并且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 ,事件处理程序,http请求回调都将在javascript事件循环中运行,没有光纤。

参见此示例

Outside fiber finished

这应输出:

yield

请注意,在调用光纤中的第一个产量后立即记录setTimeout

如您所见,我们必须立即启动光纤才能 <Grid MouseDown="Border_MouseDown"> <Rectangle Width="100" Height="100" Fill="Green" /> <Ellipse Width="100" Height="100" Fill="Orange" /> </Grid> 。如果您尝试在第三方库中使用光纤,则必须确保库不会重置&#34;重置&#34;通过调用 private void Border_MouseDown(object sender, MouseButtonEventArgs e) { MessageBox.Show("hit it"); } 或发出异步http请求,将当前执行上下文发送到javascript事件循环。

答案 1 :(得分:1)

将您的功能更改为:

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侦听器或其他)中创建光纤。典型代码:

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

简而言之,当调用异步函数(上面的第一个模式)时,您将在低级别调用Fiber.yield,并且您将在顶级侦听器中创建光纤(上面的第二个模式)。中间的所有代码都可以以同步方式编写。

注意:使用这些代码模式,您无需在每个函数中捕获/测试错误。相反,您可以使用经典的结构化异常处理(让异常冒泡)。