我如何在Aurelia中使用Promises?

时间:2017-04-04 13:35:52

标签: 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;
    }
}

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

  1. board_services.ts
  2. 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;
    	}
    }

    此代码中我从GetInstallationId()调用函数api_services.ts,但它不等待http request完成。有没有办法在执行GetInstallationId()后执行下一个语句中的语句?

1 个答案:

答案 0 :(得分:7)

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

您可以通过(a)Promises和/或(b)async/await执行此操作。如果你需要支持IE 11,那么前者是supported in all browsers except IE 11并且有polyfills like this one。后者目前在IE中根本不受支持,因为它需要新的JS关键字/语法必须与转换器一起使用比如Babel

这个答案将使用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);        
            });
        }
    
    }
    
  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));        
    }        
    ...
    
    }
      

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

      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));        
    }        
    ...
    
  3. 通过上述重构,您现在可以通过以下方式调用 // // 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); }); } ... } 另一种视图模型如下:

    getInstallationID()