【问题标题】:Waiting to get a response from a function before using it in a line below?在下面一行中使用它之前等待从函数中获得响应?
【发布时间】:2022-02-17 16:33:11
【问题描述】:

我正在使用旧版本的 Node (8.x) 做一些事情,并且我编写了一个函数来计算 redis 中一堆哈希的值。

问题是,代码总是使用默认值 0,因为该函数似乎是在它在它下面的行中使用之后才运行的。我可以在日志中看到函数返回的值不是 0。

如何确保函数在继续运行之前运行并在它下面的 redis 命令中使用?

谢谢,如果这是菜鸟问题,对不起:

您可以在下面看到我正在定义 blockEffort = 0。然后我调用下面的函数来获取实际值。但在“redisCommands.push(['sadd', coin + ':blocksExplorer', [dateNow, shareData.height, shareData.blockHash, shareData.worker, blockEffort].join(':')] );"它仍然是零。

if (isValidBlock) {
            var blockEffort = parseFloat(0);
            this.getCurrentRoundShares(function (roundShares) {
                    logger.debug("calling GetCurrentRoundShares");
                    blockEffort = [roundShares / shareData.blockDiff];
                    logger.debug(`{"message": "Calculating Block Effort", "totalRoundShares": "${roundShares}", "blockEffort": "${blockEffort}"}`);
                });
            redisCommands.push(['rename', coin + ':shares:roundCurrent', coin + ':shares:round' + shareData.height]);
            redisCommands.push(['rename', coin + ':shares:timesCurrent', coin + ':shares:times' + shareData.height]);
            redisCommands.push(['sadd', coin + ':blocksPending', [shareData.blockHash, shareData.txHash, shareData.height].join(':')]);
            redisCommands.push(['sadd', coin + ':blocksExplorer', [dateNow, shareData.height, shareData.blockHash, shareData.worker, blockEffort].join(':')]);
            redisCommands.push(['zadd', coin + ':lastBlock', dateNow / 1000 | 0, [shareData.blockHash, shareData.txHash, shareData.worker, shareData.height, dateNow].join(':')]);
            redisCommands.push(['zadd', coin + ':lastBlockTime', dateNow / 1000 | 0, [dateNow].join(':')]);
            redisCommands.push(['hincrby', coin + ':stats', 'validBlocks', 1]);
            redisCommands.push(['hincrby', coin + ':blocksFound', shareData.worker, 1]);
}



this.getCurrentRoundShares = function(cback) {
        
        connection.hgetall('ravencoin:shares:roundCurrent', function(error,result) {
            if (error) {
                logger.error(`{"message": "Error getCurrentRoundShares", "data": "${error}"}`);
                cback(error);
                return;
            } else {
                logger.debug(`{"message": "Calculating all shares in current round"}`);
                logger.debug(result.toString());

                var _shareTotal = parseFloat(0);
                for (var worker in result) {
                    logger.debug(`{"message": "Shares for each Worker", "worker": "${worker}", "shares": "${parseFloat(result[worker])}"} }`);
                    _shareTotal += parseFloat(result[worker]);
                }
                logger.debug("Total Shares: " + _shareTotal );
                cback(_shareTotal);
            }
        });         
        },
        function(err) {
              if (err) {
                logger.error(`{"message": "Error getCurrentRoundShares", "data": "${err}"}`);
                cback(0);
                return;
            }
    };

完整文件在这里:https://github.com/devdevdevdev1/rvnpool/blob/main/shareProcessor.js

【问题讨论】:

  • 您不能告诉 Javascript 等待异步回调执行。因此,您要么将剩余代码放在回调内部(因此在调用回调时继续执行),或者切换到对所有异步操作使用 Promise 接口,以便在函数调用上使用 await
  • 谢谢,我正在考虑使用 Promise,但我不认为我正在使用的节点版本完全支持它们。我想我会尝试使用回调中的所有代码。
  • 你真的需要超越节点版本 8 - 甚至不再支持错误或安全修复,因此使用它可能是完全不安全的。您在此代码中显示的所有内容看起来都需要 redis 对 Promise 的支持,并且看起来您不会从 nodejs 中丢失任何东西。仅供参考,节点版本 8 的生命周期结束于 2019 年 12 月 31 日。所以,它已经过期两年多了。
  • 是的,我知道。这是一些矿池软件的一个分支,需要大量解开才能获得更现代的节点版本。它肯定在积压清单上。它看起来确实支持承诺,我实现了下面建议的一个,但执行顺序仍然存在一些问题......

标签: javascript node.js


【解决方案1】:

您可以让this.getCurrentRoundShares 函数返回Promise

