axios 和 promise,数组值不可用但出现在 console.log

Posted

技术标签:

【中文标题】axios 和 promise,数组值不可用但出现在 console.log【英文标题】:axios and promises, array value not available but appears in console.log 【发布时间】:2018-06-10 13:53:58 【问题描述】:

我已经嵌套了 axios 调用,因此使用 Promise 来构建我将用于我的应用程序的数据数组。

第一次调用获取标题或剧集列表。

第二次调用获取第一次收到的剧集 url 以获取更多数据。然后,我将属性添加到我想在我的应用程序中使用的数据数组中。 这些是 title 和 image_urls[0]。

第三个调用然后获取 image_urls[0] 并调用以检索该实际图像。现在在这个调用中,当我 console.log 或对第二次调用中添加的值做任何事情时,我得到了未定义,但是如果我 console.log 我的完整数组出现了值!

 console.log("sections", sections); // show all the data including 2nd call
 console.log("image url", item.url); // This shows
 console.log("image title", item.title); // This doesn't and don't know why
 console.log("image imageurls", item.imageurls); // This doesn't and don't know why

这是我的代码

import axios from 'axios';

let sections = new Array(),
    section = null,
    episodes = null;

const dataService =
axios
    .get('http://feature-code-test.skylark-cms.qa.aws.ostmodern.co.uk:8000/api/sets/coll_e8400ca3aebb4f70baf74a81aefd5a78/items/')
    .then((response) => 

    var data = response.data.objects;

    Promise.all(data.map(function (item) 
        let type = item.content_type.toLowerCase();

        if (type !== "episode") 
            if (section !== null) 
                section.episodes = episodes;
                sections.push(section);
            
            section = new Object();
            episodes = new Array();
            section.header = item.heading;
        

        if (type === "episode") 
            var episode = new Object();
            episode.url = item.content_url;
            episodes.push(episode)
        
    )).then(function () 
        section.episodes = episodes;
        sections.push(section);

        Promise.all(sections.map(function (item) 
            Promise.all(item.episodes.map(function (item) 
                var url = `http://feature-code-test.skylark-cms.qa.aws.ostmodern.co.uk:8000$item.url`
                axios
                    .get(url)
                    .then((response) => 
                    var data = response.data;

                item.title = data.title;
                item.imageurls = data.image_urls[0] !== undefined ? data.image_urls[0] : "";
            );

            ))
        )).then(function () 
            Promise.all(sections.map(function (item) 
                Promise.all(item.episodes.map(function (item) 
                    console.log("sections", sections);
                    console.log("image urr", item.url);
                    console.log("image title", item.title);
                    console.log("image imageurls", item.imageurls);
                ));
            ));
        );;
    )
)

export default dataService

【问题讨论】:

您继续使用map(),但永远不会向这些映射数组返回任何内容。 Promise.all([undefined,undefined]) 没用,不会等待任何东西。也不返回链式 then()'s 中的任何内容 @charlietfl 你能给我看一个修改上面代码的例子吗? @charlietfl 我正在映射的数组,我正在 Promise 中更新。您能解释一下为什么在控制台记录sections 数组时会出现这些值,但在第三次调用中执行项目属性时却没有。 首先,仅在需要的地方使用 Promise - 代码的快速而肮脏的重写(我认为)是 jsfiddle.net/r7txrqo0 - 注意只有一个 Promise.all ...与 5 个不必要的 Promise 相比.all 在您的代码中? ...并使用 forEach,因为您的代码中根本不需要 .map - 然而,这是一个快速而肮脏的重写 你的代码可以写成jsfiddle.net/r7txrqo0/1 - 老实说,我仍然不理解或不喜欢第一个“循环”。而且,最后,dataService 将是一个解析为 undefined 的 Promise,与您的原始代码相同 - 因为我不知道您希望 dataService 实际上是什么 【参考方案1】:

以下应该对你有用,我认为你必须花一点时间来研究 promise、map 和 reduce。

