是否有可能从内部承诺中获取父函数的回调?

时间:2016-02-01 02:54:56

标签: javascript angularjs recursion timeout promise

Play with my JSfiddle

是否可以使用$timeout承诺使scrollTo可链接,如下所示?如果没有,我如何编写scrollTo作为一个承诺,以便我可以使用then回调?

HTML:

<div ng-click=toTop()>click me</div>

JS:

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);
    }
});

2 个答案:

答案 0 :(得分:1)

这就是我如何完成递归承诺:

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)
    });
}

修改

如果你想在两者之间停止超时,我猜你可以这样做:

var scrollTopTimeoutFlag = true, scrollTopTimeout;
function scrollTo_(element, to, duration) {
    if(duration<=0 || !scrollTopTimeoutFlag){
      if(scrollTopTimeout)  return $timeout.cancel(scrollTopTimeout);
      return $q.when();   // $q.when == Promise.resolve
    } 
    var difference = to - element.scrollTop,
        perTick = difference / duration * 10;
    scrollTopTimeout = $timeout(function() {
        element.scrollTop = element.scrollTop + perTick;
    }, 10, false);
    return scrollTopTimeout.then(function(){
      duration -= 10;
      return scrollTo_(element, to, duration)
    });
}

答案 1 :(得分:1)

很难解释“使用$ timeout承诺使scrollTo可链接,如下所示”,因为scrollTo不可链接。因此,让我们假设scrollTo_()通过让它返回一个$ q的承诺而成为“可以”。

有了这个假设,似乎合理的是返回的承诺应该在完成滚动时解决,或者如果滚动在完成之前停止(通过另一个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; } }; }); 调用)则拒绝。

这里是:

{{1}}

bind_param() 双击以查看滚动效果在另一个启动之前停止。

正如您所看到的,通过丢弃$ timeout和

可以避免10ms的timout引起的间隔
  • 利用DEMO,这是编排动画的现代方式(虽然浏览器兼容性目前是个问题,尤其是IE&lt; 10),保证每个用户都能获得他/她的浏览器可以管理的最佳更新率在主流处理器负载下。
  • 从每个步骤开始工作,从已建立的基准时间开始,提供更好的保证线性运动。

不久之后,每个人都应该以这种方式编写浏览器动画。