在循环中创建承诺

时间:2017-01-16 12:43:07

标签: node.js es6-promise

我必须根据给定的配置文件在循环中创建promises,并在解决所有问题后返回响应。这是代码 -

{for(let type in spotlight){
    switch (type){
        case "outliers":{
                let ops= spotlight[type];
                for(let i=0;i<ops.length;i++){
                    (function(op){
                        let p= new Promise(function(resolve,reject){
                            let reqUrl= urlCreator(op.uri,op.query);
                            //console.log("--------------------"+reqUrl);

                            apiService.get(reqUrl,function(isSuccess,data){
                                if(!isSuccess){
                                    return reject(data);
                                }
                                // console.log(isSuccess);
                                // console.log(data);
                                // console.log("trend is ------"+JSON.stringify(op));
                                // create objects array
                                // let temp= [];
                                // let overallScore= data.overall.score;
                                // for(let day in overallScore){
                                //     temp.push({"key": day,"value": parseFloat(overallScore[day])});
                                // }
                                //let outliers= stats.outliers(temp,"key","value");
                                resolve({"type":type,"name": op.name,"data": outliers});

                            })
                        });
                        promiseArray.push(p);   
                    }(ops[i]))           
                }
                break;    
            }

        case "filters":{
                let ops= spotlight[type];
                for(let i=0;i<ops.length;i++){
                    (function(op){
                        let p= new Promise(function(resolve,reject){
                            let reqUrl= urlCreator(op.uri,op.query);
                            apiService.get(reqUrl,function(isSuccess,data){
                                if(!isSuccess){
                                    return reject(data);
                                }
                                // console.log(isSuccess);
                                // console.log(data);
                                // console.log("coc is ------"+JSON.stringify(op));
                                resolve({"type": type,"name": op.name,"data": data});

                            })
                        })
                        promiseArray.push(p);
                    }(ops[i]))
                }
             break;     
            }   
    }
}

Promise.all(promiseArray).then(values=>{
    return res.json(values); 
},
reason=>{

    return res.json(reason);
}).catch(reason=>{
    return res.json(reason);
})}

问题在于承诺永远不会回归,既不会解决也不会被拒绝。
根据配置文件,它必须打两个URL,比如u1和u2。我尝试记录输出以查看返回的请求。当服务器启动并且第一次执行req时,U1返回并且req挂起。在刷新时我得到U2,U2和请求挂起的响应,然后再次刷新U1,U1,这继续。在我看来,由于某种原因,只返回一个请求而其他请求在缓冲区或其他东西中,并在下一个请求发出时出现。这两个请求都只发送到本地服务器,我在外部路由它只是为了利用缓存,因为url被用作缓存的密钥。
我尝试使用像facebook.com和google.com这样的虚拟网址,它运行得非常好。使用一个本地网址和另一个像facebook.com也可以使用,但当两个网址都是本地服务器时,它会卡住。
是否与节点的单线程特性或由于使用相同的套接字来进行两个请求有任何关系 PS-我正在使用npm-request进行URL调用。

2 个答案:

答案 0 :(得分:0)

在提出第二个请求之前犹豫不决可能会解决您的问题。

我已经制作了一些可以帮助解决这个问题的工具。请参阅

中的MacroQTools.js文件

https://github.com/J-Adrian-Zimmer/JavascriptPromisesClarified.git

答案 1 :(得分:0)

您将request回调定义为function(success , data),而request使用错误优先回调,定义为function(error , response)

您正在呼叫请求:

apiService.get(reqUrl,function(isSuccess,data){
    if(!isSuccess){
        return reject(data);
    }
    // console.log(isSuccess);
    // console.log(data);
    // console.log("coc is ------"+JSON.stringify(op));
    resolve({"type": type,"name": op.name,"data": data});

});

假装,如果第一个参数未命中,则必须使用第二个参数data拒绝它。虽然,实际上,它会像:

    apiService.get(reqUrl,function(err,data){
    if(err){
        reject(err);
    }
    else{
        // console.log(isSuccess);
        // console.log(data);
        // console.log("coc is ------"+JSON.stringify(op));
        resolve({"type": type,"name": op.name,"data": data});
    }

});

因为request需要错误优先回调(就像接受回调的节点中的几乎任何东西一样)。

因此,当请求实际按预期工作时,您的代码必须实际上拒绝具有实际实际值的承诺,因为当request有效时,isSuccess为空且data有真正的反应价值。

这肯定会破坏某些东西并且不好,而修复它可能并不能完全解决你的问题:我相信你的请求很奇怪,因为api的某些配置问题,不仅仅是因为您在请求成功时拒绝承诺(这只是send数据作为拒绝原因。)

此外,您还要处理两次拒绝Promise.all(),将第二个处理程序传递给then并再次调用catch。只需要一个,.catch(handler) is probably better

我就如何使用Promise.all收集异步请求做了一个小小的工作示例。我使用imdb作为apiService,但任何异步http服务都可以使用。我没有完全从您的代码中重现,但我确信您可以对其进行调整以使您的代码正常工作,至少是代码中仅消耗http服务的部分。

var express = require('express');
var app = express();
var Promise = require('bluebird');
var imdb = require('imdb-api');

app.get('/', controllerHandler );

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
});


var apiService = {}
apiService.get = imdb.getReq;


function controllerHandler(request , response){
    //like iterating through spotlight.type and returning an array of promises from it.
    //in this case the array is from films and Airbag is obviously the best of them
    var promises = [{name : 'The Matrix'} , { name : 'Avatar'} , {name : 'Airbag'}].map( createPromise );

    //use either .catch(errorHandler) or then( successHandler , errorHandler ). The former is the better:
    Promise.all(promises).then( successHandler ).catch( errorHandler );

    function successHandler(result){
        return response.json(result);
    }

    function errorHandler(reason){
        console.log('There was an error calling to the service:');
        console.log(reason);
        return response.send('there was an error');
    }
}

function createPromise(film){
    return new Promise( function(resolve , reject){
        apiService.get(film , function(err , data){
            if(err)
                reject( new Error(err));
            else
                resolve( {title : data.title , year : data.year} );
        });
    });
};