使用 array.map、promises 和 setTimeout 更新数组

Posted

技术标签:

【中文标题】使用 array.map、promises 和 setTimeout 更新数组【英文标题】:Using array.map, promises, and setTimeout to update an array 【发布时间】:2019-02-01 11:21:56 【问题描述】:

我希望遍历用户数组(仅设置 id 属性),每两秒使用每个 id 调用一个端点,并将响应中的关联用户名存储到更新数组。

例如更新 [ id: 1 ] [ id: 1, name: "Leanne Graham" ]

这是我的代码:

const axios = require('axios');

const users = [ id: 1 ,  id: 2 ,  id: 3 ];

function addNameToUser(user) 
  return new Promise((resolve) => 
    axios.get(`https://jsonplaceholder.typicode.com/users/$user.id`)
      .then(response => 
        user.name = response.data.name
        resolve(user);
      );
  )


const requests = users.map((user, index) => 
  setTimeout(() => 
    return addNameToUser(user);
  , index * 2000);
);

Promise.all(requests).then((updatedArr) => 
  console.log(updatedArr);
);

没有setTimeout,一切都很好,但重要的是我只每两秒发送一个请求。所以对于三个用户,我想在六秒左右后从我的Promise.all 日志中看到结果。

值得注意:这不是我正在处理的实际问题,而是我能想出的最简单的例子来帮助突出这个问题。

【问题讨论】:

***.com/questions/23803743/… 您的意思是请求 user1 并等待 2 秒,请求 user1 并等待 2 秒,...或请求 user1 结束并等待 2 秒,... 【参考方案1】:

据我了解,您问题的核心是如何将您的处理间隔 2 秒,对吧?

const users = [ id: 1 ,  id: 2 ,  id: 3 ];

/* throttledProcess is a function that does your processing spaced by the given interval millisecond */
const throttledProcess = (items, interval) =>   
  if (items.length == 0)  // stop when there's no more items to process
    console.log('ALL DONE')
    return
    
  console.log('PROCESSING', items[0], Date()) // this is where your http call/update/etc takes place
  setTimeout(() => throttledProcess(items.slice(1), interval), // wrap in an arrow function to defer evaluation
    interval)


throttledProcess(users, 2000) // run process. shows output every 2 seconds

运行此代码,每 2 秒,它将注销正在处理的用户。

希望这会有所帮助。 干杯,

【讨论】:

【参考方案2】:

您需要从地图的回调中返回一个 Promise。由于此承诺将由setTimeout() 解决,因此我们将使用Promise constructor。

已解决的超时承诺应返回 Axios 承诺,该承诺将在解决时返回结果。

注意:由于 Axios 返回一个 Promise,我们不需要用另一个 Promise 构造函数包装它。见What is the explicit promise construction antipattern and how do I avoid it?问答。

const users = [ id: 1 ,  id: 2 ,  id: 3 ];

const addNameToUser = (user) => 
  axios.get(`https://jsonplaceholder.typicode.com/users/$user.id`)
  .then(( data ) => (
    ...user,
    name: data.name
  ));

const requests = users.map((user, index) =>
  new Promise(resolve => 
    setTimeout(() => resolve(addNameToUser(user)), index * 2000)
  ));

Promise.all(requests).then((updatedArr) => 
  console.log(updatedArr);
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.min.js"></script>

【讨论】:

以上是关于使用 array.map、promises 和 setTimeout 更新数组的主要内容,如果未能解决你的问题,请参考以下文章

使用 Array.map 时嵌套承诺,使用 Promise.all 但仍然无法正常工作

处理 Array#map 中的 async/await 中的错误(拒绝)

向返回承诺数组的 Array.map 调用添加毫秒延迟

Node.JS:写入文件时,Promise 产生 null

即使 .map 循环通过数组的所有索引,也无法在我的 React 应用程序中的 array.map 中显示我的 JSX 中的图像

React:使用 array.find 和 array.map 方法设置状态有啥区别? [复制]