2013年11月 ’ 的文章存档

mysql 的权限体系介绍

mysql 的权限体系大致分为5个层级:
全局层级

全局权限适用于一个给定服务器中的所有数据库。这些权限存储在mysql.user表中。GRANT ALL ON *.*和REVOKE ALL ON *.*只授予和撤销全局权限。

数据库层级
数据库权限适用于一个给定数据库中的所有目标。这些权限存储在mysql.db和mysql.host表中。GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*只授予和撤销数据库权限。

表层级
表权限适用于一个给定表中的所有列。这些权限存储在mysql.talbes_priv表中。GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name只授予和撤销表权限。

列层级
列权限适用于一个给定表中的单一列。这些权限存储在mysql.columns_priv表中。当使用REVOKE时,您必须指定与被授权列相同的列。

子程序层级
CREATE ROUTINE, ALTER ROUTINE, EXECUTE和GRANT权限适用于已存储的子程序。这些权限可以被授予为全局层级和数据库层级。而且,除了CREATE ROUTINE外,这些权限可以被授予为子程序层级,并存储在mysql.procs_priv表中。

这些权限信息存储在下面的系统表中:

mysql.user
mysql.db
mysql.host
mysql.table_priv
mysql.column_priv

当用户连接进来,mysqld会通过上面的这些表对用户权限进行验证!

注意:

当后续目标是一个表、一个已存储的函数或一个已存储的过程时,object_type子句应被指定为TABLE、FUNCTION或PROCEDURE。当从旧版本的MySQL升级时,要使用本子句,您必须升级您的授权表。请
我们可以用 CREATE USER 或 GRANT 创建用户,后者还同时分配相关权限。而 REVOKE 则用于删除用户权限,DROP USER 删除账户。

MySQL 赋予用户权限命令语法为:

grant 权限 on 数据库对象 to 用户;
grant 权限 on 数据库对象 to 用户 identified by “密码”;
grant 权限 on 数据库对象 to 用户@”ip” identified by “密码”

GRANT 语法:

GRANT privileges (columns)
ON what
TO user IDENTIFIED BY “password”
WITH GRANT OPTION;

privileges 列表:

* ALTER: 修改表和索引。
* CREATE: 创建数据库和表。
* DELETE: 删除表中已有的记录。
* DROP: 抛弃(删除)数据库和表。
* INDEX: 创建或抛弃索引。
* INSERT: 向表中插入新行。
* REFERENCE:未使用。
* SELECT: 检索表中的记录。
* UPDATE: 修改现存表记录。
* FILE: 读或写服务器上的文件。
* PROCESS: 查看服务器中执行的线程信息或杀死线程。
* RELOAD: 重载授权表或清空日志、主机缓存或表缓存。
* SHUTDOWN: 关闭服务器。
* ALL: 所有权限,ALL PRIVILEGES同义词。
* USAGE: 特殊的 “无权限” 权限。

user 账户包括 “username” 和 “host” 两部分 即是username@host,后者表示该用户被允许从何地接入。user@’%’表示用户user可以从任何地址访问本地的数据库,默认可以省略。还可以是 “user@10.250.7.%“、”user1@%.abc.com” 等。数据库格式为 db.table,可以是 “test.*” 或 “*.*”,前者表示 test 数据库的所有表,后者表示所有数据库的所有表。
子句 “WITH GRANT OPTION” 表示该用户可以为其他用户分配权限。使用grant 命令创建用户或者进行授权之后,需要使用flush privileges刷新MySQL的系统权限相关表,否则会出现拒绝访问,或者重新启动mysql服务器,来使新设置生效。当然后者并不是一种好想法!

比如:

一 grant普通数据用户yangql402查询、插入、更新、删除 数据库(test)中所有表数据的权利。
grant select, insert, update, delete on test.* to yangql402@’%’;
二 grant数据库开发人员(yangql402),创建表、索引、视图、存储过程、函数。。。等权限。

grant创建、修改、删除 MySQL 数据表结构权限。
grant create on test.* to yangql402@’10.250.7.225′;
grant alter  on test.* to yangql402@’10.250.7.225′;
grant drop   on test.* to yangql402@’10.250.7.225′;

grant 操作 MySQL 外键权限,官方文档上说未使用!

grant references on test.* to yangql402@’10.250.7.225′;

grant 操作 MySQL 临时表权限。

grant create temporary tables on test.* to yangql402@’10.250.7.225′;

grant 操作 MySQL 索引权限。

grant index on test.* to yangql402@’10.250.7.225′;

grant 操作 MySQL 视图、查看视图源代码 权限。

grant create view on test.* to yangql402@’10.250.7.225′;
grant show   view on test.* to yangql402@’10.250.7.225′;

grant 操作 MySQL 存储过程、函数 权限。

grant create routine on test.* to yangql402@’10.250.7.225′;
grant alter routine on test.* to yangql402@’10.250.7.225′;
grant execute        on test.* to yangql402@’10.250.7.225′;

三 grant 普通DBA管理某个MySQL数据库(test)的权限。

grant all privileges on test to dba@’localhost’

其中,关键字 “privileges” 可以省略。
四 grant 高级 DBA 管理 MySQL 中所有数据库的权限。

grant all on *.* to dba@’localhost’

五 MySQL grant 权限,分别可以作用在多个层次上。

a. grant 作用在整个 MySQL 服务器上:
grant select on *.* to dba@localhost; — dba 可以查询 MySQL 中所有数据库中的表。
grant all    on *.* to dba@localhost; — dba 可以管理 MySQL 中的所有数据库

b. grant 作用在单个数据库上:
grant select on test.* to dba@localhost; — dba 可以查询 test 中的表。

c. grant 作用在单个数据表上:
grant select, insert, update, delete on test.yql8 to dba@localhost;

d. grant 作用在表中的列上:
grant select(id, se, rank) on test.yql8 to dba@localhost;

e. grant 作用在存储过程、函数上:
grant execute on procedure test.yql8 to ‘dba’@’localhost’;
grant execute on function test.yql8 to ‘dba’@’localhost’;
六 查看用户权限

查看当前用户自己的权限:
show grants;

查看其他 MySQL 用户权限:
show grants for dba@localhost;

七 撤销用户权限

使用revoke 命令来注销用户的权限,具体语法:

要撤销所有权限,需使用以下语法。此语法用于取消对于已命名的用户的所有全局层级、数据库层级、表层级和列层级的权限。

REVOKE ALL PRIVILEGES, GRANT OPTION FROM user [, user] …

也可以指定具体的权限比如:

REVOKE SELECT FROM yangql402@”10.250.7.249“;

注意:

1 使用GRANT或REVOKE,操作者必须拥有GRANT OPTION权限,并且您必须用于您正在授予或撤销的权限。
2 使用REVOKE撤销全部权限,操作者必须拥有mysql数据库的全局CREATE USER权限或UPDATE权限。

八 删除用户:

DROP USER user;

其中user 账户包括 “username” 和 “host” 两部分 即是username@host;如果创建的时候为yangql@”10.250.7.225“,则删除的时候必须使用

drop user yangql@”10.250.7.225“,否则会报错!
mysql> drop user yangql402;
ERROR 1396 (HY000): Operation DROP USER failed for ‘yangql402′@’10.250.7.225′
mysql> drop user yangql402@’10.250.7.225′;
Query OK, 0 rows affected (0.01 sec)

 

文章来源:http://wolfchen.blog.51cto.com/2211749/1243990

Python yield 使用浅析

初学 Python 的开发者经常会发现很多 Python 函数中用到了 yield 关键字,然而,带有 yield 的函数执行流程却和普通函数不一样,yield 到底用来做什么,为什么要设计 yield ?本文将由浅入深地讲解 yield 的概念和用法,帮助读者体会 Python 里 yield 简单而强大的功能。

您可能听说过,带有 yield 的函数在 Python 中被称之为 generator(生成器),何谓 generator ?

阅读全文

新浪云计算SAE推CloudBridge服务

 

CloudBridge服务是SAE推出的NaaS(Network as a Service)的总称,符合PaaS平台SDN大逻辑,包括以下三个部分:

  •  Internal提供用户公共数据访问,且资源租户间完全隔离
  •  External扩展用户私有数据,满足云环境数据安全等级
  • lInternal与External间数据通过边界CloudBridge管道打通,可授权交互

 

