admin管理员组文章数量:1208153
How can I delay a chain of promises? I need this because I want to wait for a CSS animation to complete before going on with the script.
The purpose of the function is to open a view. If the view is not already open, then open it (by changing a class), wait for the css animation, go on. If the view is already open, do nothing and go on.
I want to call the function like this: (It is a function within an angular controller)
$scope.openView(viewId).then(function() {
$scope.openAnotherView(anotherViewId);
});
/** Function to open some view **/
$scope.openView = function (viewId) {
function timeout(delay) {
return new Promise(function(resolve, reject) {
$timeout(resolve, delay);
});
}
// Check if view is already open
if ($scope.viewId != viewId) {
$scope.viewId = viewId;
// get data from ajaxcall (also a promise)
return MyService.getData(viewId).then(function(data) {
// add data to view
// change class to open view
// this is working ok!
}).then(function() {
return timeout(30000 /* some large number (testing purpose) */ )
});
} else {
// view is already open, so return here we don't have to wait
// return empty promise, with no timeout
return new Promise(function(resolve, reject) {
resolve()
});
}
}
This code works, but the delay is not working. Is my approach ok? What am I missing here?
Edit 1: improved the code with the suggestion from @sdgluck
Edit 2: Some clarification of the main question:
To clarify the main question a bit more: Can I use this construction in my code?
// code doesnt know wheter to wait or not
// can the Promise do this?
openView().then(function() {
openAnotherView();
}
Outcome 1:
the browser will call openView()
but since it is already open it will just call openAnotherView()
right away (no delay).
Outcome 2 :
The view is not open, so openView()
will open it, then a delay (or as @Dominic Tobias points out, add an eventlister?) then call openAnotherView()
after some delay.
Thanks for any help!
Edit 3: Added a fiddle with the problem explained /
How can I delay a chain of promises? I need this because I want to wait for a CSS animation to complete before going on with the script.
The purpose of the function is to open a view. If the view is not already open, then open it (by changing a class), wait for the css animation, go on. If the view is already open, do nothing and go on.
I want to call the function like this: (It is a function within an angular controller)
$scope.openView(viewId).then(function() {
$scope.openAnotherView(anotherViewId);
});
/** Function to open some view **/
$scope.openView = function (viewId) {
function timeout(delay) {
return new Promise(function(resolve, reject) {
$timeout(resolve, delay);
});
}
// Check if view is already open
if ($scope.viewId != viewId) {
$scope.viewId = viewId;
// get data from ajaxcall (also a promise)
return MyService.getData(viewId).then(function(data) {
// add data to view
// change class to open view
// this is working ok!
}).then(function() {
return timeout(30000 /* some large number (testing purpose) */ )
});
} else {
// view is already open, so return here we don't have to wait
// return empty promise, with no timeout
return new Promise(function(resolve, reject) {
resolve()
});
}
}
This code works, but the delay is not working. Is my approach ok? What am I missing here?
Edit 1: improved the code with the suggestion from @sdgluck
Edit 2: Some clarification of the main question:
To clarify the main question a bit more: Can I use this construction in my code?
// code doesnt know wheter to wait or not
// can the Promise do this?
openView().then(function() {
openAnotherView();
}
Outcome 1:
the browser will call openView()
but since it is already open it will just call openAnotherView()
right away (no delay).
Outcome 2 :
The view is not open, so openView()
will open it, then a delay (or as @Dominic Tobias points out, add an eventlister?) then call openAnotherView()
after some delay.
Thanks for any help!
Edit 3: Added a fiddle with the problem explained http://jsfiddle.net/C3TVg/60/
Share Improve this question edited Jan 7, 2016 at 12:57 11mb asked Jan 7, 2016 at 10:42 11mb11mb 1,3592 gold badges17 silver badges33 bronze badges 1- 1 I think you may be going about this the wrong way. It sounds like you might want to detect if the animation is completed like this instead. – Mike Lawson Commented Jan 7, 2016 at 11:24
3 Answers
Reset to default 13To delay a promise, simply call the resolve
function after a wait time.
new Promise(function(resolve, reject) {
setTimeout(function() {
resolve();
}, 3000); // Wait 3s then resolve.
});
The issue with your code is that you are returning a Promise and then inside the then
of that Promise you are creating another one and expecting the original promise to wait for it - I'm afraid that's not how promises work. You would have to do all your waiting inside the promise function and then call resolve:
Edit: This is not true, you can delay the promise chain in any then
:
function promise1() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('promise1');
resolve();
}, 1000);
})
.then(promise2);
}
function promise2() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('promise2');
resolve();
}, 1000);
});
}
function promise3() {
return new Promise((resolve) => {
setTimeout(() => {
console.log('promise3');
resolve();
}, 1000);
});
}
promise1()
.then(promise3)
.then(() => {
console.log('...finished');
})
However that is not a good way to wait for a css animation. It's better to listen to the transitionend event:
element.addEventListener('transitionend', onTransitionEnd);
element.classList.add('transition-me');
Note if you're using an animation
instead of a transition
the same concept applies but use the animationend event.
Each then
accepts a function which should return a Promise. It does not accept an instance of Promise. You want to return the call to timeout
:
return MyService
.getData(viewId)
.then(function(data) {
// ...
})
.then(function () {
return timeout(3000);
});
Alternatively, have timeout
return a function instead of a Promise:
function timeout(delay) {
return function () {
return new Promise(function(resolve, reject) {
// ^^^^^^^ (misspelt in your example)
$timeout(resolve, delay);
});
};
}
And then you can use it as in your example:
return MyService
.getData(viewId)
.then(function(data) {
// ...
})
.then(timeout(3000));
How can I delay a chain of promises?
$timeout
returns a promise. Return that promise to chain it.
$scope.openView = function (viewId) {
// Check if view is already open
if ($scope.viewId == viewId) {
//chain right away with empty promise
return $q.when();
};
//otherwise if view is not already open
var p = MyService.getData(viewId).then(function(data) {
// add data to view
// change class to open view
// this is working ok!
});
var pDelayed = p.then (function () {
//return to chain delay
return $timeout(angular.noop, 30000);
});
//return delayed promise for chaining
return pDelayed;
};
$scope.openView(viewId).then(function() {
//use chained promise
$scope.openAnotherView(anotherViewId);
});
本文标签: javascriptHow to delay a promise in when functionStack Overflow
版权声明:本文标题:javascript - How to delay a promise in when function - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738706831a2107963.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论