如何从 axios 响应对象中的所有项目中提取特定值到 vuex 状态

Posted

技术标签:

【中文标题】如何从 axios 响应对象中的所有项目中提取特定值到 vuex 状态【英文标题】:How can I extract specific values from all items in axios response object to a a vuex state 【发布时间】:2020-06-20 06:25:16 【问题描述】:

这让我发疯了!

我有一个 axios 调用在控制台中返回一个 json 数组对象 - 检查!

>(100) […, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …, …]
>0:
id: 54892250
iid: 1001
ref: "master"
sha: "63e3fc014e207dd4e708749cee3e89a1aa416b7d"
created_at: "2020-03-05T18:57:02.793Z"
updated_at: "2020-03-05T19:06:27.651Z"
>user: id: someuserid, name: "someuser", username: "someusername", state: "active", avatar_url: "https://assets.gitlab-static.net/uploads/-/system/user/avatar/4534925/avatar.png", …
>environment: id: 123456, name: "somename", slug: "somename-iw5iqp", external_url: "https://someaddress.com"
>deployable: id: someid, status: "success", stage: "deploy", name: "deploy-staging", ref: "master", …
status: "success"
__proto__: Object
>1: id: 54804365, iid: 1000, ref: "filter-out-expired-items", sha: "6225d8018c86fa906063aeea5c10c710ddced14c", created_at: "2020-03-05T12:25:18.949Z", …
>2: id: 54804175, iid: 999, ref: "master", sha: "aa5e50c50ba95e9b16cbc57fb968bf9075c625b2", created_at: "2020-03-05T12:24:02.284Z", …
>3: id: 54801934, iid: 998, ref: "filter-out-expired-items", sha: "4fc2

现在我需要对这个结果做两件事:

    当完全展开时,这个响应很大——而且有数千个。而不是在 vuex 状态下存储 1000 个巨大的 json 响应 - 我想首先只提取我们关心的值,这些值如下: 身份证 参考 环境名称 状态 deployable.tag

类似于:

 "id": id, "ref": ref, "environment": environment.name, "status": status, "tag": deployable.tag, 

我该怎么做?

    此响应在上面的许多页面上进行了分页,这只是一个页面结果的部分示例。

我有一个工作循环,我正在为所有这些循环获取 console.log。但我需要做的是在我提交状态之前连接所有页面(现在剥离到上述字段)。如果尝试过对象副本,推送到数组和各种有前途的实用程序 - 但我无法让它们中的任何一个工作:)

总之:

    获取页面结果 将数组中的项目压缩为简化版本 将它们全部收集到我可以插入状态的对象中

循环的相关部分

  // Use headers to get the number of pages
  const pages = await axios.head(url, options)
    .then((response) => response.headers['x-total-pages']);
  console.log('pages=', pages); // DEBUG
  // Loop through and push them to an array
  for (let i = 0; i <= pages; i += 1) 
    console.log('i=', i);
    options = 
      headers: 
        'Private-Token': token,
      ,
      params: 
        order_by: 'created_at',
        sort: 'desc',
        per_page: 100,
        page: i,
      ,
    ;
    axios.get(url, options)
      .then((result) =>  console.log(result.data); )
  

【问题讨论】:

你能贴出你的子数组(页面数组/列表)结构吗 这是我正在使用的 Gitlab 的 API - 他们有很好的文档和示例响应部署 api docs.gitlab.com/ee/api/… 他们的分页 docs.gitlab.com/ee/api/README.html#pagination 我正在努力制定我所知道的简洁的目标:) 但基本上它是一年多部署统计数据的总结。他们每年可以得到 3000-4000 个结果,这就是为什么我认为在将数据集放入状态之前对其进行拟合很重要 当您异步执行所有请求时,您将失去排序,并且您不会真正知道所有请求何时完成。当所有请求承诺都已解决时,您可以使用Promise.all()。这就是你想要的吗? 【参考方案1】:

为总结果创建一个数组:

const results = [];

在您记录的位置,解析每个单独的结果:

result.data.forEach(item => 
  results.push(
     id: item.id,
     ref: item.ref,
     environment: item.environment.name,
     status: item.status,
     tag: item.deployable.tag
  );
);

请注意,使用普通的for 循环而不是forEach 可能是一种性能优化。

【讨论】:

谢谢!这似乎工作得很好,是我在它之前尝试过的许多迭代之一。我一定是在做一些愚蠢的事情,然后将其丢弃为另一种方法,因为现在我用您的代码作为模板重试了它,它似乎工作得很好!我对你所说的 for 和 foreach 之间的性能很好奇 - 但这现在发生得非常快! 很好,没问题。 Google forEach vs for 循环,应该会有一些结果。 Here is a performance test 两年前,但在未知浏览器上。对于更大的数据集,这似乎无关紧要,甚至forEach 可以更快。【参考方案2】:

我认为您可以使用 Promise 来保持请求的顺序,从而跨页面数据排序。关键是将每个 axios 调用放入一个数组中,然后使用该数组调用 Promise.all([]) 以按照您发出请求的原始顺序一次获得所有响应。

// Use headers to get the number of pages
const pages = await axios.head(url, options)
.then((response) => response.headers['x-total-pages']);
console.log('pages=', pages); // DEBUG

let promises = [];

// Loop through and push them to an array
for (let i = 0; i <= pages; i += 1) 
  console.log('i=', i);
  options = 
    headers: 
      'Private-Token': token,
    ,
    params: 
      order_by: 'created_at',
      sort: 'desc',
      per_page: 100,
      page: i,
    ,
  ;

  let promise = axios.get(url, options);
  // this below keep responses order
  promises.push(promise);


// This wait for all Axios calls to be resolved as promise
Promise.all(promises)
  .then((result) => 
    // now if you have 10 pages, you'll have result[0] to result[9], each of them is an axios response
    console.log(result[0].data);
    console.log(result[1].data); // if pages > 0

    let items = []; // you can declare it outside too for Scope access
    for (let i = 0; i <= pages; i += 1) 
      // so many records, then take the minimum info
      if (result[i].data.length >= 1000) 
        result[i].data.forEach(item => 
          items.push(
            id: item.id,
            ref: item.ref,
            environment: item.environment.name,
            status: item.status,
            tag: item.deployable.tag
          );
        
       else 
        // Not so many records then take all info
        items = items.concat(result[i]);
      
    

    // TODO: do whatever you want with the items array now

  );

【讨论】:

这不是我现在在工作解决方案中使用的东西,但我想花时间说声谢谢!它很好地介绍了我在通过 MVP 时正在考虑的一些事情:) 这很好。不客气。因为 axios 请求已经返回了一个 Promise,所以如果你想要一次将它们全部绑定在一起是很容易的。好好利用你的东西【参考方案3】:

我会在这里使用Array.prototype.map 将原始对象映射为仅具有属性子集的简化对象:

const newResult = result.data.map(d => (
                                   id: d.id,
                                   ref: d.ref,
                                   environmentName: d.environment.name,
                                   status: d.deployable.status,
                                   deployableTag: d.deployable.tag
                                 ))

const data = [
  
    "created_at": "2016-08-11T07:36:40.222Z",
    "updated_at": "2016-08-11T07:38:12.414Z",
    "deployable": 
      "commit": 
        "author_email": "admin@example.com",
        "author_name": "Administrator",
        "created_at": "2016-08-11T09:36:01.000+02:00",
        "id": "99d03678b90d914dbb1b109132516d71a4a03ea8",
        "message": "Merge branch 'new-title' into 'master'\r\n\r\nUpdate README\r\n\r\n\r\n\r\nSee merge request !1",
        "short_id": "99d03678",
        "title": "Merge branch 'new-title' into 'master'\r"
      ,
      "coverage": null,
      "created_at": "2016-08-11T07:36:27.357Z",
      "finished_at": "2016-08-11T07:36:39.851Z",
      "id": 657,
      "name": "deploy",
      "ref": "master",
      "runner": null,
      "stage": "deploy",
      "started_at": null,
      "status": "success",
      "tag": false,
      "user": 
        "id": 1,
        "name": "Administrator",
        "username": "root",
        "state": "active",
        "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gitlab.dev/root",
        "created_at": "2015-12-21T13:14:24.077Z",
        "bio": null,
        "location": null,
        "public_email": "",
        "skype": "",
        "linkedin": "",
        "twitter": "",
        "website_url": "",
        "organization": ""
      ,
      "pipeline": 
        "created_at": "2016-08-11T02:12:10.222Z",
        "id": 36,
        "ref": "master",
        "sha": "99d03678b90d914dbb1b109132516d71a4a03ea8",
        "status": "success",
        "updated_at": "2016-08-11T02:12:10.222Z",
        "web_url": "http://gitlab.dev/root/project/pipelines/12"
      
    ,
    "environment": 
      "external_url": "https://about.gitlab.com",
      "id": 9,
      "name": "production"
    ,
    "id": 41,
    "iid": 1,
    "ref": "master",
    "sha": "99d03678b90d914dbb1b109132516d71a4a03ea8",
    "user": 
      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
      "id": 1,
      "name": "Administrator",
      "state": "active",
      "username": "root",
      "web_url": "http://localhost:3000/root"
    
  ,
  
    "created_at": "2016-08-11T11:32:35.444Z",
    "updated_at": "2016-08-11T11:34:01.123Z",
    "deployable": 
      "commit": 
        "author_email": "admin@example.com",
        "author_name": "Administrator",
        "created_at": "2016-08-11T13:28:26.000+02:00",
        "id": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
        "message": "Merge branch 'rename-readme' into 'master'\r\n\r\nRename README\r\n\r\n\r\n\r\nSee merge request !2",
        "short_id": "a91957a8",
        "title": "Merge branch 'rename-readme' into 'master'\r"
      ,
      "coverage": null,
      "created_at": "2016-08-11T11:32:24.456Z",
      "finished_at": "2016-08-11T11:32:35.145Z",
      "id": 664,
      "name": "deploy",
      "ref": "master",
      "runner": null,
      "stage": "deploy",
      "started_at": null,
      "status": "success",
      "tag": false,
      "user": 
        "id": 1,
        "name": "Administrator",
        "username": "root",
        "state": "active",
        "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
        "web_url": "http://gitlab.dev/root",
        "created_at": "2015-12-21T13:14:24.077Z",
        "bio": null,
        "location": null,
        "public_email": "",
        "skype": "",
        "linkedin": "",
        "twitter": "",
        "website_url": "",
        "organization": ""
      ,
      "pipeline": 
        "created_at": "2016-08-11T07:43:52.143Z",
        "id": 37,
        "ref": "master",
        "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
        "status": "success",
        "updated_at": "2016-08-11T07:43:52.143Z",
        "web_url": "http://gitlab.dev/root/project/pipelines/13"
      
    ,
    "environment": 
      "external_url": "https://about.gitlab.com",
      "id": 9,
      "name": "production"
    ,
    "id": 42,
    "iid": 2,
    "ref": "master",
    "sha": "a91957a858320c0e17f3a0eca7cfacbff50ea29a",
    "user": 
      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
      "id": 1,
      "name": "Administrator",
      "state": "active",
      "username": "root",
      "web_url": "http://localhost:3000/root"
    
  
]

const result = data.map(d => (
  id: d.id,
  ref: d.ref,
  environmentName: d.environment.name,
  status: d.deployable.status,
  deployableTag: d.deployable.tag
))

console.log(result)

【讨论】:

以上是关于如何从 axios 响应对象中的所有项目中提取特定值到 vuex 状态的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Express 和 Axios 从我的 get 请求发送响应对象到前端?

如何在 Vue 和 Axios 中循环访问 API 端点 JSON 对象?

如何从 JMeter 的 json 响应中的长 html 内容中提取特定的 *token* 值

如何从我得到的数组中获取特定的数组元素作为调用 axios.get() 调用的函数的响应 [重复]

Vue.js:如何将特定对象中的布尔字段从 false 更改为 true @click 处于突变状态和带有动作 axios 的服务器?

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