CloudBridge包括了从外到内、内部以及从内到外的网络控制和安全隔离,从下图中可以看到,Controler负责各应用和资源间的网络流控制,而Forwarder则负责实际的代理转发。与某些IaaS中SDN不同的是,CloudBridge不依赖于特殊网络设备而实现在OS层,并且主要负责L2以上网络流控制。目前,项目中涉及VPC部分的Data Connection仍在开发中。完成后,将可以提供一套跨企业内外网的PaaS网络解决方案。

111

(SAE CloudBridge架构图)

 

CloudBridge下辖以下服务:

  • 平台防火墙

- 高性能硬件DDoS流量清洗解决方案

- 旁路集群化部署,完全覆盖机房容量,同时规避单点瓶颈

- 按需防护,既可抵御海量DDoS攻击,又做到全类型精准识别

- 可提供完善的攻击取证,以及事件回放,最大化保护用户利益

- 运维人员远程一体化监控

 

  •  L7反向代理(High Forwarder),负责External HTTP/HTTPS请求分发,代理应答

- 负载均衡,提供多种策略保证后端服务器均衡处理前端请求
- 健康检查及故障摘除,自动识别故障节点,并将其摘除,从而保证App访问正常
- HTTPS隧道,将进入的HTTPS请求转化为内网HTTP请求
- 网络代理加速,通过电信、联通、教育网、移动等多级代理进行网络加速,提高访问质量

 

  • 应用防火墙(AFW Application Firewall),

- 针对访问IP进行黑白名单控制和多元化QoS。
- 自动识别可疑IP,及完善的老化处理。
- 提供开放API,满足用户自编程对防火墙控制,和上传验证码等逻辑。

 

  • FetchURL(Low Forwarder L7),HTTP/HTTPS,

- 自识别Internal和External,按需抓取安全控制
- 通过代理调度加快公网抓取速度
- 网络资源全隔离,防止恶意抓取
- 智能识别慢访问,避免App阻塞

 

  • SocketProxy(Low Forwarder L3&L4),TCP/SSL,

- 自识别Internal和External,访问安全控制
- 通过代理调度加快公网连接速度
- 进行网络资源全隔离,防止恶意访问
- 智能识别慢访问,避免App阻塞

 

  • Direct Connection

       – 通过边界CloudBridge打通SAE 平台Internal数据与External的安全交互。

       – 内外网区分,安全访控

       – 具有常规的防攻击能力考虑

 

 

说明:

1,斜体说明表示该功能即将上线。

2,SAE已经将High Forwarder和Low Forwarder集成在内部网络环境中,即应用无需做任何代码修改,其发出或者接收的L2以上网络通信自动经过Forwarder。同时,因为安全控制是脱离语言环境的,使得网络流量控制更安全。

3,App可以通过Low Forwarder实现各种上层协议,即访问外网数据库、发送邮件、调用socket接口等。

 

 

Java中的IO整理

写在前面:本文章基本覆盖了java IO的全部内容,java新IO没有涉及,因为我想和这个分开,以突出那个的重要性,新IO哪一篇文章还没有开始写,估计很快就能和大家见面。照旧,文章依旧以例子为主,因为讲解内容的java书很多了,我觉的学以致用才是真。代码是写出来的,不是看出来的。

最后欢迎大家提出意见和建议。

阅读全文

Web开发人员的6种赚钱之道

你是web开发人员吗?还是这个行业的新人?你想赚点外快吗?或者去挣赖以生存的钱?上面这些问题中,只要你对任意一条做出了肯定的回答(否定全部的问题也很难),那这篇文章就会对你有所帮助。

接下来,我会介绍到大部分可能通过web开发技能从网上赚钱的方法。我知道应该还有其他途径,但是在大多数情况下都会是下述的几个类别。那么,让我们开始列出它们。

5

0.当一名自由职业者

这个是最显而易见的。如果你会制作网站、编写脚本、设计网页或是模板,你就可以向他人提供你的服务。如果你准备为你的客户辛勤工作,并为你所付出的时间获取酬劳,这也许是一个赚钱的好途径。你拿到的活越多,挣的钱就越多。关于自由职业者还有更多可写的,但是那些都是题外话了。

问题:你得去寻找需要你服务的人群。

可能的解决方式:有很多可以找工作的网站。其中最大最出名的3家是:ElanceFreelancerODesk。雇主在这些网站上贴出面向自由职业者的工作,你可以“竞拍”这些工作(就像在ebay上竞拍一样)。

限制:唯一的限制可能就是你的时间。基本上你的报酬取决于你做的工作。经常是以小时计算。你干的越多——挣得就越多。但是有朝一日当你无法再承担再多的工作的话…

1. 发布免费脚本、模板(或是其他任何免费的东西)

开始的时候听上去有些蠢,提供免费的东西挣钱?怎么挣?

当你发布了免费的东西,你会有一些收获。首先可能会有捐赠。如果人们喜欢你给他们的那些免费的东西,他们会想返还给你一些,对你来说,最好的就是钱了。所以请不要忘记索要并布置一个按钮,以便任何做出决定的人都能轻而易举的捐赠。

另外,很多人也许会想让你定制或把你的脚本、模板安插在他们的网站上。你将是他们咨询此事的第一人,因为他们知道你很了解你的产品!

而这还不是全部!你会因为给出免费品而得到特殊福利。如果你有网站的话,那你将会得到更多浏览量。如果你获得了更多的浏览量,你就可以轻松的通过下面这两条赚钱(“联盟计划、点击付费、卖广告”和“卖你自己的产品”)。

问题:一般来说,如果你的免费产品不是特别特别广为人知的话,你将无法挣得赖以生存的钱。

可能的解决方式:同时应用下述两点(“联盟计划、点击付费、卖广告”和“卖你自己的产品”)

限制:俗话说,天空才是界限。你可以制造并发布更多免费产品,人们就不止会因为新产品而回访,你还会从搜索引擎在你的旧产品上获得大量点击。

编注:Code Canyon网站是全球数一数二的代码交易平台,有72多万的会员,有很多优秀的开发人员在这里出售他们的代码。如果你已是脚本代码巧匠,不妨把你的代码发布上去出售,这不失为一种赚钱之道,尤其是在工资涨不过物价的环境。

2. 联盟计划、卖广告

线上广告真的能养活你。但是对于所有这些项目,你都需要一个地方去放置你的广告或者链接代码。所以你需要建一个自己的网站并得到一些点击量。如上述所言,最好的方法就是提供来访者一些免费的产品。可以是一些脚本、模板、剪贴画或是有用的信息。另一种方法就是从SEO(搜索引擎优化)下手或买一些访问量。当你拥有来访者后,你就要放置广告并开始挣联盟佣金,或者卖各种广告。

问题:这个听上去很容易。但是你的新网站将会非常难以取得访问量,找一个转换率很好的联盟计划甚至更难。

可能的解决方式:努力工作。阅读在这个行业成功的人们的博客,向他们学习。

限制:再提一次,天空才是界限。你的网站越来越成功,你就能赚更多的钱。

3.卖你自己的产品

卖你自己的产品和从属项目营销类似,但还是也有很大的区别。

  • 你将获得销售额的100%。
  • 你必须自己制造产品(不管是脚本、模板还是其他任何东西)。
  • 你还要考虑到支付手段,客户支持等等。

一般来说,比起加入营销项目,卖自己的产品可以让你学到更多(你必须去制作人们想买的东西!)。这也需要更大量的工作。但是也许真的很划算。

问题:你要为你的产品负责,支持客户。为了运行你的产品,你需要投入大量的时间和(或)金钱。

可能的解决方式:把你的产品开发外包给一些自由职业者。有个好地方可以找到这些人,那就是(对的…我再说一次…):ElanceFreelancerODesk。然而你开始的时候仍需要资金。

限制:如果你有了优秀的产品,你就要去宣传它然后…除非广告预算不足,否则只有天空才是你的界限。

4. 出售网站

这个也许能赚大钱,卖网站大致有两种方法:

  • 制作网站并以现金售出
  • 购买网站 → 稍作加工 → 再以更高价格现金卖出

也许你不信,但是的确有效。人们在寻找一些万事就绪的网站为他们赚钱,这是一个巨大的市场。门户网站Flippa是一个很好的起始点。这个网站就像ebay一样,只不过是买卖网站。

