3 回答
TA貢獻1847條經驗 獲得超11個贊
對于仍然遇到此問題的任何人,這是我為減少延遲所做的事情:
在 APP_INITIALIZER 而不是 AppComponent 中檢查更新,以便更早完成檢查
使用
checkForUpdate方法
在你app.module.ts添加一個初始化函數:
{ provide: APP_INITIALIZER, useFactory: checkForUpdates, multi: true, deps: [SwUpdate /* Add whatever dependency is required here */] },該函數應如下所示:
export const checkForUpdates = (swUpdate: SwUpdate): (() => Promise<any>) => {
return (): Promise<void> =>
new Promise((resolve) => {
swUpdate.checkForUpdate();
swUpdate.available.subscribe(() => {
window.location.reload();
});
resolve();
});
};
我不確定是否需要 APP_INITIALIZER 和 checkForUpdate,但這樣我將延遲減少到 1-2 秒(而不是 5-10 秒甚至更多)
TA貢獻1893條經驗 獲得超10個贊
我使用 Carrm 和 NeNad 的兩個答案在我的 Angular 應用程序中創建一個頁面來管理更新。
我還使用@saithodev/ts-appversion包來管理版本。
稍后,我創建了一個腳本來更新每個構建的應用程序版本并將其顯示在該頁面上 (appversionupdate.mjs)。
然后,在 package.json 中,我將腳本設置為與 npm run 一起使用。
這樣,當我構建和部署項目時,版本會根據需要進行更新。
我知道 OP 并沒有要求所有這些,但它可能對社區有用。
menu.component.html
<mat-toolbar color="accent" fxLayout="row" fxLayoutAlign="space-between center" class="top-bar">
<div fxLayout="row" fxLayoutAlign="start center">
<h1>Atualiza??o do app</h1>
</div>
</mat-toolbar>
<main>
<div>
<h2>Vers?o do app instalada: {{versao}}</h2>
</div>
<h3>Status da atualiza??o</h3>
<!-- lista sem numera??o em HTML -->
<ul>
<li *ngFor="let mensagem of mensagens">
{{mensagem}}
</li>
</ul>
<button mat-raised-button color="accent" (click)="atualizarApp();" class="botao">Atualizar app</button>
</main>
menu.component.ts
import { Component, OnInit } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { versions } from 'src/_versions';
@Component({
selector: 'app-menu',
templateUrl: './menu.component.html',
styleUrls: ['./menu.component.scss']
})
export class MenuComponent implements OnInit {
mensagens: string[] = [];
versao: string = 'Vers?o ainda n?o carregada pelo sistema.';
constructor(
private readonly swUpdate: SwUpdate,
) { }
ngOnInit(): void {
this.atualizarApp();
this.versao = versions.version;
}
async atualizarApp() {
this.mensagens?.push(`${this.getFormattedDate()} Iniciando atualiza??o do app.`);
try {
// Check if Service Worker is supported by the Browser
if (this.swUpdate.isEnabled) {
this.mensagens?.push(`${this.getFormattedDate()} Verificado que este navegador suporta a atualiza??o do app.`);
const isNewVersion = await this.swUpdate.checkForUpdate();
this.mensagens?.push(`${this.getFormattedDate()} Verificando se há nova vers?o a ser baixada.`);
// Check if the new version is available
if (isNewVersion) {
this.mensagens?.push(`${this.getFormattedDate()} Nova vers?o do app encontrada. Fazendo download.`);
const isNewVersionActivated = await this.swUpdate.activateUpdate();
// Check if the new version is activated and reload the app if it is
if (isNewVersionActivated) {
this.mensagens?.push(`${this.getFormattedDate()} Nova vers?o baixada e instalada.`);
window.location.reload();
}
} else {
this.mensagens?.push(`${this.getFormattedDate()} O Materiale app já está atualizado.`);
}
} else {
this.mensagens?.push(`${this.getFormattedDate()} Verificado que este navegador n?o suporta a atualiza??o do app automática e outras funcionalidades.`);
this.mensagens?.push(`${this.getFormattedDate()} Por favor, atualize o navegador para a vers?o mais recente. Baixe preferencialmente o Google Chrome.`);
}
} catch (error) {
this.mensagens?.push(`${this.getFormattedDate()} Houve algum error ao tentar atualizar o app. Mensagem de erro: ${error}`);
this.mensagens?.push(`${this.getFormattedDate()} é possível que este navegador n?o seja compatível. Por favor, atualize o navegador para a vers?o mais recente. Baixe preferencialmente o Google Chrome.`);
this.mensagens?.push(`${this.getFormattedDate()} Mensagem de erro: ${error}`);
//window.location.reload();
}
}
getFormattedDate(): string {
var date = new Date();
var str = `${date.getDate()}/${(date.getMonth() + 1)}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`;
return str;
}
}
appversionupdate.mjs
import fs from 'fs';
//console.log("Atualizado versao do app");
var obj = JSON.parse(fs.readFileSync('package.json', 'utf8'));
var version = obj.version;
var major = version.split('.')[0];
var minor = version.split('.')[1];
var patch = version.split('.')[2];
var minor_updated = Number(minor) +1;
var version_updated = major + '.' + minor_updated + '.' + patch;
console.log("Nova versao: " + version_updated);
obj.version = version_updated;
let data = JSON.stringify(obj, null, 2);
fs.writeFileSync('package.json', data);
包.json
{
"name": "testeapp",
"version": "0.14.0",
"scripts": {
"ng": "ng",
"prestart": "ts-appversion",
"start": "ng serve",
"prebuild": "ts-appversion",
"build": "ng build",
"watch": "ng build --watch --configuration development",
"test": "ng test",
"bd": "node ./appversionupdate.mjs && npm run build && firebase deploy"
},
TA貢獻1816條經驗 獲得超4個贊
問題
Angular 中的 Service Worker 有 4 種不同的注冊策略,這決定了它何時向瀏覽器注冊。
registerWhenStable:<timeout>: 應用程序穩定后立即注冊(沒有掛起的微/宏任務),但不遲于毫秒。如果應用程序在幾毫秒后還沒有穩定下來(例如,由于重復的異步任務),無論如何都會注冊 ServiceWorker。如果省略,ServiceWorker 將僅在應用程序穩定后注冊。registerImmediately: 立即注冊。registerWithDelay:<timeout>: 注冊延遲毫秒。例如,使用 registerWithDelay:5000 在 5 秒后注冊 ServiceWorker。如果省略,則默認為 0,一旦所有待處理的微任務完成,它將盡快注冊 ServiceWorker,但仍然是異步的。An Observable factory function: 一個返回 Observable 的函數。該函數將在運行時用于獲取和訂閱 Observable,并且只要發出第一個值,就會注冊 ServiceWorker。
注意: Angular默認registerWhenStable:30000使用. 這意味著它將首先等待應用程序穩定,然后它會注冊一個 Service Worker(或者如果應用程序在此之前沒有穩定,它將在 30 秒后注冊 Service Worker)。
解決方案
registerWhenStable:30000您可以設置registerImmediately策略而不是 default 。然后,您可以例如添加APP_INITIALIZER并在其中檢查是否有新版本并加載它。在這種情況下,如果有新版本可用,用戶將看不到舊版本。
app.module.ts
import { APP_INITIALIZER } from '@angular/core';
import { ServiceWorkerModule, SwUpdate } from '@angular/service-worker';
...
function initializeApp(): Promise<any> {
return new Promise(async (resolve, reject) => {
try {
// Check if Service Worker is supported by the Browser
if (this.swUpdate.isEnabled) {
const isNewVersion = await this.swUpdate.checkForUpdate();
// Check if the new version is available
if (isNewVersion) {
const isNewVersionActivated = await this.swUpdate.activateUpdate();
// Check if the new version is activated and reload the app if it is
if (isNewVersionActivated) window.location.reload();
resolve(true);
}
resolve(true);
}
resolve(true);
} catch (error) {
window.location.reload();
}
});
}
...
@NgModule({
...
imports: [
...,
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
registrationStrategy: 'registerImmediately',
}),
],
providers: [
...,
{ provide: APP_INITIALIZER, useFactory: initializeApp, deps: [SwUpdate], multi: true },
],
})
export class AppModule {}
添加回答
舉報
