2016-01-07 78 views
9

如何推迟承诺链?我需要这个,因为我想在继续使用脚本之前等待CSS动画完成。如何在功能上延迟承诺

该功能的目的是打开一个视图。如果视图尚未打开,请打开它(通过更改类),等待css动画,继续。如果视图已经打开,则不要执行任何操作并继续。

我要调用的函数是这样的: (这是一个角度控制器内的功能)

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

此代码的工作,却迟迟不工作。我的方法好吗?我在这里错过了什么?


编辑1:改善与建议的代码从@sdgluck


编辑2:一些澄清的主要问题的:

为了澄清的主要问题一bit more: 我可以在我的代码中使用这种构造吗?

// code doesnt know wheter to wait or not 
// can the Promise do this? 
openView().then(function() {    
    openAnotherView(); 
} 

成果1

浏览器会调用openView(),但因为它已经打开,将只需要调用openAnotherView()马上(无延迟)。

成果2

的观点是不公开的,所以openView()会打开它,然后延迟(?或@Dominic托拜厄斯指出,添加一个eventlister)然后调用openAnotherView()一些延迟之后。

感谢您的帮助!

编辑3:添加了该问题的解释小提琴 http://jsfiddle.net/C3TVg/60/

+1

我想你可能会以这种错误的方式去做。这听起来像你可能想要检测动画是否完成像[this](https://davidwalsh.name/css-animation-callback)。 –

回答

1

如何推迟承诺链?

$timeout返回承诺。 返回诺言它。

$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); 
}); 
+0

Thx为您的答案,我刚刚更新了我的问题。我试图澄清一个事实,即如果我必须等待,我现在不会事先做好。 – 11mb

+0

更新为添加条件延迟。 – georgeawg

3

每个then accepts a function应返回的承诺。它不接受Promise实例。你要调用返回timeout

return MyService 
    .getData(viewId) 
    .then(function(data) { 
     // ... 
    }) 
    .then(function() { 
     return timeout(3000); 
    }); 

另外,有timeout回报的功能,而不是一个承诺:

function timeout(delay) { 
    return function() { 
     return new Promise(function(resolve, reject) { 
      //      ^^^^^^^ (misspelt in your example) 
      $timeout(resolve, delay); 
     }); 
    }; 
} 

然后你就可以把它作为你的例子:

return MyService 
    .getData(viewId) 
    .then(function(data) { 
     // ... 
    }) 
    .then(timeout(3000)); 
+0

Thx用于通过timout函数识别我的错误并清除如何解决它。但是我认为@Dominic Tobias指出我的代码存在另一个问题。 – 11mb

+1

@ 11mb没问题。是的,其他答案更全面。 :-) – sdgluck

13

要延期承诺,只需在等待时间后致电resolve函数即可。

new Promise(function(resolve, reject) { 
    setTimeout(function() { 
    resolve(); 
    }, 3000); // Wait 3s then resolve. 
}); 

与您的代码的问题是,你是返回一个承诺,那么无极then内要创建一个又一个和期待当初的诺言等待它 - 恐怕这不是如何承诺工作。你将不得不做的承诺函数内所有的等待,然后调用决心:

编辑:这是不正确的,你可以延迟承诺链中任何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'); 
 
    })

但是,这不是一个等待css动画的好方法。这是更好听transitionend事件:

element.addEventListener('transitionend', onTransitionEnd); 
element.classList.add('transition-me'); 

请注意,如果您使用的是animation而不是transition的概念同样适用,但使用animationend事件。

+0

在'$ timeout'上使用'setTimeout'不能解决_delay不是工作问题。但关于如何等待转换的好建议。 :-) – sdgluck

+0

啊,我确实不喜欢动画/转换时间在css和js中重复。我绝对会考虑的! 关于你的建议:如果我在'添加数据到视图'功能上添加一个超时,现在它在打开我的视图之前等待,但它不会延迟第一个的调用('一切都准备就绪'),第二个然后('openAnotherView')。 我这样调用解析:Promise.resolve(); – 11mb

+0

所以你想回报一个承诺,但你不想让它等待? –