问题:不是所有的网站都畅销。你得去找到利基(niche),制作出优秀的网站并寻找客户。此外,当你购买网站的时候,你很容易上卖家的当。你一定要清楚你到底在做什么…

可能的解决方式:在你开始之前去浏览Flippa上的表单,学习一下你的货品和销售方式到底是什么。去了解一下如何检查你购买网站的卖方。

限制:在开始业务的时候你需要投入一些资金。你会需要一些像域名(我推荐namecheap上的便宜域名)和托管(Site5上提供廉价可靠的托管)。你也可能不确定是否能捞回本钱。

5. 找一份全职工作

如果你认为上述几条都不是挣钱的好主意的话,你也许仍然需要去找(或者继续)早八点晚四点的全职工作。有些人认为这是挣活命钱的最好方式…虽然我不这样认为。

问题:你将没有时间照顾你的家庭,会面对疯狂的老板,没有任何形式的自由。

可能的解决方式:辞去你的工作并发展你自己的线上业务(如果你工作之余还有时间的话,也可以在你的闲暇时间开展业务)。

限制:不管你从老板那里得到了多少工作学到了多少知识,还是挣一样的工资…

结束语

网络上挣钱的方式多种多样,发挥你的Web开发技能的方法同样如此。我认为我涵盖了其中的大部分,并且希望提供给你了一些新点子。很多独立的开发人员并不拘泥于这其中的单一途径,因为这些方法都是多多少少相互关联的。那么,你通过网络挣钱的方法是什么呢,欢迎留言介绍你的方法。

 

原文:Chris   编译来自:伯乐在线 - 蒋少雄

Perl创建守护进程

下面的内容来自著名的Unix Programming FAQ的1.7节,介绍了Unix下创建守护进程的方法。

通常将一个不与任何终端相关联的后台进程定义为daemon进程。下面是通常所需的七 个步骤:

a. fork()之后父进程退出。子进程确保不是process group leader,这是成功调用 setsid()所要求的。

b. setsid(),创建新的session和process group,成为其leader,并脱离控制终端。

c. 再次fork()之后父进程退出,子进程确保不是session leader,将永远不会重获 控制终端。这是SVR4的特性所致。

d. chdir( “/” ),减少管理员卸载(unmount)文件系统时可能遇上的麻烦。这一步可 选,也可chdir()到其它目录。

e. umask( 0 ),使当前进程对自己所写文件拥有完全控制权,避免继承的umask()设 置带来困挠。这一步可选。

f. 关闭0、1、2三个句柄。许多daemon程序用sysconf()获取SCOPEN_MAX,并在一 个偱环中关闭所有可能打开的文件句柄。目的在于释放不必要的系统资源,它们 是有限资源。

g. 出于安全以及健壮性考虑,即使当前进程不使用stdin、stdout、stderr,也应重 新打开0、1、2三个句柄,使之对应/dev/null。当然,你也可以根据需要使之对 应不同的(伪)文件。总之,保持0、1、2三个句柄呈打开状态,并使之指向无害文 件。

实际上,除了以上7点之外你还应当做两件事情。第一件就是切换到daemon用户——避免由于代码的安全漏洞导致root权限泄漏; 第二件事情就是忽略 SIGCHLD 信号,让 init 进程来回收结束了的子进程。

如果将上述内容用 perl 写出来就是下面的程序:

#!/usr/bin/perl

#------------------------------
# daemon process sample, written by charlee, 2006/10/12
#

use strict;
use POSIX 'setsid';

our $USER = 'lijian';
our $GROUP = 'lijian';

#------------------------------
# child process to be created by daemon
sub child-process {
    # do some work here
}


#------------------------------
# create daemon process

# 1. fork() so the parent can exit, returns control to shell.
exit if fork;

# 2. setsid() to become a process group and session group leader.
&setsid();

# 3. fork() again so the parent (session group leader) can exit.
exit if fork;

# 4. (OPTIONAL) chdir('/') to ensure our daemon doesn't keep any directory in use.
chdir '/';

# 5. (OPTIONAL) umask() so we have complete control over the permissions of anything we write.
umask 022;

# 6. close() fds 0, 1, and 2.
close STDIN;
close STDOUT;
close STDERR;

