【问题标题】:initializing a nodejs global variable within a function and having it equate the same calling it outside在函数中初始化 nodejs 全局变量并使其等同于在外部调用它
【发布时间】:2020-10-18 03:09:25
【问题描述】:

所以当涉及到 nodejs 时,我在范围方面遇到了一些问题。我想知道如何在全局空间中初始化变量,在函数(私有范围)中对其进行初始化,然后在类中的任何位置调用它时使其等于在私有范围中初始化它的值。我注意到的一件事是,尽管您可以在私有范围内使用该变量,但当在该函数之外再次调用它时,它只是变为未定义。如何返回私有时初始化的相同函数?这不是我发布的代码,而是一个示例,以防图片不清晰

let name;
class blah {
    static blablah() {
        name = josh;
    }
    console.log(name);
    //this will return undefined and not josh
}

在我的上下文中我需要什么:

let genesis;
let jsonChain;

class Blockchain {
    constructor() {
        //this.chain = [Blockchain.getGenesis()];
        console.log(Blockchain.getGenesis());
}
    //down the file we find the issued function...
    static getGenesis() {
         fs.readFile(jsonRoute, 'utf-8', function(err, data) {
             if (err) throw err;
    
             jsonChain = JSON.parse(data);
             genesis = jsonChain.blocks[0].GENESIS_DATA;
             return genesis;
        });
        //returning here instead inside the callback also yields undefined
        //I want to be able to access my contents from json file through 
        //the genesis variable which is global when I return this function
        //but I cannot reach the contents of the callback
    }
}

解决方案:确保返回承诺,以便异步函数稍后在您调用它时在您的程序中运行。

let genesis;
let jsonChain;

class Blockchain {
    constructor() {
        this.chain = [Blockchain.getGenesis()];
            console.log(Blockchain.getGenesis().then(function(genesisData) {
      console.log(genesisData); // Genesis block data is here.
    }, function(err) {
      // This only runs if there was an error.
      console.log(err);
    }));
        }
    //down the file we find the solved function...
  static getGenesis() {
    return new Promise(function(resolve, reject) {
      fs.readFile(jsonRoute, 'utf-8', function(err, data) {
        if(err) return reject(err);
        const jsonChain = JSON.parse(data);
        resolve(jsonChain.blocks[0].GENESIS_DATA);
      });
    });
  }
    
}
module.exports = Blockchain;

【问题讨论】:

  • 你没有在任何地方显示你实际调用你的 blablah() 方法。而且,您的 console.log(name) 试图在类定义中,但不是在没有意义的方法中。而且,josh 不是一个定义的值。
  • 我们可以从您尝试在下面的评论中粘贴的代码中看到,真正的问题是您正在尝试从异步回调更新更高范围的变量。除了是一个糟糕的设计原则之外,您无法从回调外部知道全局何时更新。您可能会尝试在更新之前访问全局。无论如何,这只是一种反模式。不要那样做。使用异步回调中的值或从该回调中调用一个函数并将该值传递给该函数。这就是你异步编程的方式。
  • 请显示您调用getGenesis() 的代码,并显示您尝试使用jsonChain 变量的代码。这将阐明实际问题(如我之前的评论中所述),并将允许我们就您应该如何做提供建议。
  • 另外,永远不要在一个普通的异步回调中使用if (err) throw err(这是另一种反模式)。这没有任何用处。你需要真正的错误处理。
  • 感谢您的洞察力,我需要稍后再回来解决此问题,因为我有强制性工作要做。但是非常感谢您的洞察力,我学到了很多东西!

标签: javascript node.js variables scope global-variables


【解决方案1】:

现在您已经添加了真正的代码,其中说明了许多问题。

  1. if (err) throw err 在普通的异步回调中没有任何用处。没有人能捕捉到这个错误,因此永远不应该使用它。您需要在那里进行真正的错误处理。 IMO,在这种情况下永远不应该写那行代码。

  2. return genesis; 没有任何用处。这只是从fs.readFile() 回调返回,其中fs.readFile() 的内部忽略任何返回值。这不会从更高级别的函数返回。

  3. jsonChain = JSON.parse(data); 确实成功地分配给更高范围的变量,但是任何试图使用 jsonChain 变量的代码都不会知道它何时被分配了一个值,因为fs.readFile() 是异步的,并且在某些时候调用它的回调未来,不确定的时间。因此,如果您看到 jsonChain 没有任何价值,那是因为您在分配变量之前查看了该变量。基本上,这是一种反模式。您不能在 node.js 中以这种方式使用异步代码进行编程。相反,您需要在回调中使用异步值,或者您需要从回调中调用某个函数并将值传递给它。只有在这种情况下,您才知道该值何时可用。

  4. 如果这里的顶级问题是您尝试返回异步检索的某个值,那么您不能直接在 Javascript 中执行此操作。您可以阅读所有关于 here 的内容,其中解释了您必须通过回调、承诺或者您也可以使用事件将该异步值传达回调用者。

【讨论】:

  • 我已将 getGenesis() 函数设置为采用名为 genChain 的参数,因此我将异步函数中的 genesis 变量设置为将其值放入 getGenesis 然后返回它并在构造函数中调用它,这再次产生了 undefined
  • @NoobGuy - 您显然不理解 node.js 中“非阻塞、异步”操作的含义。这意味着您的其余代码将继续运行,一段时间后您不知道何时会调用异步回调。同时,您的函数早已在调用异步回调之前返回。请阅读我在上面的第 4 点中添加的链接。它解释了如何返回异步值。只有三个选项(回调、承诺或事件)。你不能退货。该函数在值存在之前返回。
  • 问题已解决,我只需要简单地返回一个承诺。我编辑了以下代码。也感谢您的解释,它有助于我的洞察力。
【解决方案2】:

您的代码的第一个问题是josh 不在引号中。 joshundefined;你是说'josh'(引号)吗?


一种方法是使您的getGenesis() 函数async,以便您可以等待它完成为genesis 分配正确的值。这需要将所有内容包装在匿名 async 函数中:

(async () => { 
  const fs = require('fs');
  let genesis;
  let jsonChain;

  class Blockchain {
    constructor() {
      this.chain = [Blockchain.getGenesis()];
      console.log(Blockchain.getGenesis());
    }

    static async getGenesis() {
      jsonChain = JSON.parse(await fs.promises.readFile(jsonRoute, 'utf-8'));
      genesis = jsonChain.blocks[0].GENESIS_DATA;
    }
  }

  console.log(genesis); // undefined D:
  await Blockchain.getGenesis();
  console.log(genesis); // not undefined :D
})();

【讨论】:

  • 假设这是真的,我尝试使用的上下文并不完全使用引号,我会在一秒钟内加载我的上下文,让你看看我做错了什么,并希望为人们提供喜欢刚接触节点洞察的我
  • class Blockchain { constructor() { this.chain = [Blockchain.getGenesis()]; console.log(Blockchain.getGenesis()); } //further down the file with the issued function static getGenesis() { fs.readFile(jsonRoute, 'utf-8', function(err, data) { if (err) throw err; jsonChain = JSON.parse(data); genesis = jsonChain.blocks[0].GENESIS_DATA; return genesis; }); //if I put return here it has the same undefined effect }
  • 考虑更新你的帖子;在 cmets 中很难阅读。甚至被单个 ` 反引号包围。
  • ok GirkovArpa,我已将其添加到问题本身
  • 我的构造函数不会是未定义的,因为它不是在等待之后吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-06
  • 1970-01-01
  • 2020-06-04
  • 2011-01-20
  • 2015-07-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多