【问题标题】:'async'/'await' in Node.js is not working in Node.js v8.1.0Node.js 中的“异步”/“等待”在 Node.js v8.1.0 中不起作用
【发布时间】:2017-12-21 15:16:16
【问题描述】:

我正在尝试刷新 Redis 缓存数据库并在响应中返回状态。但在缓存被清除之前,它会返回响应。

在下面的代码中,console.log() 调用将始终打印 undefined,因为不等待 flushRedisDB。

我的 Node.js 版本是 v8.1.0

文件 myfile.js

async function flushRedisapi(request, response)
{
    try {
        var value = await redisModules.flushRedisDB();
        console.log("the value is: " + value);
        if(value)
            response.status(200).send({status : 'Redis Cache Cleared'});
        else
            response.status(400).send({status : "Redis Cache could not be flushed"});

    } catch (error) {
        response.status(400).send({status : "Redis Cache could not be flushed"});
    }
}

文件 redismodule.js

var redisClient;        // Global (avoids duplicate connections)

module.exports =
{
    openRedisConnection : function()
    {
        if (redisClient == null)
        {
            redisClient = require("redis").createClient(6379, 'localhost');
            redisClient.selected_db = 1;
        }
    },
    isRedisConnectionOpened : function()
    {
        if (redisClient && redisClient.connected == true)
        {
            return true;
        }
        else
        {
            if(redisClient)
                redisClient.end();  // End and open once more

            module.exports.openRedisConnection();

            return true;
        }
    },
    flushRedisDB: async function()
    {
        if(!module.exports.isRedisConnectionOpened())
            return false;

        await redisClient.flushall(function (err, result)
        {
            return (result == 'OK') ? true : false;
        });
    }
};

我该如何解决这个问题?

【问题讨论】:

  • 您不能将await 与节点样式回调一起使用。它只适用于承诺。
  • 你能帮我把flushRedisDB函数转换成使用promises的概念吗?
  • @YuryTarabanko await redisClient.flushall 应该等待吧?
  • 没有那么简单,除非它返回一个承诺:)。检查我的答案。

标签: node.js asynchronous async-await


【解决方案1】:

Async/await 仅适用于 Promise(如评论中所述)。因此,只需将您的回调包装到 Promise 中即可。

function cbToPromise(asyncFunc, ...params) {
    return new Promise((resolve, reject) => {
        asyncFunc(...params, (err, result) => {
            if (err) reject(err);
            else resolve(result);
        });
    });
};

try {
    const result = await cbToPromise(redisClient.flushall);
    return result == 'OK';
}
catch(err) {
    console.error(err);
} 

附录:

只有当回调的签名是function(err, result)时它才会起作用。根据另一个答案,情况并非如此(没有错误作为第一个参数传递),因为它永远不会失败。所以在这种情况下,只需去掉 err 参数、reject 和 try/catch 处理程序。

为方便起见,我将我的答案放在此处,因为它很可能会帮助您解决其他 Redis 相关方法的问题。

【讨论】:

  • 请注意,在某些情况下,您可能必须将函数绑定到它所附加的对象,如果它依赖于其上下文,即。 cbToPromise(redisClient.flushall.bind(redisClient));
【解决方案2】:

async/await 仅适用于 Promise,因此此代码不会等待回调

await redisClient.flushall(function (err, result)
{
    return (result == 'OK') ? true : false;
});

您需要承诺flushall 方法。根据the documentation,它总是成功。

const flushall = () => new Promise(resolve => redisClient.flushall(resolve))

const flushed = await flusall()

顺便说一句。在 Node.js 版本 8 及更高版本中内置了 util.promisify 函数,允许 Promisify Node.js 风格的 CPS 函数。但它不会像这样处理总是成功的功能,所以你需要提供一个自定义的实现来让它工作。关于util.promisify

【讨论】:

  • 可能在另一种情况下,如果同时出现错误和成功怎么办?
  • @Sharath 如果我理解正确,那么util.promisify 应该可以工作。
【解决方案3】:

Bluebird 提供了自己的承诺,promisify all Redis functions 允许您将Async 附加到您希望使用的任何 Redis 命令。在您的情况下,它看起来像 flushallAsync

const redis = require('redis');
const bluebird = require('bluebird');

bluebird.promisifyAll(redis.RedisClient.prototype);
bluebird.promisifyAll(redis.Multi.prototype);

一旦承诺,您就可以随意使用 async / await 了。 ?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 2018-06-08
    • 2017-02-19
    • 2021-03-26
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    相关资源
    最近更新 更多