ES6 Dyanmic Promise链接来自阵列

时间:2017-06-06 08:08:55

标签: javascript node.js ecmascript-6 promise es6-promise

方案

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

问题

当我遍历数组时,我需要等待事务ID的请求和文件的请求在开始下一次循环迭代之前完成,但是文件的数量没有固定,所以需要动态构建一连串的承诺。

伪代码

下面是一些伪代码,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));
    }
}

问题

如何动态链接承诺链?

答案

以下是JSFiddle Ovidiu's回答的<{3}}

4 个答案:

答案 0 :(得分:6)

一种功能方法是使用reduce迭代并返回从每个子承诺链接的最终承诺。它还有助于构建结果,例如在数组中:

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);
    }
}

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

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

答案 1 :(得分:0)

你可以沿着这些方向做点什么

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);
    })
}

答案 2 :(得分:0)

尝试使用async / await。

了解更多here

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)
}
}

答案 3 :(得分:-1)

如果通过同步执行程序nsynjs运行逻辑,则可以简化逻辑。当某个函数计算为promise时,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);
    };
};