我摆脱了 axios 并使用了 fetch,因此可以在网站上打开 api page 并在控制台中运行代码时在浏览器中对其进行测试(没有导出行并将 const 替换为 var)。

如果您需要任何帮助,请告诉我。

const base = "http://feature-code-test.skylark-cms.qa.aws.ostmodern.co.uk:8000";
const setEpisodeDetails = episode =>
  fetch(`$base$episode.url`)
    .then(response=>response.json())
    .then(
      data =>
        Object.assign(
          
          ,episode
          ,
            title : data.title,
            imageurls : data.image_urls[0] || ""
          
        )
    )
    .then(//fetch image url
      episode =>
        (episode.imageurls!=="")
          ? fetch(`$base$episode.imageurls`)
            .then(response=>response.json())
            .then(
              imageData=>
                Object.assign(
                  ,
                  episode,
                  
                    image_content_url:imageData.url
                  
                )
            )
          : episode
    );
const setAllEpisodeDetails = sections =>
  Promise.all(
    sections.map(
        section =>
          Promise.all(
            section.episodes.map(
              setEpisodeDetails
            )
          )
          .then(
            episodes =>
              Object.assign(
                ,
                section,
                episodes
              )
          )

    )
  );
const createSections = data =>
  data.reduce(
    (acc,item)=>
      (item.content_type.toLowerCase()!=="episode")
        ? acc.push(header:item.heading,episodes:[])
        : acc.slice(-1)[0].episodes.push(url:item.content_url)
      return acc
    ,
    []
  );
const dataService =
  fetch(`$base/api/sets/coll_e8400ca3aebb4f70baf74a81aefd5a78/items/`)
    .then(response=>response.json())
    .then(
      response =>
        setAllEpisodeDetails(createSections(response.objects))
    )
    .then(
      sections =>
          console.log(
            "sections", 
            JSON.stringify(sections,undefined,2)
          ) || //remove this console log if it works
          // (can remove the whole last then)
          //do not remove this it returns sections (unless you get rid of the whole then)
          sections
    );

//removed export, should log the result when done (or error)

【讨论】:

好的。不了解其中的大部分内容,因此将进行一些研究。将尝试在加载实际图像的 setEpisodeDetails 之后添加另一个调用 @Adam 如果您在现代浏览器中打开this link,您可以检查输出是否正确(最近的 Chrome 可以正常工作)。按 F12 并在控制台中粘贴代码。将export default dataService 替换为dataService.then(result=>console.log(JSON.stringify(result,undefined,2))) 是的,我可以看到它工作。不知道我如何扩展它以在 setEpisodeDetails 之后对 api 有另一个请求,以使用 episode.imageurls 检索实际图像。你能给我看看吗? @Adam 您的意思是通过 fetch 获取图像并将其存储为 base64?我不知道该怎么做,但明天可以查一下。您可以尝试编写一个函数,该函数采用 url 并获取图像,将其存储为 base64 并将其设置为 img html 元素。您可以不下载图像,因为您有 url,因此您可以添加第一部分 (barurl.com...) 并将其用于您的 img src 属性。我不确定您的代码是否在 http://feature-code-test.skylark-cms.qa.aws.ostmodern.co.uk:8000 上运行,如果不是,代码可能根本无法工作,因为我没有看到允许来源的标头。 不是 base64。获取 episode.imageurls 的值是一个 api 端点。从该端点开始,属性之一是实际的绝对图像路径。所以我只需要 episode.imageurls 临时的,只是为了在那个电话之后得到实际的图像。

以上是关于axios 和 promise,数组值不可用但出现在 console.log的主要内容,如果未能解决你的问题,请参考以下文章

在map函数中使用axios时返回一个promise数组?

从 Promise(ReactJS 和 Axios)中提取图像数据

使用 axios 时可能出现未处理的 Promise 拒绝、网络错误

Vue 接口 promise + fetch + axios + async 和 await

Vue 接口 promise + fetch + axios + async 和 await

使用 Axios 在 Node.js 中克服 Pending Promise 并完成构建 JSON