1

我正在尝试将 promise 与 nodejs 一起使用(我正在尝试使用 node-promise 包);但是,没有任何成功。请看下面的代码:

var express = require('express'),
    request = require('request'),
    promise = require('node-promise');

app.get('/promise', function(req, res) {
    var length = -1;

    new promise.Promise(request(
        {uri: "http://www.bing.com"},
        function (error, response, body) {
            if (error && response.statusCode !== 200) {
                console.log("An error occurred when connected to the web site");
                return;
            }

            console.log("I'll return: " + body.length);
            length = body.length;
        }
    )).then(function(result) {
        console.log("This is what I got: " + length);
        console.log("Done!");
    });

    res.end();
});

上述代码的输出I'll return: 35857只是,它不去该then部分。

我将代码更改为:

app.get('/promise', function(req, res) {
    var length = -1;

    promise.when(
        request(
            {uri: "http://www.bing.com"},
            function (error, response, body) {
                if (error && response.statusCode !== 200) {
                    console.log("An error occurred when connected to the web site");
                    return;
                }

                console.log("I'll return: " + body.length);
                length = body.length;
            }
        ),
        function(result) {
            console.log("This is what I got: " + length);
            console.log("Done!");
        },
        function(error) {
            console.log(error);
        }
    );

    res.end();
});

这次的输出是This is what I got: -1……Done!看起来这次没有调用“承诺”。

所以:

  • 需要做什么来修复上面的代码?显然我做得不对:)
  • 当我做承诺时,节点承诺是“要走的路”,还是有更好的方法/包?即更简单,更适合生产。

谢谢。

4

2 回答 2

4

试试jquery-deferred-for-node

我不是专家,但我知道这个库往往受到同时工作在服务器端和客户端的程序员的青睐。

即使你还不知道 jQuery 的 Deferreds,走这条路的好处是:

  • 文档非常好(它包含指向 jQuery 文档的链接),尽管您可能很难找到特定于 Node.js 的示例。

  • 方法是可链接的。

  • jQueryCallbacks也包括在内。

  • 当有一天你需要在客户端做异步的东西时,几乎没有什么需要重新学习的——概念是相同的,语法也几乎是相同的。请参阅上面超链接的 github 页面中的“通信”部分。

编辑

我不是 node.js 的人,所以我在这里猜测,但根据您上面的代码,您可能需要考虑使用 jquery-deferred-for-node 进行以下操作:

var express = require('express'),
    request = require('request'),
    Deferred = require('JQDeferred');

function fetch(uri, goodCodes) {
    goodCodes = (!goodCodes) ? [200] : goodCodes;

    var dfrd = Deferred(); // A Deferred to be resolved/rejected in response to the `request()`.
    request(uri, function(error, response, body) {
        if (!error) {
            var isGood = false;

            // Loop to test response.statusCode against `goodCodes`.
            for (var i = 0; i < goodCodes.length; i++) {
                if (response.statusCode == goodCodes[i]) {
                    isGood = true;
                    break;
                }
            }

            if (isGood) {
                dfrd.resolve(response.statusCode, body);
            } else {
                dfrd.reject(response.statusCode, "An invalid response was received from " + uri);
            }
        } else {
            dfrd.reject(response.statusCode, "An error occurred attempting to connect to " + uri);
        }
    });

    // Make promise derived from dfrd available to "consumer".
    return dfrd.promise();
};

//...

app.get('/promise', function(req, resp) {
    fetch("http://www.bing.com").done(function(statusCode, result) {
        console.log("Done! This is what I got: " + result.length);
    }).fail(function(statusCode, message) {
        console.log("Error (" + statusCode + "): " + message);
    });
    resp.end();
};

在这里,我尝试编写一个通用实用程序来获取资源,以便可以在外部处理异步响应(或错误)。我认为这大致与您试图实现的目标一致。

出于兴趣,console.log() 消息以 node.js 结尾在哪里?

编辑 2

上面,我已经给出Deferred了初始资本,这是构造函数的惯例

使用 jQuery Deferreds,必须有任意数量的方法来连续地 fetch()。下面的方法保持fetch()原样,并引入fetch_()作为其前端。可能有更简单的方法,但这允许fetch()保持通用实用程序,在功能上等同于客户端jQuery.ajax()

function fetch_(uri){
    return function(){
        return fetch(uri, [200]).then(function(statusCode, result){
            console.log("Done! This is what I got: " + result.length);
        },function(statusCode, message){
            console.log("Error (" + statusCode + "): " + message);
        });
    };
}

请注意,函数fetch()返回一个函数。它必须是这样的,因为在哪里fetch()被调用,我们想要一个未执行的函数,而不是(还)该函数的结果。

现在让我们假设一组 uris 可用。这可以是硬编码或动态构建的——无论应用程序需要什么。

var uris = [
    'http://xxx.example.com',
    'http://yyy.example.com',
    'http://zzz.example.com'
];

现在,fetch_()可以调用多种方式:

//v1. To call `resp.end()` when the fetching process starts.
app.get('/promise', function(req, resp) {
    fetch_(uris[0])().then(fetch_(uris[1])).then(fetch_(uris[2]));
    resp.end();
});

//v2. To call `resp.end()` when the fetching process has finished.
app.get('/promise', function(req, resp){
    fetch_(uris[0])().then(fetch_(uris[1])).then(fetch_(uris[2])).always(resp.end);
});

//v3. As v2 but building a `.then()` chain of any (unknown) length.
app.get('/promise', function(req, resp){
    var dfrd = Deferred().resolve();//
    $.each(uris, function(i, uri){
        dfrd = dfrd.then(fetch_(uri));
    });
    dfrd = dfrd.always(resp.end);
});

未经测试

我对v1和v2更有信心。v3 可能工作。

v2 和 v3 都应该给出完全相同的行为,但 v3 可以泛化为任意数量的 uri。

一切都可能需要调试。

于 2012-12-22T10:21:24.913 回答
3

我建议使用 Q:https ://github.com/kriskowal/q 。我相信它被其他框架内部使用(如 jQuery 延迟实现)。

我相信文档是“好的”;语法与其他承诺实现一致......并且它有一个节点适配器。

所以你的延迟风格方法:

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", function (err, res) {
    if (!err) {
        deferred.resolve(res);
    } else {
        deferred.reject(err);
    }
});
return deferred.promise;

可以更简洁地写成:

var deferred = Q.defer();
FS.readFile("foo.txt", "utf-8", deferred.makeNodeResolver());
return deferred.promise;
于 2013-01-19T19:59:14.900 回答