Javascript 是否可以从内部承诺获取父函数的回调?
是否可以使用Javascript 是否可以从内部承诺获取父函数的回调?,javascript,angularjs,recursion,timeout,promise,Javascript,Angularjs,Recursion,Timeout,Promise,是否可以使用$timeoutpromise使滚动到链接,如下面所示?如果没有,我如何写scrollTo作为承诺,这样我就可以使用它了 html: <div ng-click=toTop()>click me</div> app.controller('MainCtrl', function($scope, $timeout) { $scope.toTop = function() { var bodyEl = angular.element(do
$timeout
promise使滚动到
链接,如下面所示?如果没有,我如何写scrollTo作为承诺,这样我就可以使用它了
html:
<div ng-click=toTop()>click me</div>
app.controller('MainCtrl', function($scope, $timeout) {
$scope.toTop = function() {
var bodyEl = angular.element(document.querySelector('#body'));
scrollTo_(bodyEl[0], 0, 500);
};
function scrollTo_(element, to, duration) {
if (duration <= 0) {
$timeout.cancel(forward);
console.log('yoyo');
return forward;
}
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
var forward = $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
scrollTo_(element, to, duration - 10);
}, 10, false);
}
});
点击我
js:
<div ng-click=toTop()>click me</div>
app.controller('MainCtrl', function($scope, $timeout) {
$scope.toTop = function() {
var bodyEl = angular.element(document.querySelector('#body'));
scrollTo_(bodyEl[0], 0, 500);
};
function scrollTo_(element, to, duration) {
if (duration <= 0) {
$timeout.cancel(forward);
console.log('yoyo');
return forward;
}
var difference = to - element.scrollTop;
var perTick = difference / duration * 10;
var forward = $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
scrollTo_(element, to, duration - 10);
}, 10, false);
}
});
app.controller('MainCtrl',函数($scope,$timeout){
$scope.toTop=函数(){
var bodyEl=angular.element(document.querySelector('#body');
scrollTo(bodyEl[0],0500);
};
函数滚动到(元素、到、持续时间){
如果(持续时间这就是我如何做递归承诺:
function scrollTo_(element, to, duration) {
if(duration<=0) return Promise.resolve();
var difference = to - element.scrollTop,
perTick = difference / duration * 10;
return $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
}, 10, false).then(function(){
duration -= 10;
return scrollTo_(element, to, duration)
});
}
函数滚动至(元素、至、持续时间){
如果(持续时间这就是我如何做递归承诺:
function scrollTo_(element, to, duration) {
if(duration<=0) return Promise.resolve();
var difference = to - element.scrollTop,
perTick = difference / duration * 10;
return $timeout(function() {
element.scrollTop = element.scrollTop + perTick;
}, 10, false).then(function(){
duration -= 10;
return scrollTo_(element, to, duration)
});
}
函数滚动至(元素、至、持续时间){
如果(duration很难解释“使用$timeout promise使scrollTo
可链接,如下图所示”,因为scrollTo
是不可链接的。所以让我们假设scrollTo
是“可链接的”,方法是让它返回$q承诺
有了这样的假设,返回的承诺应该在滚动完成时解决,或者如果滚动在完成之前停止(通过另一个scrollTo_u389;()
调用),则拒绝,这似乎是合理的
下面是:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, $q) {
var stopSignal = false;
$scope.toTop = function() {
var element = angular.element(document.querySelector('#body'))[0];
stopSignal = true; // stop previous.
scrollTo_(0, 500).then(function() { // Yay, scrollTo_() is thenable!
console.log('scroll complete');
}, function() {
console.log('scroll stopped');
});
function scrollTo_(to, duration) {
var startTime = null,
startPos = element.scrollTop,
dfrd = $q.defer();
function step(timestamp) {
if(stopSignal) {
// This block kills an animation that's in progress.
// It doesn't affect freshly initiated animations.
stopSignal = false; // reset the `stopSignal` flag.
dfrd.reject(); // reject the deferred, to indicate non-completion
return; // prevent further animation by returning early and killing the recursion.
}
if (!startTime) {
stopSignal = false;
startTime = timestamp;
}
var progress = timestamp - startTime;
if (progress < duration) {
element.scrollTop = startPos + (to - startPos) * progress / duration; // linear movement w.r.t. time, though not necessarily at regular intervals.
window.requestAnimationFrame(step); // recurse
} else {
element.scrollTop = to; // ensure final position is accurate
dfrd.resolve();
}
}
// This is horribly messy but necessary(?) for the stop signal to take effect.
window.requestAnimationFrame(function() {
stopSignal = false;
window.requestAnimationFrame(step);
});
return dfrd.promise;
}
};
});
var-app=angular.module('app',[]);
应用控制器('MainCtrl',函数($scope,$q){
var停止信号=错误;
$scope.toTop=函数(){
var-element=angular.element(document.querySelector('#body'))[0];
stopSignal=true;//停止上一步。
scrollTo_0500)。然后(function(){//Yay,scrollTo_0500()就可以了!
console.log('scroll complete');
},函数(){
log('scroll stopped');
});
函数滚动至(至,持续时间){
var startTime=null,
startPos=element.scrollTop,
dfrd=$q.defer();
功能步骤(时间戳){
中频(停止信号){
//此块将终止正在进行的动画。
//它不会影响新启动的动画。
stopSignal=false;//重置'stopSignal'标志。
拒绝();//拒绝延迟,表示未完成
return;//通过提前返回并终止递归来防止进一步的动画。
}
如果(!开始时间){
停止信号=假;
开始时间=时间戳;
}
var progress=时间戳-开始时间;
如果(进度<持续时间){
element.scrollTop=startPos+(to-startPos)*进度/持续时间;//线性移动w.r.t.时间,但不一定以固定间隔。
window.requestAnimationFrame(步骤);//递归
}否则{
element.scrollTop=to;//确保最终位置准确
解析();
}
}
//这是可怕的混乱,但必须(?)停止信号生效。
window.requestAnimationFrame(函数(){
停止信号=假;
window.requestAnimationFrame(步骤);
});
返回dfrd.promise;
}
};
});
双击可查看滚动效果在另一个滚动效果开始之前停止
如您所见,通过删除$timeout和:
- 利用,这是编排动画的现代方式(尽管浏览器兼容性目前是一个问题,尤其是IE<10),确保每个用户获得其浏览器在当前处理器负载下可以管理的最佳更新率
- 从确定的基准时间开始,在每一步工作,从而更好地保证运动的线性
不久以后,每个人都应该以这种方式编写浏览器动画。很难解释“使用$timeout promise使scrollTo
可链接,就像我在下面所示”,因为scrollTo
是不可链接的。所以让我们假设scrollTo
是“可链接的”,让它返回$q承诺
有了这样的假设,返回的承诺应该在滚动完成时解决,或者如果滚动在完成之前停止(通过另一个scrollTo_u389;()
调用),则拒绝,这似乎是合理的
下面是:
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope, $q) {
var stopSignal = false;
$scope.toTop = function() {
var element = angular.element(document.querySelector('#body'))[0];
stopSignal = true; // stop previous.
scrollTo_(0, 500).then(function() { // Yay, scrollTo_() is thenable!
console.log('scroll complete');
}, function() {
console.log('scroll stopped');
});
function scrollTo_(to, duration) {
var startTime = null,
startPos = element.scrollTop,
dfrd = $q.defer();
function step(timestamp) {
if(stopSignal) {
// This block kills an animation that's in progress.
// It doesn't affect freshly initiated animations.
stopSignal = false; // reset the `stopSignal` flag.
dfrd.reject(); // reject the deferred, to indicate non-completion
return; // prevent further animation by returning early and killing the recursion.
}
if (!startTime) {
stopSignal = false;
startTime = timestamp;
}
var progress = timestamp - startTime;
if (progress < duration) {
element.scrollTop = startPos + (to - startPos) * progress / duration; // linear movement w.r.t. time, though not necessarily at regular intervals.
window.requestAnimationFrame(step); // recurse
} else {
element.scrollTop = to; // ensure final position is accurate
dfrd.resolve();
}
}
// This is horribly messy but necessary(?) for the stop signal to take effect.
window.requestAnimationFrame(function() {
stopSignal = false;
window.requestAnimationFrame(step);
});
return dfrd.promise;
}
};
});
var-app=angular.module('app',[]);
应用控制器('MainCtrl',函数($scope,$q){
var停止信号=错误;
$scope.toTop=函数(){
var-element=angular.element(document.querySelector('#body'))[0];
stopSignal=true;//停止上一步。
scrollTo_0500)。然后(function(){//Yay,scrollTo_0500()就可以了!
console.log('scroll complete');
},函数(){
log('scroll stopped');
});
函数滚动至(至,持续时间){
var startTime=null,
startPos=element.scrollTop,
dfrd=$q.defer();
功能步骤(时间戳){
中频(停止信号){
//此块将终止正在进行的动画。
//它不会影响新启动的动画。
stopSignal=false;//重置'stopSignal'标志。
拒绝();//拒绝延迟,表示未完成
return;//通过提前返回并终止递归来防止进一步的动画。
}
如果(!开始时间){
停止信号=假;
开始时间=时间戳;
}
var progress=时间戳-开始时间;
如果(进度<持续时间){