【问题标题】:How to use Q library while converting Node async functions to promises?如何在将 Node 异步函数转换为 Promise 时使用 Q 库?
【发布时间】:2015-03-27 05:44:05
【问题描述】:

如何在下面的代码中使用 Promises?

function async_f1(callback) {
    setTimeout(function() {
        callback("Async function 1...");
    }, 1000);
}

function async_f2(callback) {
    setTimeout(function() {
        callback("Async function 2!...");
    }, 1000);
}

function async_f3(callback) {
    setTimeout(function() {
        callback("Second async function 3!...");
    }, 1000);
}

function doAll() {
    async_f1(function(result1) {
        async_f2(function(result2) {
            async_f3(function(result3) {
                console.log("Final result:", result1 + " " + result2 + " " + result3);
            })
        })
    });

}

doAll();

谢谢

【问题讨论】:

  • 你没有任何异步函数。只需将setTimeout() 替换为Q.delay()
  • 是的,你是对的。我曾尝试在那里模拟一个异步函数,如果我失败了,你能告诉我如何使用正确的异步函数来做到这一点吗?
  • 我使自己的异步函数与 node.js 异步调用样式兼容,回调的第一个参数是错误代码(0 = 无错误),随后的参数是结果,那么你可以很容易使用 Q 或 Bluebird 函数自动生成任何方法的异步版本。如果你不让你的异步函数与调用风格兼容,那就有点麻烦了。

标签: javascript node.js promise q


【解决方案1】:

请参阅documentation

例如:

var promise = Q.nfcall(someAsyncFunction, arg1, ...);

【讨论】:

  • 问题是我已经阅读了很多关于它的内容,但也许是我的愚蠢,我无法实现它。我已经看过文档了。如果您想回答我的问题,请提供详细的解释性答案。谢谢。
  • 你不明白什么?没有具体的例子,我不能给你更多的细节。请参阅文档。
  • 谢谢你的链接,我要去看看,你的博文看起来“很有前途”:) 不过,我已经更新了我的问题,你能直接回答吗?它真的会帮助我实际理解它。感谢您的耐心等待!
  • @scaryguy:Q.nfcall(async_f1).then(function(result) { ... })(或Q.all(...)
【解决方案2】:

这里正在使用 Q.nfcall 使用承诺的 sn-p:

var Q = require('q');


var a = Q.nfcall(function async_f1(callback) {
    setTimeout(function() {
        callback(null, "Async function 1...");
    }, 1000);
});

var b = Q.nfcall(function async_f2(callback) {
    setTimeout(function() {
        callback(null, "Async function 2!...");
    }, 1000);
});

var c = Q.nfcall(function async_f3(callback) {
    setTimeout(function() {
        callback(null, "Second async function 3!...");
    }, 1000);
});

function doAll() {
    Q.all([a, b, c]).then(function(result) {
        console.log(result);
    }).fail(function(err) {
        console.log(err);
    })

}

doAll();

这里是Q.denodeify版本:

var Q = require('q');


var a = function async_f1(callback) {
    setTimeout(function() {
        callback(null, "Async function 1...");
    }, 1000);
};

var b = function async_f2(callback) {
    setTimeout(function() {
        callback(null, "Async function 2!...");
    }, 1000);
};

var c = function async_f3(callback) {
    setTimeout(function() {
        callback(null, "Second async function 3!...");
    }, 1000);
};

var a_promise = Q.denodeify(a);
var b_promise = Q.denodeify(b);
var c_promise = Q.denodeify(c);

function doAll() {
    Q.all([a_promise(), b_promise(), c_promise()]).then(function(result) {
        console.log(result);
    }).fail(function(err) {
        console.log(err);
    })

}

doAll();

我之前的尝试失败了,因为我错过了一个重要的点:

为了Q.nfcall 工作,您的回调必须使用 callback(error, data) 模式。以前我没有添加错误参数,所以我没有收到任何错误,但也没有任何输出。一旦我将它修复为callback(null, "Async function 1"),它就开始工作了。

【讨论】:

  • 但是您的原始代码确实按顺序调用它们(需要 3 秒而不是 1 秒)?!
  • 对不起,Bergi,但我没明白重点?使用 Promise 只需 1 秒,因为它们是并行运行的?
  • 是的,完全正确。但我以为你想复制原始脚本的顺序行为?
  • 不不,我不是那个意思。我帖子中的片段只是一些嵌套/依赖异步函数的示例。
【解决方案3】:

首先,您需要promisify your functions。对于interfacing with nodeback functions,您通常使用Q.denodeify,但您的示例函数总是将它们的结果传回第一个参数。所以我们需要编写自己的函数:

function promisify(fn) {
    return function() {
        var args = Array.prototype.slice.call(arguments), ctx = this;
        return Q.Promise(function(resolve) {
            fn.apply(ctx, args.concat([resolve]);
        });
    };
}

并像使用它一样

var f1 = promisify(async_f1),
    f2 = promisify(async_f2),
    f3 = promisify(async_f3);

有了这些,你就可以使用 Promise 风格编写你的 doAll 函数:

function doAll() {
    return f1().then(function(result1) {
        return f2().then(function(result2) {
            return f3().then(function(result3) {
                return "Final result:", result1 + " " + result2 + " " + result3;
            });
        });
    }).then(function(res) {
        console.log(res);
    });
}
doAll();

如果你觉得这个回调金字塔看起来很奇怪,请查看How do I access previous promise results in a .then() chain?

但由于您的函数实际上并不依赖于其他函数的结果,因此您可以轻松地并行运行它们:

function doAll() {
    return Q.all([f1(), f2(), f3()]).then(function(result) {
        console.log("Final result:", result1 + " " + result2 + " " + result3);
    });
}

【讨论】:

  • 感谢您的回答,Bergi。可能这是我的错,但我真的不确定为什么有人需要做这样的事情?如果您确实需要编写我们自己的 promisify 函数的假设确实存在,那么为什么我的答案中的代码会起作用?我错过了什么吗?
  • @scaryguy:您答案中的代码有效,因为那里的async_f* 函数与问题中的函数不同。责怪OP :-)
  • 所以是的,只有当您必须使用的回调函数不符合节点约定时,才需要编写额外的promisify 函数。幸运的是,这种情况很少见,您通常可以使用给定的Q.denodeify
猜你喜欢
  • 1970-01-01
  • 2015-04-15
  • 2015-10-15
  • 2014-09-01
  • 2015-10-24
  • 1970-01-01
  • 2019-04-01
  • 2013-06-05
  • 1970-01-01
相关资源
最近更新 更多