用承诺打破循环

时间:2021-07-29 11:08:10

In my node js App, I have a function that checks if you have the permissions:

在我的node js应用中,我有一个功能,可以检查您是否有权限:

//queryPermissions is an object that contains all possible permissions:
//each property of queryPermission is an object containing the values to be checked
for (var key in queryPermissions) {
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method));
    }
}

Q.all(promisesArray).then(function(response) {
    response.forEach(function(value) {
        //response is an array with all promises' resolved values
        //if all values are true -> access granted
        //if one or more values are false -> access denied
    }
}

This works good, but if only one of the values returned by checkThis inside the for loop is false, than the result would be access denied; so it is not efficient to continue to check other permissions after the first one that resoves with false; CheckThis returns a promise but sometimes it needs to wait for a query result, sometimes it resolves immediately, it depends.

这工作得很好,但是如果在for循环中checkThis返回的值中只有一个为false,那么结果就是访问被拒绝;因此,在第一个具有false的权限之后继续检查其他权限是不有效的;CheckThis返回一个承诺,但有时它需要等待查询结果,有时它立即解决,这取决于。

Is there a way I can break the loop (if it is not finished yet) when the first "checkThis" returns false?

当第一个“checkThis”返回false时,是否有办法中断循环(如果还没有完成)?

4 个解决方案

#1


2  

Here is an alternative solution to Bergi's approach - we map false return values to the exceptional condition failures they are and use Q.all directly:

这是Bergi方法的另一种解决方案——我们将错误的返回值映射到异常情况下的故障,并使用Q。所有直接:

Your current code does:

你当前的代码:

for (var key in queryPermissions) {
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method));
    }
}

We add an additional step:

我们再增加一个步骤:

for (var key in queryPermissions) {
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method).then(function(val){
             if(!val) throw new Error("Invalid Permissions");
             return true;
        });
    }
}

This simple addition would let us use Q directly:

这个简单的添加可以让我们直接使用Q:

Q.all(promisesArray).catch(function(err){
     // one or more authentication errors
}).then(function(){
      // everyone validated, all ok user authenticated here
});

This is a more general method - using the exception pipeline for exceptional cases can greatly simplify your code.

这是一种更通用的方法——对异常情况使用异常管道可以极大地简化代码。

#2


2  

Not with any native Q function. You could however write an every method for promises yourself (loosely based on Q.all):

没有任何的本地Q函数。然而,你可以为你自己写一个每个承诺的方法(松散地基于Q.all):

Q.every = function every(promises) {
    return Q.when(promises, function (promises) {
        var countDown = 0;
        var deferred = defer();
        for (var i=0; i<promises.length; i++) {
            var promise = promises[i];
            var snapshot;
            if (
                Q.isPromise(promise) &&
                (snapshot = promise.inspect()).state === "fulfilled"
            ) {
                if (!snapshot.value) {
                    deferred.resolve(false);
                    return deferred.promise;
                }
            } else {
                ++countDown;
                q.when(
                    promise,
                    function (value) {
                        if (!value)
                            deferred.resolve(false);
                        else if (--countDown === 0)
                            deferred.resolve(true);
                    },
                    deferred.reject,
                    (function(index) {
                        return function (progress) {
                            deferred.notify({ index: index, value: progress });
                        };
                    }(i));
                );
            }
        }
        if (countDown === 0) {
            deferred.resolve(true);
        }
        return deferred.promise;
    });
}

#3


0  

It's not possible. Indeed, Q.all run parallel promises, so when you want to break, the other promises are still running. So they can't be stopped. One way is to use Q.spread but therefore the promises are no more parallel :(.

这是不可能的。事实上,问。所有的承诺都是并行的,所以当你想要违背的时候,其他的承诺仍然在运行。所以他们不能被阻止。一种方法是用Q。传播但因此承诺不再是平行的:(。

#4


0  

Maybe I had a sudden enlightment but was not so hard: just using a global flag:

也许我突然得到了启发,但并没有那么困难:仅仅使用一个全球旗帜:

var alreadyFailed = false;

//queryPermissions is an object that contains all possible permissions:
//each property of queryPermission is an object containing the values to be checked
for (var key in queryPermissions) {
    if (alreadyFailed) {
        break;
    }
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method));
    }
}

Then it is sufficient to set alreadyFailed to true inside checkThis when a false result occurs; of course it can happen that the for loop ends before the first resolve to false, but in this case there's no way to do better; but if checkThis resolves with a false before the for loop ends -> it will be stopped

然后,当出现错误结果时,在checkThis中设置alreadyFailed to true就足够了;当然,在第一次解析为false之前,for循环就会结束,但是在这种情况下没有更好的方法;但是如果checkThis在for循环结束之前用一个false解决,那么它将被停止

#1


2  

Here is an alternative solution to Bergi's approach - we map false return values to the exceptional condition failures they are and use Q.all directly:

这是Bergi方法的另一种解决方案——我们将错误的返回值映射到异常情况下的故障,并使用Q。所有直接:

Your current code does:

你当前的代码:

for (var key in queryPermissions) {
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method));
    }
}

We add an additional step:

我们再增加一个步骤:

for (var key in queryPermissions) {
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method).then(function(val){
             if(!val) throw new Error("Invalid Permissions");
             return true;
        });
    }
}

This simple addition would let us use Q directly:

这个简单的添加可以让我们直接使用Q:

Q.all(promisesArray).catch(function(err){
     // one or more authentication errors
}).then(function(){
      // everyone validated, all ok user authenticated here
});

This is a more general method - using the exception pipeline for exceptional cases can greatly simplify your code.

这是一种更通用的方法——对异常情况使用异常管道可以极大地简化代码。

#2


2  

Not with any native Q function. You could however write an every method for promises yourself (loosely based on Q.all):

没有任何的本地Q函数。然而,你可以为你自己写一个每个承诺的方法(松散地基于Q.all):

Q.every = function every(promises) {
    return Q.when(promises, function (promises) {
        var countDown = 0;
        var deferred = defer();
        for (var i=0; i<promises.length; i++) {
            var promise = promises[i];
            var snapshot;
            if (
                Q.isPromise(promise) &&
                (snapshot = promise.inspect()).state === "fulfilled"
            ) {
                if (!snapshot.value) {
                    deferred.resolve(false);
                    return deferred.promise;
                }
            } else {
                ++countDown;
                q.when(
                    promise,
                    function (value) {
                        if (!value)
                            deferred.resolve(false);
                        else if (--countDown === 0)
                            deferred.resolve(true);
                    },
                    deferred.reject,
                    (function(index) {
                        return function (progress) {
                            deferred.notify({ index: index, value: progress });
                        };
                    }(i));
                );
            }
        }
        if (countDown === 0) {
            deferred.resolve(true);
        }
        return deferred.promise;
    });
}

#3


0  

It's not possible. Indeed, Q.all run parallel promises, so when you want to break, the other promises are still running. So they can't be stopped. One way is to use Q.spread but therefore the promises are no more parallel :(.

这是不可能的。事实上,问。所有的承诺都是并行的,所以当你想要违背的时候,其他的承诺仍然在运行。所以他们不能被阻止。一种方法是用Q。传播但因此承诺不再是平行的:(。

#4


0  

Maybe I had a sudden enlightment but was not so hard: just using a global flag:

也许我突然得到了启发,但并没有那么困难:仅仅使用一个全球旗帜:

var alreadyFailed = false;

//queryPermissions is an object that contains all possible permissions:
//each property of queryPermission is an object containing the values to be checked
for (var key in queryPermissions) {
    if (alreadyFailed) {
        break;
    }
    if (queryPermissions.hasOwnProperty(key)) {
        promisesArray.push(checkThis(key, req.method));
    }
}

Then it is sufficient to set alreadyFailed to true inside checkThis when a false result occurs; of course it can happen that the for loop ends before the first resolve to false, but in this case there's no way to do better; but if checkThis resolves with a false before the for loop ends -> it will be stopped

然后,当出现错误结果时,在checkThis中设置alreadyFailed to true就足够了;当然,在第一次解析为false之前,for循环就会结束,但是在这种情况下没有更好的方法;但是如果checkThis在for循环结束之前用一个false解决,那么它将被停止