22

论NodeJS中的循环引用

 4 years ago
source link: https://www.tuicool.com/articles/EzAzInb
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

最近在用node的时候排查一个问题排查了半天,最终发现是循环引用导致的问题,故在此记录一下。

场景复现

出现问题场景比较简单,一共四个类:

  • parent.ts
  • child.ts
  • child_2.ts
  • util.ts
export abstract class Parent {

    abstract hello(): string;
}
import {Parent} from "./parent";

export class Child extends Parent {

    hello(): string {
        return "child";
    }

}
import {Child} from "./child";

export class Util {

    static useChildInSameCase(): string {
        let child: Child;
        return child.hello();
    }
}
import {Parent} from "./parent";

export class Child_2 extends Parent {

    hello(): string {
        return "child_2";
    }

}

这个时候我们去构造一个Child类:

import {Child} from "./child";

console.log(new Child().func());

就会直接报错了:

class Child_2 extends parent_1.Parent {
^

TypeError: Class extends value undefined is not a function or null

#寻找原因

说的是这个父类是一个undefined,很明显就是没有初始化。

一开始我觉得很奇怪,明明在child_2这个文件里已经import了parent,为什么会是undefined呢?后来debug查了一下代码的堆栈,恍然大悟:

入口文件->child.ts->parent.ts->util.ts->child_2.ts->parent.ts

很明显这里存在着一个循环引用,当我们在加载child_2.ts这个文件的时候,parent.ts还处在未加载完的状态。

我们可以去 官网看一下node中是如何处理循环引用的

通过官网我们可以知道,对于这样的循环引用,在child_2.ts加载parent.ts的时候,会去缓存中寻找,而由于parent.ts还未加载完成,所以缓存中会是一个空对象了,官网中用的语句是 an unfinished copy of the a.js

解决方案

知道原因之后,解决方案也就变得清晰了起来,一句话搞定,将parent.ts中的import语句放在后面:

export abstract class Parent {

    abstract hello(): string;

    func(): string {
        return Util.useChildInSameCase();
    }
}

import {Util} from "./util";

这样在加载parent.ts的时候,就会先export对象,然后再import所需要的util.ts了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK