我正在努力獲取等待相關服務準備資料的編碼。我現在有一個大腦鎖定,我沒有得到我期望的行為。我的期望是 home.ts 頁面依賴于 B 服務,而 B 服務又依賴于首先完成的 A 服務。此外,我不想讓 home.ts 頁面知道 A 服務(理想情況下)。
我在 stackblitz 中做了以下簡化嘗試,第一次使用每個服務公開的 Ready_P 承諾。但是,我現在意識到,通常取決于注入機制,它是未定義的,因此 this.BService.Ready_P.then().. 行在 home.ts 的建構式中失敗。
處理此問題的更好/正確方法是什么?
// home.ts
import { CService } from './CService'; // 20220122
import { BService } from './BService'; // 20220122
//
@Component({
selector: 'home',
templateUrl: 'home.html',
styleUrls: ['./home.scss'],
// encapsulation: ViewEncapsulation.None
})
export class home {
constructor(
//
//
public CService: CService,
public BService: BService
) {
this.Init();
}
//
async Init() {
await this.CService.Load();
console.log('CService Ready from home');
await this.BService.Load();
console.log('BService Ready from home');
}
}
// C.ts
import { BService } from './BService'; // 20220122
/** # CService Depends on BService being data ready
* - 20220122 */
@Injectable()
export class CService {
// 20220122
constructor(
//
public BService: BService
) {
// this.BService.Load().then(() => {
// console.log('BService Ready from C');
// this.Load();
// });
}
//
//
Ready_P: Promise<boolean>;
//
async Load() {
await this.BService.Load()
// Do work
// if (this.Ready_P) return this.Ready_P; // to avoid repeated execution.
return (this.Ready_P = new Promise((resolve) => {
setTimeout(() => {
console.log('C Resolves');
resolve(true);
}, 1000);
}));
}
}
// B.ts
import { AService } from './AService'; // 20220122
/** # BService Depends on AService being data ready
* - 20220122 */
@Injectable()
export class BService {
// 20220122
constructor(
//
public AService: AService
) {
}
//
//
Ready_P: Promise<boolean>;
//
async Load() {
await this.AService.Load()
// Do work
// if (this.Ready_P) return this.Ready_P // to avoid repeated execution.
return (this.Ready_P = new Promise((resolve) => {
setTimeout(() => {
console.log('B Resolves');
resolve(true);
}, 2000);
}));
}
}
// A.ts is similar to C
完整的代碼可以在這里找到找到。
注意:我希望使用相同的模式對我的 A、B、C 服務進行理想編碼。這些服務可能會也可能不會使用 http.get... 等來完成和準備一些資料。為簡單起見,我使用 setTimeout() 來模擬它們將需要一些不同的時間才能完成。
預期的執行順序
1. A Resolves
2. AService Ready from B
3. B Resolves
4. BService Ready from C
5. C Resolves
6. CService Ready from home
7. BService Ready from home
uj5u.com熱心網友回復:
你在正確的軌道上。你看到重復的原因是 home 呼叫了 B 和 C 的 init,B 呼叫了 A,C 呼叫了 B,所以你最終得到
home -> B -> A
home -> C -> B -> A
請注意,A 和 B 將被初始化兩次。如果這些類確實具有這種依賴關系,則向該類知道它已完成的 init 行程添加一個副作用。就像是:
asnyc Load() {
if (this.wasLoaded) return Promise.resolve();
await this.otherService.Load;
this.wasLoaded = true;
}
負載的一個“副作用”可能是物件上的某些實體資料正在設定。該資料的存在可能是 Load 是否需要執行的一個很好的標志。
要解決的另一件事是,您已經成功地從服務 A、B、C 的建構式中洗掉了異步呼叫,但是您的home類從建構式中呼叫了它的(異步)Load()方法。也洗掉它。
在風格上,最現代的語法呈現在您的home課堂上。這是一種風格,但我會將該語法(將使用的方法標記await為存在async并使用await而不是then())復制到您的其他類。
最后,在async/await樣式中,錯誤是用try/catch塊捕獲的,如...
// in class A
async Load() {
if (this.dataWeGetFromB) return Promise.resolve();
try {
this.dataWeGetFromB = await this.BService.Load();
} catch (err) {
// handle err
}
}
uj5u.com熱心網友回復:
我不建議為此目的使用 Promises。相反,Angular 有一種更好的方法來處理依賴于其他代碼來完成的異步代碼。
使用您的代碼,我會這樣寫:
服務一:
@Injectable()
export class AService {
// this service demonstrates dependance on http - an action that takes time to finish
constructor(private http: HttpClient) {}
public load() {
return this.http.get('https://jsonplaceholder.typicode.com/todos');
}
}
注意:出于演示的目的,我使此服務依賴于 http - 這是一個需要時間才能完成的操作。
服務乙:
@Injectable()
export class BService {
private dataStoreExample: Subject<any> = new Subject<any>();
constructor(private AService: AService) {}
get dataFromServiceB() {
return this.dataStoreExample.asObservable();
}
public load() {
this.AService.load().subscribe((data) => {
console.log('A Resolves');
this.dataStoreExample.next(data);
});
}
}
服務 B 依賴于服務 A,并且僅在服務 A 完成其作業時才發出一個值。home.ts 反過來只會在 B 發出該值時接收該值(同樣,在 A 完成其作業之后)。
home.ts:
export class home {
constructor(
public Events: Events,
public BService: BService
) {
this.BService.dataFromServiceB.subscribe(
(data) => console.log('BService Ready from home, got data:', data),
(error) => console.log('BService FAIL from home, error:', error)
);
}
}
見這里:https ://stackblitz.com/edit/ionic-yvza2i?file=pages/home/home.ts
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/419259.html
標籤:
