美文网首页JavaScriptWeb前端之路让前端飞
自制前端框架Day15 写写scope放松一下

自制前端框架Day15 写写scope放松一下

作者: 蚊子爸爸 | 来源:发表于2017-06-12 21:39 被阅读49次

写在前面

之前写博客是为了记录自己的开发过程,没指望有人看,所以写的非常凌乱。没想到的是在这些日子里,竟然会有其他人看我的博客并给我评论留言,我感到受宠若惊。所以我要求自己写博客要写的更容易让别人看懂,把自己的所想所得分享出去,如果有人看了我的博客,我希望的文字能对得起别人花费的时间。

前端框架是什么

其实前端框架做的事情都一样,无非是解决了如何用数据来渲染页面的问题:在我看来,无论react还是vue还是angular,其实都是controller+view。
拿我最熟悉的angular来说,数据与页面的绑定就是scope与compile的绑定。
之前写表达式解析部分写的头晕,决定换换脑子,写写scope。

scope的本质

scope其实就是一个普通对象,只不过上面封装了很多方法而已。

scope的数据监测机制

在angular的scope中,有两个部分是数据监测的关键,$watch和$digest。我目前不清楚vue的数据变化监测是什么机制,但是angular的是脏值监测,本质是给scope对象上增加watcher。

watcher是什么

watcher监控scope的某一个属性,并且当属性变化的时候执行回调函数。

$digest()是什么

digest负责把每一个watcher都检查并且运行一次。

今天先决定写这个部分。

在scope的对象上有很多watcher,所以要有一个地方存放这些watcher。

function Scope(){
    this.$$watchers=[]
}

scope有$watch函数,这个函数接受两个参数,第一个参数用于指定该watcher监听的属性,第二个是属性变化的时候执行的回调函数。

Scope.prototype.$watch=function(watchFn,listenFn){
    var watcher = {
        watchFn:watchFn,
        listenFn:listenFn
    }
    this.$$watchers.push(watcher);
}

$digest是用来执行所有watcher的listen方法,也很简单,遍历一下,执行就可以

Scope.prototype.$digest=function(){
    for(var i=0;i<this.$$watchers.length;i++){
        this.$$watchers[i].listenFn();
    }
}

写一个测试案例试试看:

describe('scope', function() {
    var scope;
    beforeEach(function(){
        scope=new Scope()
    })
    it('scope可以赋值', function() {
        scope.name='wangji'
        expect(scope.name).toBe('wangji');
    });
     it('scope的watch和digest方法执行正常', function() {
        var watchFn=function(){
            return 'name'
        }
        var listenFn=jasmine.createSpy();
        scope.$watch(watchFn,listenFn);
        scope.$digest();
        expect(listenFn).toHaveBeenCalled();
    });
});
顺利执行

watcher的实现就是典型的一种观察者模式

watcher有两个方法,一个是watchFn,一个是listenFn。watchFn用于获取scope上某一个属性的值:

watchFn=function(scope){
    return scope.id//这个watcher用于监听scope.id的值
}

listenFn是一个回调函数,这样一来就是很典型的观察者模式:一个方法用来监听某个对象的值,另一个方法是当监听到相应动作时候执行。

脏值检测的实现

每一个watcher既然能获取scope上的一个属性值,那么应该也可以保存上次的值。然后运行一次digest,把每一个watcher跑一次,如果这次拿到的值和上次保存的值不同,说明值是脏的,就可以运行listenFn回调函数,典型的观察者模式。

function Scope(){
    this.$$watchers=[]
}
Scope.prototype.$watch=function(watchFn,listenFn){
    var watcher = {
        watchFn:watchFn,
        listenFn:listenFn,
        last:''
    }
    this.$$watchers.push(watcher);
}
Scope.prototype.$digest=function(){
    var self = this;
    var oldValue,newValue;
    for(var i=0;i<this.$$watchers.length;i++){
        oldValue = this.$$watchers[i].last;
        newValue = this.$$watchers[i].watchFn(self)
        if(oldValue!=newValue){
            this.$$watchers[i].last = newValue;
            this.$$watchers[i].listenFn();
        }
    }
}

执行以下案例看看效果

    it('脏值检测',function() {
        scope.id=2;
        var watchFn=function(scope){
            return scope.id;
        }
        var listenFn=function(){
              console.log('listen!')
        }
        scope.$watch(watchFn,listenFn);
        scope.$digest();
    })

运行$digest方法时,期望中是这样的:
watcher的last值最初是空的,调用watchFn后拿到id属性的值,是2,进行对比,不相等,然后执行了listenFn,打印出listen!这句话。同时,watcher的last被设置为新值,也就是2.
来运行一下试试:

旧值和新值确实不相等 last已经变成最新值 打印出了语句,说明listenFn执行了

没问题!那么再运行一次$digest的话,应该不会再打印listen了,因为经过第一次digest以后,watcher的last属性被赋值为最新值,所以值不再脏了,也就不再运行listenFn了。

执行两次digest,只运行了一次listenFn

完成,这就是脏值检测的核心。

相关文章

  • 自制前端框架Day15 写写scope放松一下

    写在前面 之前写博客是为了记录自己的开发过程,没指望有人看,所以写的非常凌乱。没想到的是在这些日子里,竟然会有其他...

  • 自制前端框架Day23.Scope的parses与evalAsy

    Parses是啥 之前在写表达式的时候遇到的parse是解析的意思,这里的parses是阶段的意思。scope上面...

  • 放松一下,随便写写

    最近在读《心流》,书是读了,但想在短时间内达到稳定的心流状态,确实不太可能。不过也对心流状态有了初步的体验。这体验...

  • 自制简易前端MVC框架

    周末花了大概7小时写了一个简易的响应式blog,原意是练习css的,写着写着却去实现了一套前端路由并渲染的东西,这...

  • 随意写写,放松放松

    人的内心贪婪、恐惧、傲慢、嫉妒……烦恼真的是很多。 身处这个时代,各种便利,各种好吃的,好玩的,时时刻刻刺激着我们...

  • 寒假碎碎念(七)

    前天在冰塘滑冰,家里大人自制冰车两个,只为让我们这些孩子放松一下,也为怀念一下童年乐趣。 自制...

  • angular调用第三方方法时对$scope的赋值

    昨天用七牛云api写了前端上传的框架,在上传成功后把返回的外链赋值给$scope的某个值,结果有个bug,赋值后$...

  • 通过样例来理解 MVC 模式

    参考: 自制前端框架之 MVC参考: MVC,MVP 和 MVVM 的图示 如何设计一个程序的结构,这是一门专门的...

  • 浏览收藏文章列表

    前端 frameset frame前端框架支持ie8选择前端框架选择2前端框架选择weexframeset,fra...

  • 自制前端前端框架 Day17. 完善digest

    如果digest遇到了死循环该如何处理 假设有两个watcher,在digest的时候互相更改对方的值,这会导致d...

网友评论

  • 三生石上绛珠草:写的这么好肯定有人看的啊。前段时间没怎么看哈哈,我慢慢补
    我理解的是Angular和Vue都是MVVM中的ViewModel,通俗说是binder,把Model和View绑定到一起:joy: 是吧?
    蚊子爸爸:@三生石上绛珠草 我也是这么理解的,我甚至觉得所有前端框架都在做同样的事情。

本文标题:自制前端框架Day15 写写scope放松一下

本文链接:https://www.haomeiwen.com/subject/wkmlqxtx.html