kittencup / angular2-ama-cn

angular2 随便问
691 stars 101 forks source link

Angular 2 DI系统中 函数forwardRef 的作用? #11

Open kittencup opened 8 years ago

kittencup commented 8 years ago

forwardRef函数在 src/core/di/forward_ref.ts

kittencup commented 8 years ago

首先来看下面代码

import {Component,Inject} from 'angular2/core';
@Component({
    selector: 'app',
    template: `
        <h1>test</h1>
    `,
})
export class App {
    constructor(service:Service) {
        console.log(service);
    }
}

@Injectable()
class Service {
}

bootstrap(App,[Service])

如果运行代码,会抛出一个错误 Cannot resolve all parameters for App(undefined). Make sure they all have valid type or annotations.

原因呢很简单。class Serviceclass App的下面,所以在constructor(service:Service) Service是undefined,所以无法使用类型来注入,来看下编译后的代码

    var App = (function () {
        function App(service) {
            console.log(service);
        }
        App = __decorate([
            core_1.Component({
                selector: 'app',
                template: "\n        <h1>test</h1>\n    ",
            }), 
            __metadata('design:paramtypes', [Service])
        ], App);
        return App;
    })();
    exports.App = App;
    var Service = (function () {
        function Service() {
        }
        Service = __decorate([
            core_2.Injectable(), 
            __metadata('design:paramtypes', [])
        ], Service);
        return Service;
    })();

        bootstrap(App,[Service])

class 最终被编译成 函数 并赋值给变量,变量不会被编译器提升到最顶部,所以在App里的Service是undefined。

最简单的解决方案就是,改变顺序

import {Component,Inject} from 'angular2/core';
@Injectable()
class Service {
}
@Component({
    selector: 'app',
    template: `
        <h1>test</h1>
    `,
})
export class App {
    constructor(service:Service) {
        console.log(service);
    }
}
bootstrap(App,[Service])

当然,程序写到后面可能越来越复杂,在最后合并的时候可能无法保证所有的顺序,那么就可以通过forwardRef来解决这个问题

import {Component,Inject,forwardRef} from 'angular2/core';
@Component({
    selector: 'app',
    template: `
        <h1>test</h1>
    `,
})
export class App {
    constructor(@Inject(forwardRef(() => Service)) service) {
        console.log(service);
    }
}

@Injectable()
class Service {

}

bootstrap(App,[Service])