js怎么实现一个一个发送请求,连续发送几十次?

本来想用Promise.all去一下请求几十次,但是对面返回错误码,说请求太频繁。

之后想用for循环,然后中间sleep一秒钟,但是js没有sleep方法。

请问有没有什么好的方法呢

阅读 6.7k
12 个回答

js 有 setTimeout 用于延迟执行(还有一个 setInterval 用于定时重复执行)

写法一,设置 n 个 timeout

for (let i = 0; i < 10; ++i)
  setTimeout(fn(i), i * 1000)

写法二,timeout 循环

const repeat = (fn, times, timeout = 1000, i = 0) => {
  fn(i)
  if (++i < times)
    setTimeout(repeat, timeout, fn, times, timeout, i)
}

repeat(fn, 10)

写法二进阶,支持设置第一次执行的延迟,支持取消执行

const repeat = (fn, times, timeout = 1000, firstTimeout = 0) => {
  let i = 0
  let tid = setTimeout(function loop() {
    fn(i)
    if (++i < times)
      tid = setTimeout(loop, timeout)
  }, firstTimeout)
  return () => clearTimeout(tid)
}

const cancel = repeat(fn, 10, 1000, 2000)

写法三,把 setTimeout 包装为 sleep

const sleep = timeout => new Promise(resolve => setTimeout(resolve, timeout))

for (let i = 0; i < 10; ++i) {
  fn(i)
  await sleep(1000)
}

// 最后一次执行后不 sleep
// for (let i = 0;; await sleep(1000)) {
//   fn(i)
//   if (++i == 10) break
// }

写法二进进阶,支持获取全部执行结果

const repeat = (fn, times, timeout = 1000, firstTimeout = 0) => {
  let tid
  return [
    () => clearTimeout(tid),
    new Promise(resolve => {
      const promises = []
      let i = 0
      tid = setTimeout(function loop() {
        promises.push(fn(i))
        if (++i < times) tid = setTimeout(loop, timeout)
        else resolve(Promise.all(promises))
      }, firstTimeout)
    })
  ]
}

const [cancel, promise] = repeat(fn, 10, 1000, 2000)
const res = await promise
console.log(res)

// cancel 时获取之前的执行结果
// const repeat = (fn, times, timeout = 1000, firstTimeout = 0) => {
//   const promises = []
//   let finish
//   let tid
//   return [
//     () => {
//       clearTimeout(tid)
//       finish()
//     },
//     new Promise(resolve => {
//       finish = () => resolve(Promise.all(promises))
//       let i = 0
//       tid = setTimeout(function loop() {
//         promises.push(fn(i))
//         if (++i < times) tid = setTimeout(loop, timeout)
//         else finish()
//       }, firstTimeout)
//     })
//   ]
// }

写法一进阶,支持获取全部执行结果

await Promise.all(Array.from({ length: 10 }, (_, i) => new Promise(resolve => setTimeout(() => resolve(fn(i)), i * 1000))))

没有就写一个

const sleep = second => new Promise(resolve => setTimeout(resolve, second*1000));

for (...) {
    // dosomthing...
    await sleep(1)
}

p-limit 就是你想要的。已经有现成的了.

image.png

题主问了一个很奇葩的需求,但不管怎么样,按照题主意思,硬要是要使用技术实现的话,可以设计一个请求队列,然后按照一定时间间隔提取队列中的请求发送请求,在逻辑理解和编码处理上都容易

看来你的问题主要是发送请求频繁想使用sleep的方式每隔一秒再发送
可以使用setInterval定时从一个数组中取走一个连接再发送请求

arr = [];
setInterval(function(){
    url = arr.shift();
    do sth...
}, 1000);

arr.push(url1)
arr.push(url2)
...
新手上路,请多包涵

不用异步,用同步请求,可以么?

//模拟请求
    //参数数组假设请求时间不一样
    const arr = [1, 2, 3, 4,2,3,4,1,2,3]
    const ajax=time=>new Promise((res)=>{
      setTimeout(()=>res(time),time*1000)
    })
    //请求函数
    const fn = (arr,idx) => {
      ajax(arr[idx]).then(r=>{
        console.log(r)
        if(arr[idx+1]){
          fn(arr,idx+1)
        }
      })
    }
    //执行
    fn(arr,0)
//控制一个还是比较容易的

直接贴代码:

function makeLoop(fn, delay = 1000, repeatLimit = 10) {
  var index = 0;
  const loop = function () {
    index++;
    if (index > repeatLimit) return;
    fn.apply(this, arguments);
    setTimeout(() => loop.apply(this, arguments), delay);
  };
  return loop;
}

var loop = makeLoop((a,b)=>console.log("打印", a, b), 1000, 5);
loop(1, 2)

在then中发送下一次请求

看了下大家答案...

我不太理解,这么简单的一个小功能,为何引起这么多讨论?

以及众多复杂的解决方案,甚至还要安装一个依赖??

直接 setInterval 不就行了吗???

// 准备一份请求列表
var api_list = [
    'http://xxx.com/api1',
    'http://xxx.com/api2',
    'http://xxx.com/api3',
    ...
]

// 每3秒发送一个请求
var timer = setInterval(()=>{
    var api = api_list.shift();
    if (api===undefined) clearInterval(timer);
    else $.ajax(api);
}, 3000)
新手上路,请多包涵

不能一次性发送N个请求,浏览器有并发限制。维护一个请求池,依次注入/取回完成所有请求。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Microsoft
子站问答
访问
宣传栏