关于js promise队列的疑问

学习promise的过程中遇到一个关于队列的问题,在开发中遇到一个问题,需要循环请求上传的接口,但是下面的的方法好像没有做到队列,跪求大神帮我改造

需求是执行完一个再执行一个,直到最后一个,串行,对列的概念也不是很懂

function queue(files) {
  let promise = Promise.resolve();
  files.forEach(file => {
    promise = promise.then(() => {
      return new Promise(resolve => {
         doThing(file, () => {
           //上传操作,访问接口
             resolve();
           });
      });
    });
  });
  return promise;
}

queue([file1, file2, file3]).then(data => {
  console.log(data);
});
阅读 3.5k
6 个回答

一个promise的resolve只能使用一次,第二次以后的使用都是无效的
你需要RxJs

问题是,这不是队列,而是foreach执行promise,递归一下就好了。

function doThing(file) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log('doThing', file)
      resolve('result:' + file)
    }, 500)
  })
}

function queue(files, data = []) {
  return new Promise((resolve) => {
    if (files.length > 0) {
      let file = files.shift();
      doThing(file).then((res) => {
        data.push(res)
        resolve(queue(files, data))
      })
    } else {
      resolve(data)
    }
  })
}

queue(['file1', 'file2', 'file3']).then(data => {
  console.log(data);
});

不知道,你是不是要达到 串行上传还是并行上传的目的 ?

// 下面是串行上传的
function queue(arr, handle) {
let index = 0
let length = arr.length

return new Promise((resolve, reject) => {

!(function next() {
  try {
    handle(arr[index])
      .then(function () {
        ++index < length
          ? next()
          : resolve()
      })
      .catch(reject)
  } catch (err) {
    reject(err)
  }
})()

})
}

function upload(file) {
return new Promise((resolve, reject) => {

// 上传文件
setTimeout(function () {
  console.log(`upload ${file}`)
  resolve()
}, file * 1000 )

})
}

queue(['3', '2', '1'], upload).then(data => {
console.log('ok');
}).catch(err => {
console.log('error', err)
})

楼主我来对你的代码做点注释,你自己再看看问题出在哪里

// 定义一个队列构造器
function queue(files) {

  // 使用Promise.resolve(val)生成一个Promise实例promise
  // promise的状态已转换为Resolved状态,
  // 这时promise仍可通过then方法获取到Resolved的结果val(这里的val为空,所以是undefined)
  let promise = Promise.resolve(); 
  
  // 遍历一次传入的数组
  files.forEach(file => {

    // promise对象添加then方法,并将then方法的返回值重新赋值给promise并传入resolve回调,
    // 因为只传了一个函数(这个函数没有参数,所以没法捕获上一次操作完成返回的值,
    // 事实上,楼主也没有在每次完成返回值,因为resolve()中没有给值。)参数,
    // 所以reject的回调为undefined
    promise = promise.then(() => { 

    // then.resolve回调中返回了一个新的Promise实例,新的实例通过构造的方式生成,
    // 构造传入了"resolve"这样一个名字的函数参数,作为promise的resolve回调,没有reject
      return new Promise(resolve => { 

         // 新构造的Promise实例的resolve回调中执行异步上传方法
         doThing(file, () => { 
             
             //上传操作,访问接口

             // 上传完成resolve这个promise,但是没有给下一个操作传入值,
             // 所以最后调用的data为空
             resolve();
           });
      });
    });
  });
  // 返回了新的promise引用,事实上,这个promise引用就已经是个队列了
  return promise;
}

// 这一步调用之后,做了什么事情?从这里再看这个queue内部的执行过程,
// 调用之后,第一个上传文件的操作就会立即启动,上传完成之后就会继续上传下一个,
// 直到这数组中都传完, 最后一个操作的resolve被下面这个then捕获
queue([file1, file2, file3]) 

//获取了最后一个promise实例成功后resolve的值
.then(data => { 

  // 打印resolve的值
  console.log(data); 
});

另外,我这里还有个学习promise做的笔记,你可以回顾下
我的Promise笔记

题主你队列的做法没问题,只是最后没有返回 data 而已。如果你需要 data 的话,可以在 resolve() 里返回。

另外自荐一下我的讲堂:Promise 的 N 种用法,里面除了详细介绍了 Promise 的各种用法,还专门写了两种队列的处理。

推荐问题
宣传栏