在node.js

时间:2015-10-07 22:58:16

标签: javascript node.js promise q

我是来自java世界的js和节点的新手。我根据我写的真实程序将测试程序放在一起。它在node.js程序中使用Q库。

for循环仅作用于数组中的最后一项..就像所有其他Q.promises都丢失一样。

我的输出是: registerELB 去registerELB resumeASG 4 开始实例4 resumeASG 4 开始实例4 resumeASG 4 开始实例4 resumeASG 4 开始实例4 autoshutdown完成。

我期望它在哪里:

resumeASG 1 开始实例1 resumeASG 2 开始实例2 resumeASG 3 开始实例3 resumeASG 4 开始实例4 registerELB 去registerELB autoshutdown完成。

  1. 循环中发生了什么?承诺是否会丢失?

  2. 为什么registerELB和de-registerELB发生在我的第一次.then()

    之前

    var Q = require('q');     var startedInstances = [];

    test();
    
    function test() {
        getInstances()
        .then(function(data) {
            var promise = Q.defer();
    
            for(var x = 0; x < data.length; x++) {
                var somedata = data[x];
                console.log(somedata);
    
                startOrStop(somedata)
                .then(function (updateStatus) {
                    var promiseinner = Q.defer();
                    console.log(somedata);
                    if(updateStatus == 'start') {
                        return Q.nfcall(resumeASG, somedata)
                        .then(Q.nfcall(startInstance, somedata));
                    } else if(updateStatus == 'stop') { 
                        return Q.nfcall(suspendASG, somedata)
                        .then(Q.nfcall(stopInstance, somedata));
                    }
                    promiseinner.resolve('complete');
    
                    return promiseinner.promise;
                })
            }
            promise.resolve('successful');
    
            return promise.promise;
    
        }, function(error) {
            console.log('Failed to get instance data ' + error);
            //context.fail();
        }).then(function(data) {
            return registerELB();
        }, function(error) {
            console.log('Failed to Re-register ELB ' + error);
            //context.fail();
        }).then(function(data) {
            console.log('autoshutdown complete.')
            //context.succeed(data);
        }, function(error) {
            console.log('autoshutdown failed to complete. ' + error)
            //context.fail();
        }).done();
    };
    
    function getInstances() {
        var promise = Q.defer();
    
        startedInstances.push(1);
        startedInstances.push(2);
        startedInstances.push(3);
        startedInstances.push(4);
    
        promise.resolve(startedInstances);
        return promise.promise;
    }
    
    function suspendASG (asg) {
        var promise = Q.defer();
    
        console.log('suspendASG ' + asg);
        promise.resolve(asg);
    
        return promise.promise;
    }
    
    function resumeASG (asg) {
        var promise = Q.defer();
    
        console.log('resumeASG ' + asg);
        promise.resolve(asg);
    
        return promise.promise;
    }
    
    function registerELB() {
        var promise  = Q.defer();
    
        console.log('registerELB ');
        console.log('de-registerELB ');
        promise.resolve('success elb');
    
        return promise.promise;
    }
    
    function startInstance(instanceId) {
        var promise = Q.defer();
    
        console.log('started instance ' + instanceId);
        promise.resolve(instanceId);
    
        return promise.promise;
    }
    
    function stopInstance(instanceId) {
    var promise = Q.defer();
    
        console.log('stopped instance ' + instanceId);
        promise.resolve(instanceId);
    
        return promise.promise;
    }
    
    function startOrStop (instance) {
        var promise = Q.defer();
    
    
        promise.resolve('start');
    
        return promise.promise;
    }
    

1 个答案:

答案 0 :(得分:4)

这是循环中for循环和任何异步操作的经典问题。因为for循环中的异步操作在for循环完成后的某个时间完成,所以在for循环内设置的任何变量都将在循环结束时具有值。任何异步操作都会完成。

在您的特定情况下,somedata变量是一个问题。您通常可以通过使用闭包来解决此问题,以便异步操作的每次调用都具有自己的功能,因此它自己的状态在异步操作完成之前一直存在。

在我看来,您可能还会遇到其他同步问题,因为您的for循环并行运行所有操作,并且您的内部异步操作与您要解析的外部承诺之间没有任何关联,所以我怀疑这里还有其他问题。

但是,如果您只是将for循环更改为.forEach()循环,则循环的每次调用都将具有自己的唯一状态。老实说,我不能说这段代码中没有其他问题(因为我无法对其进行测试),但至少应该解决与for循环相关的一个问题:

test();

function test() {
    getInstances()
    .then(function(data) {
        var promise = Q.defer();

        // -------- Change made here -------------
        // change for loop to .forEach() loop here
        // to create closure so your async operations
        // each can access their own data
        data.forEach(function(somedata) {
            console.log(somedata);

            startOrStop(somedata)
            .then(function (updateStatus) {
                var promiseinner = Q.defer();
                console.log(somedata);
                if(updateStatus == 'start') {
                    return Q.nfcall(resumeASG, somedata)
                    .then(Q.nfcall(startInstance, somedata));
                } else if(updateStatus == 'stop') { 
                    return Q.nfcall(suspendASG, somedata)
                    .then(Q.nfcall(stopInstance, somedata));
                }
                promiseinner.resolve('complete');

                return promiseinner.promise;
            })
        });
        promise.resolve('successful');

        return promise.promise;

    }, function(error) {
        console.log('Failed to get instance data ' + error);
        //context.fail();
    }).then(function(data) {
        return registerELB();
    }, function(error) {
        console.log('Failed to Re-register ELB ' + error);
        //context.fail();
    }).then(function(data) {
        console.log('autoshutdown complete.')
        //context.succeed(data);
    }, function(error) {
        console.log('autoshutdown failed to complete. ' + error)
        //context.fail();
    }).done();
};

另外,你是否意识到你的内在承诺(在.forEach()循环内)根本没有与外部承诺相关联?那么,getInstances()将在.forEach()循环中的内部承诺完成之前解决它的承诺?这对我来说很糟糕。我不知道究竟应该推荐什么,因为我不知道你想并行运行哪些操作,哪些应该是串联的。您可能需要执行Promise.all()收集来自for循环的所有承诺,然后使用它来解决您的外部承诺。