我如何在Aurelia中使用Promises?

Bim*_*P.B 1 javascript aurelia

我有2个文件1. api_service.ts

import { HttpClient } from 'aurelia-http-client';
import { autoinject } from "aurelia-framework";
import { ObserverLocator } from "aurelia-binding";

@autoinject()
export class ApiServices {
    private app_url = 'http://example.com/';
    private host = 'http://api.example.com:8080';

    constructor(private store: Store, private client: HttpClient, private observerLocator: ObserverLocator) { }

    GetInstallationId() {
        let url = this.host + "/1/api/iid";
        let iid;
        this.client.get(url)
            .catch((err) => { })
            .then(res => {
                let response = JSON.parse(res.response);
                iid = response.iid;
            });
        return iid;
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里,我试图从服务器和HTTP响应中获得一些价值,我可以看到我得到它.

  1. board_services.ts

import { Store } from './localstorage_service';
import { ApiServices } from './api_service';
import { autoinject } from "aurelia-framework";
import { ObserverLocator } from "aurelia-binding";

@autoinject()
export class AppServices {
	private installation_ID: string;

	constructor(private store: Store, private apiServices: ApiServices, private observerLocator: ObserverLocator) { }

	getInstallationID() {
		const iid = this.store.getValue('installation_ID');
		console.log("iid = " + iid);
		if (iid && iid != undefined) {
			console.log('inside if iid');
			// this.installation_ID = this.apiServices.GetInstallationId();
			this.installation_ID = iid;
		} else {
			console.log('inside else iid');
			this.installation_ID = this.apiServices.GetInstallationId();
		}
		this.store.setValue('installation_ID', this.installation_ID);
		console.log("after if condition iid = " + iid);
		return this.installation_ID;
	}
}
Run Code Online (Sandbox Code Playgroud)

在这段代码中,我正在调用函数GetInstallationId(),api_services.ts但它并没有等待http request完成.有没有办法在执行后使下一个语句中的语句执行GetInstallationId()

sha*_*nvl 7

简短的回答:您需要支持异步行为.

你可以通过(a)Promises和/或(b)async/await来做到这一点.除了IE 11之外,所有浏览器支持前者,如果你需要支持IE 11,那么有像这样的polyfill.后者目前在IE中根本不受支持,因为它需要新的JS关键字/语法必须与一个转换器一起使用像巴贝尔.

这个答案将使用Promises,因为它们的依赖性比async/await少.下面的片段已更新为使用Promises - 查找以下评论:

// REPLACED THIS LINE ... // WITH THIS LINE

// ADDED THIS LINE

它标识更新.

  1. GetInstallationId 是一个异步函数,必须返回一个promise.

    
    class ApiServices { 
        ... 
        GetInstallationId() {
            let url = this.host + "/1/api/iid";
            return new Promise(function(accept, reject) {                
                let iid;
                this.client.get(url)
                    .catch((err) => { })
                    .then(res => {
                        let response = JSON.parse(res.response);
                        // REPLACED THIS LINE
                        // iid = response.iid;
                        // WITH THIS LINE which accepts the promise
                        accept(response.iid);
                    })
                    // ADDED THIS LINE to catch any errors 
                    // e.g. when invalid response received
                    .catch(reject);        
            });
        }
    
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 因为getInstallationID电话GetInstallationId,它也必须返回一个承诺.此示例定义了一个单独的函数,handler然后通过.bind(this)该函数进行绑定,以确保无论何时执行该函数,this都将始终引用回正确的ApiService对象.

    
    class AppServices {
        ...
        getInstallationID() {
    
    
      function handler(accept, reject) {
        const iid = this.store.getValue('installation_ID');
        console.log("iid = " + iid);
        if (iid && iid != undefined) {
            console.log('inside if iid');
            // this.installation_ID = this.apiServices.GetInstallationId();
            this.installation_ID = iid;
        } else {
            console.log('inside else iid');
            // REPLACED THIS LINE
            // this.installation_ID = this.apiServices.GetInstallationId();
            // WITH THIS LINE
            this.apiServices.GetInstallationId().then(accept,reject);
        }
        this.store.setValue('installation_ID', this.installation_ID);
        console.log("after if condition iid = " + iid);
        // REPLACED THIS LINE
        // return this.installation_ID;
        // WITH THIS LINE
        accept(this.installation_ID); 
      };
    
      return new Promise(handler.bind(this));        
    }        
    ...
    
    Run Code Online (Sandbox Code Playgroud) }

    上面的函数只是一个跨浏览器工作的例子.另一个需要ES6支持和/或转换的解决方案是使用箭头功能:

    
        //
        // Arrow function version
        //
    class AppServices {
        ...
        getInstallationID() {
          // NOTE the => which is shorthand for `(function (accept,reject) {...}).bind(this)`
          return new Promise((accept, reject) => {
            const iid = this.store.getValue('installation_ID');
            console.log("iid = " + iid);
            if (iid && iid != undefined) {
                console.log('inside if iid');
                // this.installation_ID = this.apiServices.GetInstallationId();
                this.installation_ID = iid;
            } else {
                console.log('inside else iid');
                // REPLACED THIS LINE
                // this.installation_ID = this.apiServices.GetInstallationId();
                // WITH THIS LINE
                this.apiServices.GetInstallationId().then(accept,reject);
            }
            this.store.setValue('installation_ID', this.installation_ID);
            console.log("after if condition iid = " + iid);
            // REPLACED THIS LINE
            // return this.installation_ID;
            // WITH THIS LINE
            accept(this.installation_ID); 
          });        
        }        
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

通过上面的重构,您现在可以getInstallationID()从例如另一个视图模型调用:

import {AppServices} from '...';
import {autoinject} from 'aurelia-framework';
@autoinject()
export class SomeViewModel {
    constructor(appServices) {
        this.appServices = appServices;
    }

    callGetInstallationId() {

        this.appServices.getInstallationID().then(function(id) {
            // the ID that is passed here is the one that is `accept`ed.
            // ie. if AppServices.getInstallationID calls accept('123'), then 
            // the '123' will be passed to this function as the first argument
        }, function(e) {
            // this function will be called if AppServices.getInstallationID
            // calls reject.  e will be the Error object, if any, that is passed
            // to the reject method.
        });

    }
}
Run Code Online (Sandbox Code Playgroud)