Skip to content

思路: pool为多少,就创建多少个工作区,每个工作区最多只有一个任务,任意一个工作区执行完任务后如果是成功的就继续添加任务执行, 到最后发现没有任务了 --> 成功 一旦中间过程有某个任务失败 --> 失败

javascript
function createRequest (tasks, pool) {
  pool = pool || 5
  let result = [],
    together = new Array(pool).fill(null),
    index = 0

  together = together.map(() => {
    // 通过Promise判断成功还是失败
    return new Promise((resolve, reject) => {
      const run = function run () {
        if (index >= tasks.length) {
          // 所有任务都能执行完,说明成功了
          resolve()
          return
        }
        // 取出任务
        let indexBackUp = index,
          task = tasks[index++]

        task().then(val => {
          // 如果成功,添加结果,保证结果顺序
          result[indexBackUp] = val
          // 成功了递归执行下一个任务
          run()
        }).catch(reason => {
          // 有一个失败,整个工作区都失败
          reject(reason)
        })
      }
      run()
    })
  })

  return Promise.all(together).then(() => result)
}

createRequest(tasks, 2).then(val => {
  // 都成功,整体才成功,按顺序存储结果
  console.log(val)
}).catch(reason => {
  // 只要有一个失败,整体就是失败
  console.log(reason)
})

思路: 只有一个工作区, 开始没有任务, 每次放入一个任务并尝试执行 如果能执行说明

js
function createRequest2 (tasks, pool, callback) {
  if (typeof pool === 'function') {
    callback = pool
    pool = 2
  }
  if (typeof pool !== 'number') pool = 2
  if (typeof callback !== 'function') callback = Function.prototype

  class TaskQueue {
    // 执行的任务总数
    running = 0
    // 任务队列
    queue = []
    // 结果数组
    result = []

    pushTask (task) {
      let self = this
      self.queue.push(task)
      // 每次放入一个任务都尝试执行
      self.next()
    }

    // 执行
    next () {
      let self = this
      // 执行任务的条件
      while(self.running < pool && self.queue.length) {
        // 执行数量+1
        self.running++
        // 从任务队列中取出该任务执行
        let task = self.queue.shift()
        task().then(val => {
          // 成功则保存结果
          self.result.push(val)
        }).finally(() => {
          // 不管成功/失败, 这个任务都执行完了
          self.running--
          // 执行下一个任务
          self.next()
        })
      }
      console.log(self.running)
      if (self.running === 0) callback(self.result)
    }

  }

  let taskQueue = new TaskQueue
  tasks.forEach(task => taskQueue.pushTask(task))


}

createRequest2(tasks, 2, val => {
  console.log(val)
})

使用队列, 初始化时任务进队直到队列满, 执行队列任务直到所有任务执行完, 再进队...

js
class Queue {
  constructor (limit) {
    this.queue = []
    this.limit = limit ? limit : Number.MAX_SAFE_INTEGER
  }

  offer (val) {
    if (this.size() >= this.limit) {
      return false
    } else {
      this.queue.push(val)
      return true
    }
  }

  poll () {
    if (this.isEmpty()) {
      return null
    } else {
      return this.queue.shift()
    }
  }

  peek () {
    if (this.isEmpty()) {
      return null
    } else {
      return this.queue.shift()
    }
  }

  peek () {
    if (this.isEmpty()) {
      return null
    } else {
      let { queue } = this
      return queue[queue.length - 1]
    }
  }

  size () {
    return this.queue.length
  }

  isEmpty () {
    return this.size() === 0
  }
}
javascript
class Scheduler {
  constructor (tasks, limit, cb) {
    this.originalTask = tasks
    this.tasks = tasks.slice()
    this.cb = cb
    this.limit = limit
    this.result = []
    this.queue = []

    // 装载任务
    this.load()
  }

  load () {
    const { tasks, queue, limit } = this
    let task = null
    
    // 装满
    while (queue.length < limit && tasks.length > 0) {
      queue.unshift(tasks.shift())
    }

    // 清空任务
    this.flush()
  }

  flush () {
    const { queue, result, cb, limit, originalTask } = this
    let running = 0

    // 所有任务都执行完了
    if (!queue.length) {
      return cb(result)
    }

    while (queue.length) {
      
      // 取出任务并执行
      const task = queue.shift()
      const index = originalTask.indexOf(task)
      task().then(val => {

        // 保存结果
        result[index] = val
        running++

        if (running === limit) {
          // 重新装载任务
          this.load()
        }
      }, reason => {
        return callback(reason)
      })
    }
  }
}

function scheduler (tasks, limit, callback) {
  new Scheduler(tasks, limit, callback)
}

scheduler(tasks, 1, val => {
  console.log(val)
})