【问题标题】:How to assign variable to result of asynchronous class method that returns an object in its promise?如何将变量分配给在其承诺中返回对象的异步类方法的结果?
【发布时间】:2020-08-27 13:08:00
【问题描述】:

看起来互联网上没有人描述类似的问题,并且类似的解决方案对我不起作用。 我正在尝试 scrape 网页,因此我为解析器创建了类,其中一种方法如下所示:

 get chListUrl() {
    return "http://www.teleman.pl/program-tv/stacje";
  }

getChannels() {
     var dict = {};
     axios.get(this.chListUrl).then(function (response) {  
       var $ = cheerio.load(response.data);       
        var ile_jest_stacji = $('#stations-index a').length;
        $('#stations-index a').each( (i,elem) => {
          let href = $(elem).attr('href');
          let kodstacji = href.replace(/\/program-tv\/stacje\//ig,'');     
          let nazwastacji = $(elem).text();
          dict[nazwastacji]=kodstacji;
        });
        return  dict;
        
    }).catch(function (error) {
        console.log(error);
        return null;
    }).finally(function() {
        console.log("Koniec");
        
    });
  }

问题是getChannels 必须是间接异步的,因为它包含 axios BUT

let tm = new TM();
var a = tm.getChannels();

a 总是未定义的,它应该是字典!这种构造意味着“将 tm.getChannels() 的执行结果分配给变量”,因此应始终在整个函数结束后进行赋值。否则这样的语言语法是没有用的,因为你永远无法确定变量中存储的是什么值,而且这样的错误很难找到和调试。

var a = await tm.getChannels();

不工作 -> SyntaxError: await 仅在异步函数中有效(嗯?)

将异步添加到 getChannels() 不会改变任何事情。
将异步分配给 getChannels() 并从分配中删除“等待”返回 Promise{undefined}(嗯?)
将 async 放在 axios 之前没有任何改变,因为 .then() 已经处理了响应
return dict 更改为 return await dict 会给出另一个“等待仅在异步函数中有效”(嗯?axios 是异步的)

我为此苦苦思索了 2 周。 在 Swift 中,当完成处理程序中返回某些内容时,它会在适当的时候分配给变量,为什么 Promise 返回的内容不以相同的方式工作?

【问题讨论】:

  • Such construct means "assing to variable a result of execution of tm.getChannels()" so assignment should always be done AFTER whole function ends. - 它IS在整个函数结束后完成。您的getChannels() 函数不会立即执行您传递给.then(...) 的函数。您将此函数作为 Promise回调 - 你告诉解释器,“当请求完成时运行此代码”,解释器保存代码 并且然后返回而不运行它
  • axios 是 GetChannels 中的内部函数。 GetChannels 不返回任何应返回字典的承诺,因此,如果我理解正确,如果 Promises 无法返回值,则它们在 JavaScript 中是无用的:( ,多么可悲的故事
  • 他们可以返回一个值。它们可以异步返回值,但不能同步。这远非无用。这意味着您可以在等待 HTTP 请求完成的同时继续执行代码。这意味着您可以同时启动多个 HTTP 请求。你只需要围绕这个新模式调整你的代码 - getChannels() 依赖于一个 HTTP 请求,所以它不能直接返回一个字典,你必须给它一个回调或者让它返回一个承诺。这对你来说是异步 javascript。

标签: javascript promise axios


【解决方案1】:

您需要在异步函数中才能使用await expression

await 运算符用于等待 Promise。它只能在异步函数中使用。

示例来自MDN:

async function f1() {
  var x = await resolveAfter2Seconds(10);
  console.log(x); // 10
}

f1();

解决您的问题

class TM {

  get chListUrl() {
    return "http://www.teleman.pl/program-tv/stacje";
  }

  async getChannels() { // you need not use get syntax 
    let dict = {};
    try { // we will be handling possible errors with try catch instead of reject
        const response = await axios.get(this.chListUrl);
        let $ = cheerio.load(response.data);       
        let ile_jest_stacji = $('#stations-index a').length;
        $('#stations-index a').each( (i,elem) => {
          let href = $(elem).attr('href');
          let kodstacji = href.replace(/\/program-tv\/stacje\//ig,'');     
          let nazwastacji = $(elem).text();
          dict[nazwastacji]=kodstacji;
        });
      return dict;
     } catch(ex) {
      console.log(ex);
      return null
     }
  }

}

// let's make it work!
(async function() {
  const tm = new TM()
  const channels = await tm.getChannels()
  // do whatever you want with channels
  console.log(channels)
})()

现在,您可能不会像这样突然调用getChannels,而是可能会在您自己定义的函数中,您需要将async 关键字添加到该函数中。无论您的代码是什么块函数,都必须是async

【讨论】:

  • 谢谢,我会尝试,但我总是很难理解这种奇怪的语法 (function)() 发生了什么,这给我带来了另一个问题——如果你不能从 Promise 中返回值,为什么存在 Promise
  • 感谢您花时间提供帮助 :) 我当时使用了,因为我在一些博客上发现了这个,作者不敢解释返回值的细微差别,现在应该更容易了 :)跨度>
【解决方案2】:

如果你想使用 async/await 语法,你应该删除 .then() 语法,你可以这样解决:

async getChannels() {
     const response = await axios.get(this.chListUrl);
     return response
  }

您可以在链接中了解有关 async/await 的更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

【讨论】:

  • 我不知道使用什么同步等待。我的问题是我的 Promise 函数显然无法正确返回值并将其分配给变量,这就是交易
猜你喜欢
  • 2020-05-10
  • 1970-01-01
  • 2018-08-30
  • 2021-10-15
  • 2020-01-03
  • 2015-12-13
  • 1970-01-01
  • 2019-09-18
  • 1970-01-01
相关资源
最近更新 更多