尽管已分配,但函数范围外的变量未定义?

Variable undefined outside function scope despite being assigned?

问题

我在 MERM 应用程序中遇到问题,在该应用程序中,在整个函数主体中声明的变量被分配给子函数,但是,每当我尝试 manipulate/display 这个变量时在整个函数的末尾,它 returns 一个 "undefined"。

代码

getSimilarCasesFromID: function(req, res, next) {
    let queryString = "id::"+req.params.id; 
    let params = {
        'query': queryString,
        'environment_id':environmentId,
        'collection_id': collectionId,
        'configuration_id': configurationId,
        return: 'enriched_text'
    }

    let filterStrArr = [];
    const FILTER_CONCEPT = "enriched_text.concepts.text:";
    let filterStr ="";

    discovery.query(params, (error, results) => {
        if (error) {
            next(false, err, []);
        } else {
            let conceptSize = results.results[0].enriched_text.concepts.length;
            let concepts = {};
            for (let i = 0; i < conceptSize; i++) {
                concepts[i] = { 
                    text: results.results[0].enriched_text.concepts[i].text,
                    relevance: results.results[0].enriched_text.concepts[i].relevance
                 };

                filterStrArr[i] = FILTER_CONCEPT + concepts[i].text;
            }

            filterStr = filterStrArr.join(",");
            console.log(filterStr);
            //1. Works and displays---------------
        }
    });

    console.log("FullString (2.)"+filterStr);
    //2. Undefined????????????????????------------

    next(true, [], []);
},

我指的是第 (1.) 和 (2.) 行。我不知道我是否错过了什么,犯了一个愚蠢的、微不足道的错误。

服务器上的输出:

有趣的是,如图 1 所示,FullString (2.) 出现在行 (1.) 之前。这可能是由于 Watson Discovery 的响应时间造成的吗?请记住该服务位于澳大利亚悉尼?如果是这样,其他人有这方面的经验吗?

discovery.query() 有两个属性,
1 - 参数
2 - 函数(也称为回调)

discover.query() 被执行,但是 returns 在执行回调之前,
接下来 console.log("FullString (2.)"+filterStr);被执行
最后执行回调。

您需要在回调中执行您想要的操作。

这很痛苦,但 JavaScript 就是这样工作的。更准确地说,discovery.query() 是如何工作的。更糟糕的是当你有嵌套的回调时,它会变得非常混乱并且有一个名字:"callback hell"。这个问题的现代解决方案是 promises 和 async await。

祝你好运

discovery.query是一个异步函数,所以变量filterStr只有到达回调才会被定义。您需要在 discovery.query 的回调中使用 filterStr 或在 try/catch 块中使用 async/awaitreturn results.

异步函数的工作原理是允许它在不中断线程的情况下执行。所以这就是 console.log(2.) 被执行的原因,然后稍后,console.log(1.) 在回调中被执行(由于函数是 asynchronous,它需要一些时间才能到达回调)。您正在尝试做一些事情 synchronously,为此,您需要重构您的代码。 Click here 有关异步和同步执行的更多信息。

回调内

getSimilarCasesFromID: function(req, res, next) {
  const queryString = "id::"+req.params.id; 
  const params = {
    'query': queryString,
    'environment_id':environmentId,
    'collection_id': collectionId,
    'configuration_id': configurationId,
    return: 'enriched_text'
  };

  const filterStrArr = [];

  const FILTER_CONCEPT = "enriched_text.concepts.text:";

  discovery.query(params, (error, results) => {
    if (error) {
      next(false, err, []);
    } else {
      let filterStr ="";

      const conceptSize = results.results[0].enriched_text.concepts.length;

      let concepts = {};
      for (let i = 0; i < conceptSize; i++) {
        concepts[i] = { 
          text: results.results[0].enriched_text.concepts[i].text,
          relevance: results.results[0].enriched_text.concepts[i].relevance
        };

        filterStrArr[i].push(FILTER_CONCEPT + concepts[i].text);
      }

      filterStr = filterStrArr.join(",");
      console.log(filterStr);

      // utilize filterStr here

      next(true, [], []);
    }
  });
},

async/await:

getSimilarCasesFromID: async function(req, res, next) {
  const queryString = "id::"+req.params.id; 
  const params = {
    'query': queryString,
    'environment_id':environmentId,
    'collection_id': collectionId,
    'configuration_id': configurationId,
    return: 'enriched_text'
  }

  const filterStrArr = [];

  const FILTER_CONCEPT = "enriched_text.concepts.text:";

  let filterStr ="";

  try {
    const results = await discovery.query(params);

    const conceptSize = results.results[0].enriched_text.concepts.length;

    let concepts = {};
    for (let i = 0; i < conceptSize; i++) {
      concepts[i] = { 
        text: results.results[0].enriched_text.concepts[i].text,
        relevance: results.results[0].enriched_text.concepts[i].relevance
      };

      filterStrArr[i].push(FILTER_CONCEPT + concepts[i].text);
    }

    filterStr = filterStrArr.join(",");
    console.log(filterStr);

    // utilize filterStr here

    next(true, [], []);       

  } catch(err) {
     next(false, err, []);
  }
},