this.getCurrentRoundShares = function(cback) {
    return new Promise((resolve, reject) => {
        // do your stuf..
        
        let processHasFinishedSuccessfully = true;
        // if your stuff failed
        if (processHasFinishedSuccessfully){
           resolve();
        }
        else {
           reject(Error('Failed'));
        }
    };

然后,在您的 this.handleShare 函数中,您等待响应

this.handleShare = async function(isValidShare, isValidBlock, shareData) {
    // your stuff ...

            await this.getCurrentRoundShares(function (roundShares) {
                    logger.debug("calling GetCurrentRoundShares");
                    blockEffort = parseFloat([roundShares / shareData.blockDiff]);
                    logger.debug(`{"message": "Calculating Block Effort", "totalRoundShares": "${roundShares}", "blockEffort": "${blockEffort}"}`);
                });

    // your stuff...
    };

这应该确保代码执行不会继续进行,直到您收到来自 getCurrentRoundShares () 函数的响应。

【讨论】:

  • 谢谢,这样的 promise 在 Node 8.x 中有效吗?我认为情况并非如此。
  • 好的,所以承诺确实有效,但它仍然将它作为 0 插入到 redis 中(日志说它应该是 154.727。我在这里更新了代码 (github.com/devdevdevdev1/rvnpool/blob/main/…) - 知道我是什么我做错了吗?
  • 调用回调时roundShares 有什么值?可能有几个原因:解析失败,值实际上是 0 等等。
  • 第 70 行的调试日志返回:"result": {"message": "Calculating Block Effort", "totalRoundShares": "30.7", "blockEffort": "154.7279059625679"}} 所以值肯定不为零。初始化 blockEffort 时,它似乎仍然采用默认值。
【解决方案2】:

如果你正在使用这个redis module,那么它已经内置了 Promise 支持,你可以直接使用它。你不显示调用代码,但是如果你调用函数async,你可以这样做:

async function someFunction() {

    // ... other code here

    if (isValidBlock) {
        try {
            var blockEffort = parseFloat(0);
            let roundShares = await this.getCurrentRoundShares();
            logger.debug("calling GetCurrentRoundShares");
            blockEffort = [roundShares / shareData.blockDiff];
            logger.debug(`{"message": "Calculating Block Effort", "totalRoundShares": "${roundShares}", "blockEffort": "${blockEffort}"}`);
            redisCommands.push(['rename', coin + ':shares:roundCurrent', coin + ':shares:round' + shareData.height]);
            redisCommands.push(['rename', coin + ':shares:timesCurrent', coin + ':shares:times' + shareData.height]);
            redisCommands.push(['sadd', coin + ':blocksPending', [shareData.blockHash, shareData.txHash, shareData.height].join(':')]);
            redisCommands.push(['sadd', coin + ':blocksExplorer', [dateNow, shareData.height, shareData.blockHash, shareData.worker, blockEffort].join(':')]);
            redisCommands.push(['zadd', coin + ':lastBlock', dateNow / 1000 | 0, [shareData.blockHash, shareData.txHash, shareData.worker, shareData.height, dateNow].join(':')]);
            redisCommands.push(['zadd', coin + ':lastBlockTime', dateNow / 1000 | 0, [dateNow].join(':')]);
            redisCommands.push(['hincrby', coin + ':stats', 'validBlocks', 1]);
            redisCommands.push(['hincrby', coin + ':blocksFound', shareData.worker, 1]);
        } catch(e) {
            logger.debug(e);
            // handle error in this.getCurrentRoundShares() here
        }
    }
}

this.getCurrentRoundShares = async function() {
    let result = await connection.hGetAll('ravencoin:shares:roundCurrent');
    logger.debug(`{"message": "Calculating all shares in current round"}`);
    logger.debug(result.toString());

    let _shareTotal = parseFloat(0);
    for (var worker in result) {
        logger.debug(
            `{"message": "Shares for each Worker", "worker": "${worker}", "shares": "${parseFloat(result[worker])}"} }`
            );
        _shareTotal += parseFloat(result[worker]);
    }
    logger.debug("Total Shares: " + _shareTotal);
    return _shareTotal;
};

【讨论】:

  • 谢谢。这似乎以正确的顺序执行,但我的查询不再返回数据。我不得不更改你的 hGetAll(这不是 redis 的函数)以让 result = await connection.hgetall('ravencoin:shares:roundCurrent');,但“结果”现在返回“真”而不是数据。跨度>
  • @DEVDEVDEVDEV - 如果你使用this library 访问redis,那么the doc 表示它支持await client.hGetAll()。也许您正在使用不同的库。无论如何,如果这有助于您弄清楚,您可以通过单击答案左侧的复选标记在此处向社区表明这一点。遵循正确的程序,这也将为您赢得一些声誉积分。
  • 我正在使用那个库,v2.8.0。可能会更新。问题是您上面放置的代码没有将查询结果返回到“结果”,它只是返回“真”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-24
  • 2021-06-06
  • 1970-01-01
  • 1970-01-01
  • 2020-12-21
  • 2022-12-01
  • 1970-01-01
相关资源
最近更新 更多