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

关于如何解开循环依赖的一个想法 #1436

Closed
xwcoder opened this issue Feb 5, 2015 · 4 comments
Closed

关于如何解开循环依赖的一个想法 #1436

xwcoder opened this issue Feb 5, 2015 · 4 comments

Comments

@xwcoder
Copy link

xwcoder commented Feb 5, 2015

简化场景:模块a依赖模块b,同时模块b依赖模块a, a要等b ready后才能进入ready状态,b要等a ready后才能进入ready状态,如果没有循环探测,a和b会永久的相互等待,即静默失败。

循环依赖的路径可能非常长而且复杂。通常思路就是在一个图结构中寻找环,然后将环打开,使用递归的话会引起回溯,性能会受影响。在实现mb时递归遍历树,当有回溯产生时,执行时间对于页面响应来说是不能忍受的,所以这不是一个好的方法。

思路如下:
现在的模块有如下状态:

  FETCHING: 1, // 正在加载对应文件
  LOADING: 2, // 正在加载依赖模块
  LOADED: 3, // 依赖模块加载完毕

循环依赖造成静默失败时,a, b所处的状态是LOADING, 等待依赖。

可以在每个模块进入LOADING状态后,检查是否有模块正在被加载(处于FETCHING状态),如果没有,则可以认为所有模块对应的文件都加载完毕,即define执行完毕。此时遍历模块,如果有模块处于LOADING状态,那么可以认为出现了循环依赖,将其状态置为LOADED。

release: function () {
    var hasFetching= false;
    var uri, mod;
    for ( var uri in cache ) {
        mod = cache[uri];
        if ( mod.status == STATUS.FETCHING ) {
            hasFetching = true;
            break;
        }
    }

    if ( !hasFetching ) {
        for ( uri in cache ) {
            mod = cache[uri];
            if ( mod.status == STATUS.LOADING ) {
                mod.onload();
            }
        }
    }
}

优化一下,可以维护一个fetching模块计数器,和一个处于LOADING状态的模块列表;

    var fetchingCount = 0;
    var loadingModules = {};

release方法:

release: function () {

    if ( fetchingCount > 0 ) {
        return;
    }

    var uri, mod;

    for ( uri in loadingModules ) {
        mod = loadingModules[uri];
        if ( mod.status == STATUS.LOADING ) {
            mod.onload();
        }
    }
    loadingModules = {};
}

一个简单实现 https://github.com/xwcoder/kit

@army8735
Copy link
Member

army8735 commented Feb 5, 2015

3.0已经和nodejs保持一致,支持简单循环依赖了

@qbaty
Copy link

qbaty commented Feb 5, 2015

@army8735 已经实现了?nice and well done,之前邮件组里讨论过无数次了

@army8735
Copy link
Member

army8735 commented Feb 5, 2015

https://github.com/seajs/seajs/blob/master/src/module.js#L51

传递引用算法。

从seajs.use入口开始,将use引用一值向下传递,到叶子依赖模块,碰到循不循环跳过。叶子依赖加载完了直接执行入口引用。性能和循环都是最佳。

@qbaty
Copy link

qbaty commented Feb 5, 2015

是的!干的漂亮,issue 可以关了

@army8735 army8735 closed this as completed Feb 5, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants