Return 值而不是承诺 [停止嵌套的延迟承诺]
Return value instead of a promise [to stop nested deferred promise]
我有一堆嵌套的函数,因为顶级函数是 ajax 请求。
所以我想 return 一个值而不是嵌套 child 函数中的承诺。
Parent
let getUserPermissions = function(id) {
let deferred = $q.defer();
let promise = accessRequestService.getPermissions(id);
promise.then(function(data) {
deferred.resolve(data);
}, function(err) {
deferred.reject(err);
})
return deferred.promise;
}
Child 1
$rootScope.userInit = function() {
return getUserPermissions(vzid)
.then(function(data) {
//Some code here
return data;
})
}
Child 2
let checkAuthorize = function(toState) {
return $rootScope.userInit().then(
function(data) {
//some code here
return data;
});
}
3 级
checkAuthorize(toState).then( function(val){
$rootScope.isAuthorized = val;
if ($rootScope.isAuthorized == true) {
$log.info('is Authorized')
} else {
$log.info('is not Authorized');
throw new AuthorizationError()
}
})
在第 3 级,我们仍在履行承诺。可以 child 2
return 一个值而不是 promise。
3 级的期望值
$rootScope.isAuthorized = checkAuthorize(toState);
if ($rootScope.isAuthorized == true) {
$log.info('is Authorized')
} else {
$log.info('is not Authorized');
throw new AuthorizationError()
}
是的,这种事情是可能的,但它会改变行为。您可能希望保留 userInit
,但您还添加了一个 userInitValue
变量并将其初始化如下:
let userInitValue = null;
let userInit = function() {
return getUserPermissions()
.then(function(data) {
userInitValue = data;
return data;
})
}
所以现在 userInitValue
将以 null 开始,然后初始化为相关数据。
function isKnownAuthorized(toDoSomething) {
// If we don't know whether the user is authorized
// because we are still waiting for the server to tell us
// then return false and disallow access for now
if(!userInitValue) return false;
// Otherwise return the truth
// (as of when we got the server response)
return userInitValue.isAuthorized(toDoSomething);
}
再次注意行为的变化。获得即时响应(也许在服务器为您提供数据之前)的代价是即时响应可能是错误的。所以不要在 AngularJs.
中的一次性 :: 表达式中使用它
残酷的事实是:你不能,除非你想要到处都是意大利面条式代码。
最好的解决方案是使用 ui-router's resolve 之类的方法,在向用户显示页面之前获得所需的所有权限。然后,您可以在控制器上使用它们而无需任何异步调用。
根据您希望在级别 3 中实现的目标,我猜测此函数将使用相同的输入被调用多次。在这种情况下,我要做的是在没有缓存结果的情况下调用 promise,并缓存结果。这样你就不必沿着承诺链走下去,尽管我在提供的代码中只计算了一个承诺。 resolve 上有多个处理程序,但只有一个 promise。
你可以为它使用async/await
构造。并使用 Babel 来支持旧浏览器。
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
console.log('done');
}
f1();
你可以运行你的代码就像使用nsynjs同步一样:它将逐步评估代码,如果某些函数returns承诺,它将暂停执行,等待promise resolve,将resolve result赋值给data
属性。因此,下面的代码将暂停在级别 1,直到 promise 被解析为实际值。
var getUserPermissions = function(id) {
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve({
id: id,
isAdmin: "yes he is",
})
}, 1000);
});
};
function synchronousCode() {
console.log("start");
var vzid = 35;
var userInit = function() {
return getUserPermissions(vzid).data;
};
var checkAuthorize = function() {
return userInit().isAdmin;
};
var isAuthorized = checkAuthorize();
console.log(isAuthorized);
};
nsynjs.run(synchronousCode, null, function(){
console.log("finish");
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
我正在使用要在 $stateChangeStart
之前调用的 $state.transitionTo 方法。
var transitionTo = $state.transitionTo;
$state.transitionTo = function(to, toParams, options) {
var from = $state.$current,
fromParams = $state.params;
to = to.name ? to : $state.get(to);
$rootScope.state = {
to: to.self,
toParams: toParams,
from: from.self,
fromParams: fromParams,
options: options
}
if (options.notify && options.notify !== false) {
return $q.reject(new AuthorizationError('Rejecting $state.transitionTo', 'Transition Rejected'));
} else {
return checkAuthorize(to).then(function(auth) {
$rootScope.isAuthorized = auth;
return transitionTo(to, toParams, options)
})
}
}
StateChangeStart
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
$log.info("Route change start from", fromState.url, "to", toState.url);
//event.preventDefault();
if ($rootScope.isAuthorized == true) {
$log.info('is Authorized')
//$state.go($rootScope.toState.name);
} else {
event.preventDefault();
$log.info('is not Authorized');
throw new AuthorizationError('User is not Authorized.', 'NOT_AUTHENTICATED')
}
});
我有一堆嵌套的函数,因为顶级函数是 ajax 请求。 所以我想 return 一个值而不是嵌套 child 函数中的承诺。
Parent
let getUserPermissions = function(id) {
let deferred = $q.defer();
let promise = accessRequestService.getPermissions(id);
promise.then(function(data) {
deferred.resolve(data);
}, function(err) {
deferred.reject(err);
})
return deferred.promise;
}
Child 1
$rootScope.userInit = function() {
return getUserPermissions(vzid)
.then(function(data) {
//Some code here
return data;
})
}
Child 2
let checkAuthorize = function(toState) {
return $rootScope.userInit().then(
function(data) {
//some code here
return data;
});
}
3 级
checkAuthorize(toState).then( function(val){
$rootScope.isAuthorized = val;
if ($rootScope.isAuthorized == true) {
$log.info('is Authorized')
} else {
$log.info('is not Authorized');
throw new AuthorizationError()
}
})
在第 3 级,我们仍在履行承诺。可以 child 2
return 一个值而不是 promise。
3 级的期望值
$rootScope.isAuthorized = checkAuthorize(toState);
if ($rootScope.isAuthorized == true) {
$log.info('is Authorized')
} else {
$log.info('is not Authorized');
throw new AuthorizationError()
}
是的,这种事情是可能的,但它会改变行为。您可能希望保留 userInit
,但您还添加了一个 userInitValue
变量并将其初始化如下:
let userInitValue = null;
let userInit = function() {
return getUserPermissions()
.then(function(data) {
userInitValue = data;
return data;
})
}
所以现在 userInitValue
将以 null 开始,然后初始化为相关数据。
function isKnownAuthorized(toDoSomething) {
// If we don't know whether the user is authorized
// because we are still waiting for the server to tell us
// then return false and disallow access for now
if(!userInitValue) return false;
// Otherwise return the truth
// (as of when we got the server response)
return userInitValue.isAuthorized(toDoSomething);
}
再次注意行为的变化。获得即时响应(也许在服务器为您提供数据之前)的代价是即时响应可能是错误的。所以不要在 AngularJs.
中的一次性 :: 表达式中使用它残酷的事实是:你不能,除非你想要到处都是意大利面条式代码。
最好的解决方案是使用 ui-router's resolve 之类的方法,在向用户显示页面之前获得所需的所有权限。然后,您可以在控制器上使用它们而无需任何异步调用。
根据您希望在级别 3 中实现的目标,我猜测此函数将使用相同的输入被调用多次。在这种情况下,我要做的是在没有缓存结果的情况下调用 promise,并缓存结果。这样你就不必沿着承诺链走下去,尽管我在提供的代码中只计算了一个承诺。 resolve 上有多个处理程序,但只有一个 promise。
你可以为它使用async/await
构造。并使用 Babel 来支持旧浏览器。
function resolveAfter2Seconds(x) {
return new Promise(resolve => {
setTimeout(() => {
resolve(x);
}, 2000);
});
}
async function f1() {
var x = await resolveAfter2Seconds(10);
console.log(x); // 10
console.log('done');
}
f1();
你可以运行你的代码就像使用nsynjs同步一样:它将逐步评估代码,如果某些函数returns承诺,它将暂停执行,等待promise resolve,将resolve result赋值给data
属性。因此,下面的代码将暂停在级别 1,直到 promise 被解析为实际值。
var getUserPermissions = function(id) {
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve({
id: id,
isAdmin: "yes he is",
})
}, 1000);
});
};
function synchronousCode() {
console.log("start");
var vzid = 35;
var userInit = function() {
return getUserPermissions(vzid).data;
};
var checkAuthorize = function() {
return userInit().isAdmin;
};
var isAuthorized = checkAuthorize();
console.log(isAuthorized);
};
nsynjs.run(synchronousCode, null, function(){
console.log("finish");
});
<script src="https://rawgit.com/amaksr/nsynjs/master/nsynjs.js"></script>
我正在使用要在 $stateChangeStart
之前调用的 $state.transitionTo 方法。
var transitionTo = $state.transitionTo;
$state.transitionTo = function(to, toParams, options) {
var from = $state.$current,
fromParams = $state.params;
to = to.name ? to : $state.get(to);
$rootScope.state = {
to: to.self,
toParams: toParams,
from: from.self,
fromParams: fromParams,
options: options
}
if (options.notify && options.notify !== false) {
return $q.reject(new AuthorizationError('Rejecting $state.transitionTo', 'Transition Rejected'));
} else {
return checkAuthorize(to).then(function(auth) {
$rootScope.isAuthorized = auth;
return transitionTo(to, toParams, options)
})
}
}
StateChangeStart
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
$log.info("Route change start from", fromState.url, "to", toState.url);
//event.preventDefault();
if ($rootScope.isAuthorized == true) {
$log.info('is Authorized')
//$state.go($rootScope.toState.name);
} else {
event.preventDefault();
$log.info('is not Authorized');
throw new AuthorizationError('User is not Authorized.', 'NOT_AUTHENTICATED')
}
});