ES6 Dyanmic Promise从arrays链接

脚本

我有一个我需要下载的URL数组,但每个都必须提供唯一的事务ID,必须从服务器请求,并且只有在请求成功时才会增加。

问题

当我循环访问数组时,我需要等待事务ID的请求和文件的请求,然后开始下一个迭代循环,但是文件的数量不是固定的,所以需要dynamic地构build一个链承诺。

伪代码

下面是一些伪代码,getFiles()是问题,因为所有的请求获得相同的事务ID,因为他们不等待前一个请求完成。

function getTransationId(){ return new Promise((resolve,reject)=> { let id = getNextTransactionId(); if(id!=error){ resolve(id); }else{ reject(error); } }) } function getFile(url, transactionId){ return new Promise((resolve,reject)=>{ http.request(url+transactionId, function(err,response){ if(err){ reject(err); }else{ resolve(response); } }); }); } function getFilesFromArray(urlArray){ for(let url of urlArray){ getTransactionId().then(resolve=>getFile(url,resolve),reject=>console.error(reject)); } } 

我如何dynamic链式承诺?

回答

这是一个Ovidiu的回答JSFiddle

一个function性的方法是使用reduce来迭代并返回从每个子promise中链接的最终promise。 它也帮助build立结果,例如在一个数组中:

 function getFilesFromArray(urlArray){ const filesPromise = urlArray.reduce((curPromise, url) => { return curPromise .then(curFiles => { return getTransactionId() .then(id => getFile(url, id)) .then(newFile => [...curFiles, newFile]); }); }, Promise.resolve([])); filesPromise.then(files => { console.log(files); } } 

这有效地build立了一个承诺链:

  • 以静态Promise开始,值为[]代表最初的一组文件: Promise.resolve([])
  • 在每次迭代中,返回一个承诺,等待链中的curPromise ,然后
  • 执行getTransactionId并使用该id到getFile
  • 一旦文件将被检索,它将返回一个数组,其中包含curFiles设置的curPromise (以前的值),并将newFile连接到它
  • 最终的结果将是一个单一的承诺,收集所有文件

你可以按照这些方法做一些事情

 function getAllFiles(i, results, urlArray) { if(i == urlArray.length) return; getTransationId().then(id => { return new Promise((resolve, reject) => { http.request(urlArray[i] + id, (err, response) => { if(err){ reject(); }else{ results.push(response); resolve(); } }); }); }).then(() => { getAllFiles(i + 1, results, urlArray); }) } 

尝试使用asynchronous/等待。

在这里阅读更多

 async function getFilesFromArray(urlArray) { for(let url of urlArray){ //wrap this in a try/catch block if you want to continue with execution //if you receive an error from one of the functions const transactionId =await getTransactionId() const file = await getFile(url,transactionId) } } 

如果通过同步执行程序nsynjs运行它,则可以简化逻辑。 Nsynjs会暂停一些函数评估,然后将结果赋值给data属性。 代码将如下变换:

 function getFilesFromArray(urlArray){ for(var i = 0; i<urlArray.length; i++) { var trId = getTransactionId().data; // trId is ready here var fileContent = getFile(urlArray[i],trId).data; // file data is ready here console.log('fileContent=',fileContent); }; }; nsynjs.run(getFilesFromArray,{},urls,function(){ console.log('getFilesFromArray is done'); }); 

getFilesFromArray可以进一步简化为:

 function getFilesFromArray(urlArray){ for(var i = 0; i<urlArray.length; i++) { var fileContent = getFile(urlArray[i],getTransactionId().data).data; console.log('fileContent=',fileContent); }; };