วิธีเรียกใช้บริการเมื่อแอปเริ่มต้นใน Angular 2


97

ฉันสร้างบริการ SocketService โดยพื้นฐานแล้วจะเริ่มต้นซ็อกเก็ตเพื่อให้แอปฟังบนพอร์ต บริการนี้ยังโต้ตอบกับส่วนประกอบบางอย่าง

// socket.service.ts

export class SocketService {
    constructor() {
        // Initializes the socket
    }
    ...
}

ฉันรู้รหัสในตัวสร้างของ SocketService () เริ่มทำงานเมื่อคอมโพเนนต์ใช้ SocketService เท่านั้น

และโดยปกติโค้ดใน app.ts จะมีลักษณะดังนี้:

// app.ts

import {SocketService} from './socket.service';
...
class App {
    constructor () {}
}
bootstrap(App, [SocketService]);

อย่างไรก็ตามฉันต้องการให้บริการนี้ทำงานเมื่อแอปเริ่มทำงาน ดังนั้นฉันจึงสร้างเคล็ดลับเพียงแค่เพิ่มตัวprivate _socketService: SocketServiceสร้างของแอพ () ตอนนี้รหัสมีลักษณะดังนี้:

// app.ts (ใหม่)

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {}
}
bootstrap(App, [SocketService]);

ตอนนี้ใช้งานได้แล้ว ปัญหาคือบางครั้งรหัสในตัวสร้างของ SocketService () ทำงานบางครั้งไม่ได้ แล้วจะทำอย่างไรให้ถูกต้อง? ขอบคุณ


คู่มือนี้ช่วยฉันได้: angular.io/docs/ts/latest/tutorial/…
Marian07

คำตอบ:


130

คำตอบของ Stuart ชี้ไปในทิศทางที่ถูกต้อง แต่การค้นหาข้อมูลบน APP_INITIALIZER นั้นไม่ใช่เรื่องง่าย เวอร์ชันสั้นคือคุณสามารถใช้เพื่อเรียกใช้รหัสเริ่มต้นก่อนที่รหัสแอปพลิเคชันอื่น ๆ ของคุณจะทำงาน ฉันค้นหาอยู่พักหนึ่งและพบคำอธิบายที่นี่และที่นี่ซึ่งฉันจะสรุปในกรณีที่พวกเขาหายไปจากเว็บ

APP_INITIALIZER ถูกกำหนดเป็นเชิงมุม / แกน คุณรวมไว้ใน app.module.ts ของคุณเช่นนี้

import { APP_INITIALIZER } from '@angular/core';

APP_INITIALIZER เป็นOpaqueToken (หรือ InjectionToken ตั้งแต่ Angular 4) ที่อ้างถึงบริการ ApplicationInitStatus ApplicationInitStatus เป็นผู้ให้บริการหลาย รองรับการอ้างอิงหลายรายการและคุณสามารถใช้ในรายการผู้ให้บริการของคุณได้หลายครั้ง มันใช้แบบนี้

@NgModule({
  providers: [
    DictionaryService,
    {
      provide: APP_INITIALIZER,
      useFactory: (ds: DictionaryService) => () => return ds.load(),
      deps: [DictionaryService],
      multi: true
    }]
})
export class AppModule { }

ประกาศผู้ให้บริการนี้บอกให้คลาส ApplicationInitStatus รันเมธอด DictionaryService.load () load () ส่งคืนคำสัญญาและ ApplicationInitStatus บล็อกการเริ่มต้นแอปจนกว่าคำสัญญาจะแก้ไข ฟังก์ชัน load () ถูกกำหนดไว้เช่นนี้

load(): Promise<any> {
  return this.dataService.getDiscardReasons()
  .toPromise()
  .then(
    data => {
      this.dictionaries.set("DISCARD_REASONS",data);
    }
  )
}

ตั้งค่าให้พจนานุกรมถูกโหลดก่อนและส่วนอื่น ๆ ของแอปจะขึ้นอยู่กับมันได้อย่างปลอดภัย

แก้ไข: โปรดทราบว่าสิ่งนี้จะเพิ่มเวลาในการโหลดล่วงหน้าสำหรับแอปของคุณโดยใช้เวลานานแค่ไหนในการโหลด () วิธีการ หากคุณต้องการหลีกเลี่ยงคุณสามารถใช้ตัวแก้ไขในเส้นทางของคุณแทน


ขอบคุณสำหรับสิ่งนี้ ... มีประโยชน์มาก
Gaurav Joshi

5
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ปัจจุบันจะย้ายโค้ดเพียงบรรทัดเดียวจากคอนสตรัคเตอร์ไปยังinitเมธอด ในขณะที่ช่างก่อสร้างควรถูกทำให้เรียบง่ายที่สุด แต่ความคิดนั้นเพียงอย่างเดียวไม่ได้ทำให้เป็นทางออกที่เหมาะสม ใช้APP_INITIALIZERไม่
JP ten Berge

ฉันไม่คิดว่าคำตอบที่เลือกผิดเพราะมันช่วยแก้ปัญหาของ OP ได้ แต่เนื่องจากฉันมีปัญหาคล้าย ๆ กันเกี่ยวกับการพัฒนาห้องสมุดบางแห่งฉันจึงเปิดคำถามอื่นที่คำตอบนี้จะเข้ากันได้อย่างสมบูรณ์แบบ
Machado

วิธีที่ดีที่สุด
Renil Babu

58

ย้ายตรรกะในตัวSocketServiceสร้างของคุณไปที่วิธีการแทนแล้วเรียกสิ่งนั้นในตัวสร้างองค์ประกอบหลักของคุณหรือngOnInit

SocketService

export class SocketService{
    init(){
        // Startup logic here
    }
}

แอป

import {SocketService} from './socket.service';
...
class App {
    constructor (private _socketService: SocketService) {
        _socketService.init();
    }
}
bootstrap(App, [SocketService]);

1
ฉันไม่เข้าใจว่าตรรกะเบื้องหลังทำสิ่งต่าง ๆ ในวิธีการแทนตัวสร้างได้โปรดอธิบายสิ่งนี้ข้อดีของการทำตรรกะในวิธีการคืออะไร
Pardeep Jain

1
แนวทางที่สะอาดกว่า imho
inoabrian

12
คอนสตรัคเตอร์ควรเรียบง่ายที่สุดเท่าที่จะเป็นไปได้ (โดยปกติจะมีเฉพาะจุดฉีดเท่านั้น) ในกรณีที่คุณต้องการเพิ่มตรรกะเพิ่มเติมให้ใช้ตะขอ ngOnInit
Sergio

1
อีกสิ่งหนึ่งที่ทีมงานคิดไม่ถึง .. ยิ่งฉันทำงานกับ Angular 4 มากเท่าไหร่ฉันก็ตระหนักดีว่า Aurelia framework สร้างขึ้นมาได้อย่างยอดเยี่ยม มันมีความเป็นไปได้ทั้งหมดเหล่านี้ทันทีโดยเพิ่มมัณฑนากร พวกนั้นรู้ว่ากำลังทำอะไร
Joel Hernandez

1
@CodyBugstein ขึ้นอยู่กับกรณีการใช้งานของคุณ หากเป็นเพียงไฟและลืมให้เรียกใช้วิธี async หากคุณต้องการรอผลลัพธ์คุณสามารถคืนค่า a Promiseจากinit()วิธีการของคุณแล้วต่อโซ่ได้ตามต้องการ ไม่ว่าในกรณีใดก็สามารถทำได้ แต่อาจจะยากและขึ้นอยู่กับคุณในการหารายละเอียด หากคุณต้องการความช่วยเหลือเพิ่มเติมคุณสามารถโพสต์คำถามพร้อมรายละเอียดปัญหาที่แน่นอนของคุณได้เสมอและชุมชนยินดีที่จะช่วยเหลือคุณ
SnareChops


1

ลองสร้างตัวสร้างบริการแล้วเรียกมันใน ngOnInit () ของคอมโพเนนต์ของคุณ

  • โมดูลบริการ

 export class SocketService {
    constructor() { }
        getData() {
            //your code Logic
        }
}

  • ส่วนประกอบ

export class AppComponent {
    public record;  
    constructor(private SocketService: DataService){ }
    ngOnInit() {        
        this.SocketService.getData()
        .subscribe((data:any[]) => {
            this.record = data;
        });   
  }  
}       

หวังว่านี่จะช่วยได้


1
@Hongbo ต้องการให้บริการทำงานเมื่อแอปเริ่มทำงานไม่ใช่ในส่วนประกอบเฉพาะที่ใช้บริการ
Jarod Moser

คำตอบง่ายๆนี้ใช้ได้ผลสำหรับฉัน ฉันชอบคำตอบง่ายๆ ขอบคุณ.
Aggie Jon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.