# 7. redirect fds 0, 1, and 2 to /dev/null
open STDIN, '/dev/null';
open STDOUT, '>/dev/null';
open STDERR, '>/dev/null';

# 8. change to daemon user and group.
&sudo($USER, $GROUP);

# 9. ignore SIGCHLD signal to avoid zombie processes
$SIG{CHLD} = 'IGNORE';

# 10. start main loop.
while(1) {
    my $pid = fork;
    if ($pid == 0) {
        &child_process();
        exit;
    } else {
        sleep 1;
    }
}

# main end

# function to change user and group
sub sudo {
    my ($user, $group) = @_;
    my $uid = (getpwnam($user))[2];
    my $gid = (getgrnam($group))[2];
    ($(, $)) = ($gid, "$gid $gid");
    ($<, $>) = ($uid, $uid);
}    

__END__

文章来自:idv2

nginx中upstream的设计和实现

(一)

在nginx的模块中,分为3种类型,分别是handler,filter和upstream,其中upstream可以看做一种特殊的handler,它主要用来实现和后端另外的服务器(php/jboss等)进行通信,由于在nginx中全部都是使用非阻塞,并且是一个流式的处理,所以upstream的实现很复杂,接下来我会通过几篇blog来详细的分析下nginx中upstream的设计和实现。

阅读全文

新浪云计算诚聘前端开发工程师啦!

工作地点:

> 北京, 中关村

岗位职责:

> 参与新项目的开发,以及负责线上运行项目的日常维护以及新功能的开发。

职位要求:

> 1.乐于编码,善于学习,可以融入集体,进行团队开发;

> 2.熟悉前端相关技术,包括HTML/CSS/JS等(JS写的漂亮的加分);

> 3.熟悉WEB标准,以及会根据项目需求选择最优解决的方案;

> 4.熟悉流行前端框架的使用,熟悉常规css hacks。

 

特别说明:

> 1.我们接受应届潜力出众的同学,在这里你可以接触到很多经验丰富的技术大牛,

> 以及和你一样求知若渴的童鞋,升级犹如开挂的人民币玩家。

> 2.简历请发送至 saemail@sina.cn , 邮件标题请注明 “应聘SAE 前端开发工程师”

JS判断移动端访问设备并解析对应CSS

JS判断不同web访问环境,主要针对移动设备,提供相对应的解析方案。

直接看 Mobile_demo

// 判断是否为移动端运行环境

// wukong.name 20130716

if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))){

if(window.location.href.indexOf("?mobile")<0){

try{

if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)){

// 判断访问环境是 Android|webOS|iPhone|iPod|BlackBerry 则加载以下样式

setActiveStyleSheet("style_mobile_a.css");

}

else if(/iPad/i.test(navigator.userAgent)){

// 判断访问环境是 iPad 则加载以下样式

setActiveStyleSheet("style_mobile_iPad.css");

}

else{

// 判断访问环境是 其他移动设备 则加载以下样式

setActiveStyleSheet("style_mobile_other.css");

}

}

catch(e){}

}

}

else{

// 如果以上都不是,则加载以下样式

setActiveStyleSheet("style_mobile_no.css");

}

// 判断完毕后加载样式

function setActiveStyleSheet(filename){document.write("<link href="+filename+" rel=stylesheet>");}

via  w3ctech

构建自己的AngularJS,第一部分:Scope和Digest

Angular是一个成熟和强大的JavaScript框架。它也是一个比较庞大的框架,在熟练掌握之前,需要领会它提出的很多新概念。很多Web开发人员涌向Angular,有不少人面临同样的障碍。Digest到底是怎么做的?定义一个指令(directive)有哪些不同的方法?Service和provider有什么区别?

Angular的文档挺不错的,第三方的资源也越来越丰富,想要学习一门新的技术,没什么方法比把它拆开研究其运作机制更好。

在这个系列的文章中,我将从无到有构建AngularJS的一个实现。随着逐步深入的讲解,读者将能对Angular的运作机制有一个深入的认识。

在第一部分中,读者将看到Angular的作用域是如何运作的,还有比如$eval, $digest, $apply这些东西怎么实现。Angular的脏检查逻辑看上去有些不可思议,但你将看到实际并非如此。

阅读全文