【问题标题】:Angular - get synchronously from PromiseAngular - 从 Promise 同步获取
【发布时间】:2017-07-05 23:37:20
【问题描述】:

我想打印产品历史。我在 ActivatedRoute.params 中有一个产品 ID。在 ngOnInit 方法中,我必须获取产品的所有历史记录并分配给变量。然后我想将产品映射到productHistory,因为我想拥有最后一个带有历史的版本。但问题在于获取历史。获取历史记录的方法返回 Promise,当我使用此属性时无法获取 productsHistory 的长度并且未定义。从服务加载后如何获取此属性?

我想在执行 getHistory() 后执行方法。

我的代码:

ProductService.ts:

import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';

import 'rxjs/add/operator/toPromise';

// rest imports

@Injectable()
export class ProductService {

    // URL to web api
    private projectsUrl = 'http://localhost:8080/products';

    private headers = new Headers({'Content-Type': 'application/json'});

    constructor(private http: Http) {}

    getHistory(id: number): Promise<ProductHistory[]> {
        const url = `${this.projectsUrl}/projectId/${id}`;
        return this.http.get(url)
            .toPromise()
            .then(response => response.json() as ProductHistory[])
            .catch(this.handleError);
    }

    handleError() {
        //...
        // implementation is irrelevant
    }
}

ProductHistoryComponent.ts:

import { Component, Input, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';

import { ProductService } from './product.service';

import { ProductHistory } from './product-history';
import { Product } from './model/product';

import 'rxjs/add/operator/switchMap';

@Component({
    selector: 'product-history',
    templateUrl: './product-history.component.html',
    styleUrls: [ './product-history.component.css' ]
})
export class ProductHistoryComponent implements OnInit {

    auditProducts: ProductHistory[] = new Array<ProductHistory[]>();    
    selectedProduct: ProductHistory;

    constructor(
        private route: ActivatedRoute,
        private location: Location,
        private productService: ProductService
    ) {}

    ngOnInit(): void {
        let id: number = this.route.snapshot.params['id'];

        this.productService.getHistory(id)
            .then(history => this.historyProducts = history);

        this.productService.getProduct(id)
            .then(product => {
                let lastVersion: ProductHistory = this.createLastVersion(product);
                this.auditProducts.push(lastVersion);
            });
    }

    onSelect(ProductHistory: ProductHistory): void {
        this.selectedProduct = ProductHistory;
        this.compare(this.selectedProduct);
    }

    goBack(): void {
        this.location.back();
    }

    compare(history: ProductHistory): void {
        let previous: ProductHistory;
        if (history.changeNumber != null && history.changeNumber > 1) {
            previous = this.historyProducts[history.changeNumber - 2];
            if (typeof previous != 'undefined') {
                this.setPreviousDiffsFalse(previous);
                if (previous.name !== history.name) {
                    history.nameDiff = true;
                }
                if (previous.price !== history.price) {
                    history.priceDiff = true;
                }
            }
        }
    }

    createLastVersion(product: Product): ProductHistory {
        let lastVersionProduct: ProductHistory = new ProductHistory();
        lastVersionProduct.id = this.historyProducts.length + 1;
        lastVersionProduct.name = product.name;
        lastVersionProduct.price = product.price;
        lastVersionProduct.changeNumber = this.historyProducts[this.historyProducts.length - 1].changeNumber + 1;
        return lastVersionProduct;
    }

    setPreviousDiffsFalse(previous: ProductHistory): void {
        previous.nameDiff = false;
        previous.priceDiff = false;
    }

}

【问题讨论】:

  • 你不能从一个承诺中同步地获得一个价值,就像你从一个橙子中获得一个苹果一样。

标签: javascript angular asynchronous promise


【解决方案1】:

您不能同步运行它,您必须等待每个 Promise 返回一个结果,然后才能对该结果执行某些操作。执行此操作的正常方法是在使用 Promise 时将代码嵌套在 then 块中。或者,您也可以将async/await 与最新版本的打字稿一起使用,并且您只需更改您的component 代码,因为您已经从您的服务中返回了Promise 类型。这使得代码更易于阅读 (IMO),尽管发出的 javascript 代码仍将使用函数/回调嵌套(除非你的目标是 es7,我相信,也许有人会纠正或确认这一点)。

// note the use of async and await which gives the appearance of synchronous execution
async ngOnInit() {
    let id: number = this.route.snapshot.params['id'];

    const history = await this.productService.getHistory(id);
    this.historyProducts = history;

    const product = await this.productService.getProduct(id);
    let lastVersion: ProductHistory = this.createLastVersion(product);
    this.auditProducts.push(lastVersion);
}

【讨论】:

    【解决方案2】:

    我建议使用 observables 而不是 promises ...但要回答您的问题,您只需要在收到第一个请求 之后执行第二个请求。像这样的:

    ngOnInit(): void {
        let id: number = this.route.snapshot.params['id'];
    
        this.productService.getHistory(id)
            .then(history => {
                   this.historyProducts = history);
    
                   this.productService.getProduct(id)
                         .then(product => {
                             let lastVersion: ProductHistory = this.createLastVersion(product);
                             this.auditProducts.push(lastVersion);
            });
         }
    }
    

    我只是将第二个请求移动到第一个请求的 then。注意:我没有对此进行语法检查。

    【讨论】:

      猜你喜欢
      • 2013-10-29
      • 2019-04-25
      • 2019-12-24
      • 1970-01-01
      • 2018-04-08
      • 2017-12-23
      • 1970-01-01
      • 2017-10-24
      相关资源
      最近更新 更多