我有一个关于Javascript承诺链接的问题。假设我在承诺链的某个地方有一个动作。该操作不会返回任何值,但必须在链继续之前完成。
我是否需要将此行动包含在承诺中?我需要这样的东西:
$q.when();
请参阅下面的代码:
...
var goToDashboard = function () {
//TODO: use $q here?
$state.go('dashboard');
};
...
activateEmail().then(signinByToken).then(setPersonalInfo).then(goToDashboard).then(somethingElse).catch(reportProblem);
有人可以提出建议吗?
答案 0 :(得分:2)
在下文中,我演示了使用各种函数和其他返回类型的promise来链接.then
。当然,在没有返回承诺的情况下,没有延迟解决,并且立即执行以下.then
- 因此,如果您有需要完成的异步,则需要返回在异步任务完成时解析的承诺。请注意,返回$q.when()
会返回一个承诺(包含您作为参数提供的任何内容),但它会立即解决。
另外,请注意$state.go
actually returns a promise!因此,在上面的示例中,您只能return $state.go('dashboard');
并且以下.then
不应该执行,直到ui-router更改了路由(如下所示)。
(function() {
"use strict";
angular.module('myApp', ['ui.router', 'ngResource'])
.controller('myController', ['$scope', '$state', '$q', '$timeout', '$resource', '$log', MyController])
.config(['$stateProvider', configUiRouter]);
function configUiRouter($stateProvider) {
$stateProvider
.state("home", {
url: "/home",
template: "<div>Home state</div>"
})
.state("dashboard", {
url: "/dashboard",
template: "<div>Dashboard state</div>"
})
.state("error", {
url: "/error",
template: "<div>Error state: I'm sorry Dave, I'm afraid I can't do that...</div>"
});
}
function MyController($scope, $state, $q, $timeout, $resource, $log) {
$scope.status = {
emailActivated: false,
signinByToken: false,
personalInfo: false,
stackoverflowUsers: null,
loading: null,
counter: 0
};
$state.go('home'); // set default state for ui-router test
activateEmail()
.then(updateStatusLoading).then(counting) // Loading: . Counter: 1
.then(signinByToken)
.then(updateStatusLoading).then(counting) // Loading: .. Counter: 2
.then(setPersonalInfo)
.then(updateStatusLoading).then(counting) // Loading: ... Counter: 3
.then(goToDashboard)
.then(updateStatusLoading).then(counting) // Loading: .... Counter: 4
.then(somethingElse)
.then(triggerError)
.then(neverReached)
.catch(catchesReject);
/* * * * * * * * * * *
* Promise functions *
* * * * * * * * * * */
// doesn't return any promise
// (resolves immediately)
function updateStatusLoading() {
if (!$scope.status.loading) {
$scope.status.loading = "";
}
$scope.status.loading += ".";
}
// returns something other than a promise (a String...)
// (resolves immediately)
function counting() {
$scope.status.counter++;
return "Did some counting... (" + $scope.status.counter + ")";
}
// using promise returned by $timeout
// (delayed resolution)
function activateEmail() {
return $timeout(function simulateActivateEmailLatency() {
$scope.status.emailActivated = true;
}, 1000);
}
// using promise returned by $q.defer, resolved in a $timeout
// (the return is immediate, but the resolve is delayed)
function signinByToken() {
var deferred = $q.defer();
$timeout(function simulateSignInLatency() {
$scope.status.signinByToken = true;
deferred.resolve({
returningSomething: "Is entirely optional"
});
}, 1000);
//log to console what this object looks like
$log.log("deferred.promise: ", deferred.promise);
return deferred.promise;
}
// using promise created by $q.when; no timeout
// (immediate resolution)
function setPersonalInfo() {
$scope.status.personalInfo = true;
$log.log("$q.when: ", $q.when({
foo: "bar"
}));
return $q.when({
returningSomething: "Is entirely optional"
});
}
// using promise created by $state.go
// (will resolve once route has changed; which could include time spent doing ui-router resolves...)
function goToDashboard() {
// yup, this returns a promise!
// https://github.com/angular-ui/ui-router/wiki/Quick-Reference#stategoto--toparams--options
var goPromise = $state.go('dashboard');
$log.log("$state.go: ", goPromise);
return goPromise;
}
// using $promise returned by resource, and adding an .then
// (resolves when the $resource does)
function somethingElse() {
var resourceContainingPromise = $resource('https://api.stackexchange.com/2.2/info')
.get({
site: 'stackoverflow'
});
// (note that it contains a $promise, is not a promise itself)
$log.log("$resource: ", resourceContainingPromise);
return resourceContainingPromise
.$promise
.then(function resourceHandler(results) {
$scope.status.stackoverflowUsers = results.items[0].total_users;
});
}
// returns a rejected promise
// (immediate resolve)
function triggerError() {
var rejectPromise = $q.reject("An error message");
$log.log("$q.reject: ", rejectPromise);
return rejectPromise;
}
// this gets skipped due to .triggerError()
function neverReached() {
$log.error("Shouldn't see this!");
$scope.status.loading += "Never reached!";
}
// this catches the $q.reject and logs the data it passed...
function catchesReject(data) {
$log.log(data); //log the error message
return $state.go('error');
}
}
})();
&#13;
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular-resource.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.14/angular-ui-router.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myController">
<div style="display:inline-block; float:left; margin-right: 20px; min-width: 250px;">
<ul>
<li>Email activated: {{status.emailActivated}}</li>
<li>Sign-in by Token: {{status.signinByToken}}</li>
<li>Personal info set: {{status.personalInfo}}</li>
<li>Stackoverflow Users: {{status.stackoverflowUsers}}</li>
</ul>
<hr />
Loading: {{status.loading}}
<br />Counter: {{status.counter}}
</div>
<div style="display:inline-block; padding: 10px; border: 1px solid grey; max-width: 150px;">
<strong>Ui Router Test</strong>
<div ui-view></div>
</div>
</div>
</div>
&#13;
答案 1 :(得分:0)
我想我找到了问题的答案。
首先,需要考虑then()
引用文档的事实,返回一个新的承诺,该承诺通过回调的返回值解决。
见下文:
然后(successCallback,errorCallback,notifyCallback) - 无论如何 当承诺已经或将要解决或拒绝时,请拨打一个 成功或错误回调一旦结果异步 是可用的。使用单个参数调用回调: 结果或拒绝原因。另外,通知回调可能是 在之前调用零次或多次以提供进度指示 承诺得到解决或拒绝。
此方法返回通过解析或拒绝的新承诺 successCallback的返回值,errorCallback(除非那个 value是一个promise,在这种情况下,它用值来解析 使用promise chaining解决了这个承诺。它也通知 通过notifyCallback方法的返回值。承诺不能 从notifyCallback方法中解析或拒绝。
所以我假设以下回调(确实明确地返回了一些内容)将只返回undefined
本身包含在then()
的承诺中:
var goToDashboard = function () {
//TODO: use $q here?
$state.go('dashboard');
};
所以我确实有一个承诺 - 感谢then()
- 我不需要任何其他的东西......