liuguanyu / quiz-every-meeting

8 stars 0 forks source link

2018-10-18 顺序并发请求 #36

Open liuguanyu opened 5 years ago

liuguanyu commented 5 years ago

请实现顺序请求一组url的方法:

function seqRequest(urls: string[], parallel:number=1):Promise;

interface Ret {
    response_content: string
}

要求: 1、urls是数组,为一组网址。 2、parallel为并发访问的数量,要求依照urls的顺序,每次同时执行parallel个请求,默认为1。 3、返回值为Promise,success时候可以获得所有的结果,形为:Ret[],数组顺序和urls给定顺序一致。 4、任意一个url访问错误,即判定访问错误,可Promise的fail分支。 5、当urls中尚未访问的url数量小于parallel数量时候,则以剩余url数量并发访问即可。

function seqRequest(urls, parallel=1){

}
chunpu commented 5 years ago
点开是答案 ```js function delay(val, cb) { console.log('start', val) setTimeout(() => { if (val === 3) { cb('error') } else { cb(null, val) } }, 1000) } function mapLimit(arr, fn, cb, limit = 1) { var ret = [] var startCount = 0, execCount = 0, doneCount = 0 var hasDone, hasStart function exec() { for (let i = startCount; i < arr.length; i++) { if (execCount >= limit) return hasStart = true execCount++ startCount++ fn(arr[i], function(err, val) { if (hasDone) return execCount-- doneCount++ if (err) { hasDone = true return cb(err) } ret[i] = val if (doneCount === arr.length) { hasDone = true cb(null, ret) } else { exec() } }) } } exec() if (!hasStart) cb(null) // empty } function seqRequest(urls, parallel=1){ return new Promise((resolve, reject) => { mapLimit(urls, delay, (err, ret) => { if (err) { reject(err) } else { resolve(ret) } }, parallel) }) } seqRequest([1, 2, 3, 4, 5]).then(data => { console.log(data) }).catch(err => { console.error(err) }) ```
liuguanyu commented 5 years ago
const axios = require("axios")
let rets = []

const _seqRequest = (urls) => {
  console.log("**REQUESTING__" + urls.toString() + "**")
  return urls.map(el => axios.get(el, {
    timeout: 1000
  }))
}

const seqRequest = (urls, parallel = 1) => {
  let head = urls.slice(0, parallel)
  let tail = urls.slice(parallel)

  return Promise.all(_seqRequest(head))
    .then(response => {
      rets = response.reduce((prev, curr) => {
        prev = prev.concat({response_content:curr.data.toString()})
        return prev
      }, rets)

      return (tail.length) ? seqRequest(tail, parallel) : rets
    })
    .catch(err => {
      throw new Error(err)
    })
}
// 测试
const tester = (urlsOK, urlsFail) => {
  seqRequest(urlsOK, 3)
    .then(data => {
      console.log(data)

      console.log("============\n")

      seqRequest(urlsFail, 3)
        .then(data2 => {
          console.log(data2)
        })
        .catch(err => {
          console.log(err)
        })
    })
    .catch(err => {
      console.log(err)
    })
}

tester([
  "https://hq.sinajs.cn/?list=gb_sohu",
  "https://hq.sinajs.cn/?list=gb_sina",
  "https://hq.sinajs.cn/?list=gb_jd",
  "https://open.onebox.so.com/index/getCurr?kw=1%7CUSD%7CCNY"
], [
  "https://hq.sinajs.cn/?list=gb_sohu",
  "https://www.111.222.com/?list=gb_sina", // 不合法网址
  "https://hq.sinajs.cn/?list=gb_jd",
  "https://open.onebox.so.com/index/getCurr?kw=1%7CUSD%7CCNY"
])
mileOfSunshine commented 5 years ago
const axios = require("axios")

axios.interceptors.response.use(response => {
  if (response.status !== 200) {
    return Promise.reject(response)
  }
  return response.data
}, err => {
  return Promise.reject(err)
})

function seqRequest(urls, parallel=1){

  // 分组
  function chunk(arr, size) {
    return Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => arr.slice(size * i, size + size * i)
    )
  }

  var urlChunk = chunk(urls, parallel)

  return new Promise((resolve, reject) => {
    var ret = [], i = 0

    function doRequest() {
      Promise.all(urlChunk[i].map( url => axios.get(url))).then(result => {
        ret = ret.concat(result)
        if (ret.length === urls.length) {
           resolve(ret)
        }
        i++
        doRequest()
      }).catch(err => {
        reject(err)
      })
    }
    doRequest()
  })
}

// 测试数据
var urls = [1, 2, 3, 4, 5, 6, 7].map(v => `https://cnodejs.org/api/v1/topics?limit=1&page=${v}`)

seqRequest(urls, 2).then(data => {
  console.log('success~')
  data.map(result => {
    console.log(result.data[0])
  })
}).catch(err => {
  console.log('fail!!!', err)
})
tataqiuqiu commented 5 years ago
import axios from 'axios'
import _ from 'lodash'

function all(list, fn, fail){
  if (index >= list.length) {
    return fn(result)
  }

  const getArray = list[index].map(( item )=>{
    return axios.get(item)
  })

  Promise.all(getArray)
    .then((data)=>{
      result = [...result, ...data]
      index++
      setTimeout(function(){
        all(list, fn, fail)
      }, 1000)
    }, ()=>{
      fail('访问错误')
    })
}

function seqRequest(urls, parallel=1){
  const _newUrls = _.chunk(urls, parallel)
  return new Promise((success, fail) => {
    all(_newUrls, success, fail)
  })
}

const index = 0;
const result = [];
const _urls = ['/api/1', '/api/2', '/api/3']
const _parallel = 2;

seqRequest( _urls, _parallel)
  .then((data) => {
    console.log(data)
  }, (error) => {
    console.log(error)
  })