如何使用非常规方法从NodeJS中的异步函数传递数据?

时间:2013-05-26 06:51:06

标签: javascript node.js asynchronous

我一直在玩jsdom,这是node.js的一个模块。底部的以下代码来自其文档页面。我的问题是如何从异步函数返回一些东西。

我知道这是一个很多问题,可能也是我。我也知道,当涉及到这类问题时,回调是一个好朋友。我的目标是在PHP中找到一个可能像cookie或Session变量一样的解决方法,以便在异步函数之外将这一小部分数据传输到外部作用域。然后,一旦从外部范围设置数据,就应该可以访问它。

我想知道的第一件事是:

  1. 是否已经有办法将数据存储在某个地方,例如存在于外部范围中的cookie或会话,并且在我完成我必须做的事情后可以访问?
  2. 如果我要将数据写入文件,在代码中点 B ,并在 C 点读取,我不会写一个在读取文件之前等待几秒钟的某种超时功能?我在nodejs中使用异步函数的经验有时表明我必须在写入过程完成之前等待几秒钟才能尝试读取它。这也是这种情况吗?如果是的话,如果我保存数据的地方是内存,那么它是不是意味着必须发生?
  3. 如果我要为此目的编写一个c ++插件,那就是一个单独的数据托架,我们可以{<1}}点 B 到内存和save(data)来自记忆的点 C ;这会有用吗?
  4. 老实说,我不喜欢编写临时文件来解决异步函数问题。我一直在寻找一种简单而有效的方法来传递数据,但是我需要像你这样有经验的程序员的一些指导来超越这个问题的不必要的方法。

    如果你能为我提出一些想法,说明哪些可行,哪些可能无效,我会很感激。

    以下是示例代码:

    retrieve(data)

2 个答案:

答案 0 :(得分:7)

您需要清除您的同步体验,认为文件中较低的代码会在以后发生。它不一定在节点中那样做。这是交易。在节点中,您可以像在餐馆一样下订单,而不是像以下那样:

1. Order a salad
2. Wait 11 minutes
3. Eat the salad

你这样做

1. Order a salad
2. Wait for the server to serve you the salad
3. Eat the salad

第一个例子是你的程序中的竞争条件和可怕的错误,这将导致沙拉等待无缘无故地吃掉或尝试吃掉尚未出现的沙拉。

不要想“我想在这里回复一些东西”,认为“这个数据准备就绪”。所以你可以:

function eatSalad() {...}
placeOrder("salad", eatSalad);

其中eatSaladplaceOrder例程的回调,它执行必要的I / O来获取沙拉。请注意,即使eatSalad在文件中较早,它也会按时间顺序发生。你没有返回东西,你用你准备好的数据调用回调。

这是你的异步片段。

// Print all of the news items on hackernews
var jsdom = require("jsdom");
// var result; 
// A) Outer Scope: Since the function is async in done, storing the result here and echoing in point C is pointless.
jsdom.env({
  html: "http://news.ycombinator.com/",
  scripts: ["http://code.jquery.com/jquery.js"],
  done: function (errors, window) {
    var $ = window.$;
    console.log("HN Links");
    $("td.title:not(:last) a").each(function() {
      console.log(" -", $(this).text());
    });
    // B) let's say I want to return something I've scavenged here.
    // result = $("a");
    resultIsReady($("a"));
  }
});

function resultIsReady(element) {
    console.log(element);
}

编辑添加从评论中回答您的问题,节点代码通常不是从返回事物的函数构建的,而是从调用回调函数及其“返回值”的函数构建的。 return关键字仅用于实际返回不执行任何I / O的内存中代码的值。因此,找到内存数组的平均值只能返回它,但是从数据库结果集中找到均值必须调用回调函数。基本范例是从像这样的函数(伪代码DB库)构建你的程序:

function getUser(email, callback) {
    db.users.where({email: email}, function (error, user) {
        if (error) {
            //This return statement is just for early termination
            //of the function. The value returned is discarded
            return callback(error);
        }
        callback(null, user);
    });;
}

这就是你做事的方式。通常这样的函数执行非常有限数量的IO调用(1或2是常见的,然后你开始陷入嵌套地狱并需要重构)。

我亲自编写了许多这样的函数,然后使用async库来描述需要发生的高阶序列。还有很多其他流行的流控制库,有些人喜欢promises模式。然而,目前一些核心节点社区成员似乎主张回调是一种真正的方式,而承诺似乎已经失宠。

答案 1 :(得分:3)

避免在可能阻止执行的任何地方使用同步代码,例如数据库操作,文件IO,网络数据检索,长时间计算等。 在您的示例中,在完成计算以继续执行时使用回调,您还可以查看异步https://npmjs.org/package/async库,这是毛发调用的事实标准:

    function sendData(result) {
        res.json(result);
    }

    var jsdom = require("jsdom");
    // var result;
    // A) Outer Scope: Since the function is async in done, storing the result here 
    // and echoing in point C is pointless.
    jsdom.env({
        html: "http://news.ycombinator.com/",
        scripts: ["http://code.jquery.com/jquery.js"],
        done: function (errors, window) {
            var $ = window.$;
            console.log("HN Links");
            $("td.title:not(:last) a").each(function () {
                console.log(" -", $(this).text());
            });
            // B) let's say I want to return something I've scavenged here.
            var result = $("a");
            sendData(result);
        }
    });