Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS event loop 与 AngularJS 的问题? #11

Open
hjzheng opened this issue Jul 7, 2016 · 2 comments
Open

JS event loop 与 AngularJS 的问题? #11

hjzheng opened this issue Jul 7, 2016 · 2 comments

Comments

@hjzheng
Copy link
Member

hjzheng commented Jul 7, 2016

今天 Fix bug 遇到一个典型的问题, 先简单描述一下该问题:

<div ng-click="vm.toggle()"></div>
<div ng-show="vm.show">这是测试内容</div>
<div id="test">这是测试内容</div>
vm.toggle = function() {
     vm.show = !vm.show
     console.log($document[0].getElementById('test').offsetTop); 
};

参看上面的例子,其实我们是想得到中间 div 隐藏后,最后一个 div 的 offsetTop, 实际上得到的是中间 div 隐藏前的 offsetTop。

为什么呢,因为实际 toggle 中变量的变化,还没有引起 dom 变化,也就是脏检查并没有结束,Dom 也没有重新渲染。此时拿到的 offsetTop 肯定不是我们想要的。

可以参看此图:
qq20160707-1 2x

那么怎么办呢,大家都知道 js 是单线程的,存在一个 event loop 来处理异步任务,这些异步任务存放在一个队列里, 所以我们只需要将获取 offsetTop 操作放入这个队列里就 OK。
当 ng-click 中的函数,AngularJS的脏检查等如上图所示 在队列中执行完毕后,就轮到我们的获取 offsetTop 的异步任务了。

很简单

vm.toggle = function() {
     vm.show = !vm.show
     $timeout(function() {
          console.log($document[0].getElementById('test').offsetTop); 
     }, 0, false);
};

参考资料:
https://docs.angularjs.org/guide/scope
http://www.ruanyifeng.com/blog/2014/10/event-loop.html
http://notes.iissnan.com/2014/waiting-for-dom-to-finish-rendering/

@kuitos
Copy link

kuitos commented Jul 10, 2016

$timeout 虽然是一个解决方案,但是它更像 hack 而不是 resolve,这里应该用 $scope.$$postDigest(fn) 来添加 dirty-check done hook,虽然是私有 api 但是方案上更 语义 & 贴近问题本质。
通常情况下在 ng 里要用到这个手段都是万不得已的情况,不建议当作合理场景,你可以从代码设计上再去考虑有没有更合理的方案。

@hjzheng
Copy link
Member Author

hjzheng commented Jul 10, 2016

@kuitos 👍 之后 AngularJS1.x 会添加方法$postDigestWatch angular/angular.js#5828 去专门处理这种情况吧!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants