43

请排好队,一个一个的来 --- 基于Promise.all()实现并发控制

 4 years ago
source link: https://db324246.github.io/2020/03/04/请排好队,一个一个的来 --- 基于Promise.all()实现并发控制/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

前几天看了作者 zz_jesse写给新手前端的各种文件上传攻略,从小图片到大文件断点续传 ,学习了很多有关上传的知识点。但在大文件分片上传一块,作者有提及分片上传需要做并发限制处理,但他的demo并没有做。抱着学习的心态,我又去网上学习了一番。。

IRjEZji.jpg!web

Promise.all()

Promise.all() 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。

const p = Promise.all([p1, p2, p3]);

上面代码中, Promise.all() 方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,再进一步处理。另外, Promise.all() 方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。

p的状态由p1、p2、p3决定,分成两种情况。

(1)只有p1、p2、p3的状态都变成 fulfilled ,p的状态才会变成 fulfilled ,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。

(2)只要p1、p2、p3之中有一个被 rejected ,p的状态就变成 rejected ,此时第一个被 reject 的实例的返回值,会传递给p的回调函数。

Code

  const requestsLimit = (list, limit, asyncHandle) => {
    return new Promise(resolve => {
      let _limit = limit;
      let recordList = []; // 记录异步操作
      let index = 0;
      let listCopy = [].concat(list);
      let asyncList = []; // 正在进行的所有并发异步操作


      const asyncFunc = () => {
        while(_limit--) {
          const data = listCopy.shift()
          if (data) asyncList.push(asyncHandle(data, index++)); 
        }
        
        Promise.all(asyncList).then(response => {
          // 监听并记录每一次请求的结果
          recordList = recordList.concat(response.filter(item => item));


          if (listCopy.length !== 0) {
            _limit = limit;
            asyncList = [];
            asyncFunc() // 数组还未迭代完,递归继续进行迭代
          } else {
            // 所有并发异步操作都完成后,本次并发控制迭代完成,返回记录结果
            resolve(recordList)
          }
        })
      }


      asyncFunc()
    })
  }


  var dataLists = [1,2,3,4,5,6,7,8];
  
  requestsLimit(dataLists, 3, (item, index) => {
    return new Promise(resolve => {
      // 执行异步处理
      setTimeout(() => {
        // 筛选异步处理的结果
        console.log(index)
        if (item % 2 === 0) resolve({ item, index })
        else resolve()
      }, Math.random() * 5000)  
    });
  }).then(response => {
    console.log('finish', response)
  })

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK