2017-07-14 43 views
3

我开始了一个简单的Angular2 Electron应用程序,并且我有一个查询本地SQL Server数据库的服务方法。到目前为止一切正常。现在我正尝试将服务数据库调用的结果获取到我的组件并以某种方式显示它。Angular2将服务方法从回调改为异步

的问题是,查询逻辑更多的回调语法编写:

sql.query(sqlString, (err, result) => { 
    ... 
    callback(result); 
    ... 
}); 

我有一个很难改写它返回一个承诺,因为其结果将永远是结果参数中查询命令功能。我的组件看起来是这样的:

export class LinkDocRetriever { 

    constructor(private myService: MyService) { } 

    results = ""; 

    loadMyData(id: number): void { 

    let tcData = this.myService.getMyData(); 
    tcData.forEach(element => { 
     this.results += element.FileName + " " + "....\n"; 
    }); 

    }; 
} 

我的服务是这样的:

import { Injectable } from "@angular/core"; 
import * as sql from "mssql"; 

@Injectable() 
export class MyService { 

    getMyData():Array<MyItem> { 

     let myData:Array<MyItem> = []; 

     let config = { 
      user: "sa", 
      password: "xxx", 
      server: "localhost", 
      database: "mydb" 
     }; 

     const pool1 = new sql.ConnectionPool(config, err => { 

      if (err) { 
       console.log("connect erro: " + err); 
      } 

      let q:string = `SELECT TOP 10 * FROM MyTable;`; 

      let final = pool1.request() 
      .query<MyItem>(q, (err, result) => { 
       if (err) { 
        console.log("request err: " + err); 
       } 

       console.log("db result count: " + result.recordsets[0].length); 
       result.recordsets[0].forEach(row => { 
        myData.push(row); 
       }); 
      }); 
     }); 
     return myData; 
    } 
} 

我得到的结果回来,但因为它回来返回结果之前该组件永远看不到它。

我试着在查询呼叫做一个的await,在连接池功能中,但我得到一个错误,说明等待着只能异步函数中调用,即使我已经异步对方法设置。 mssql包有一个Async/ Await section,但是当我尝试它时,该页面上的给定语法给出了错误。

任何想法如何我可以写这个使用承诺?

回答

3

正如您所指出的,有3种方法可以处理异步函数:使用回调,使用promise和使用Async/Await。我将尝试显示所有三种方式,但您应该了解JavaScript中的事件循环以及如何处理异步函数。

回调

回调是处理异步功能技术上最快的方式,但它是在第一次相当混乱,如果不正确使用可能会产生一种叫做回调地狱。回拨地狱是非常可怕的,有人甚至为它创建了一个网站http://callbackhell.com/

所以,你的代码可以改写为:

export class LinkDocRetriever { 

    constructor(private myService: MyService) { } 

    results = ""; 

    loadMyData(id: number): void { 

    // call getMyData with a function as argument. Typically, the function takes error as the first argument 
    this.myService.getMyData(function (error, tcData) { 
     if (error) { 
     // Do something 
     } 

     tcData.forEach(element => { 
     this.results += element.FileName + " " + "....\n"; 
     }); 
    }); 
    }; 
} 

服务

import { Injectable } from "@angular/core"; 
import * as sql from "mssql"; 

@Injectable() 
export class MyService { 
    // Now getMyData takes a callback as an argument and returns nothing 
    getMyData(cb) { 

     let myData = []; 

     let config = { 
      user: "sa", 
      password: "xxx", 
      server: "localhost", 
      database: "mydb" 
     }; 

     const pool1 = new sql.ConnectionPool(function(config, err) { 

      if (err) { 
       // Error occured, evoke callback 
       return cb(error); 
      } 

      let q:string = `SELECT TOP 10 * FROM MyTable;`; 

      let final = pool1.request() 
      .query<MyItem>(q, (err, result) => { 
       if (err) { 
        console.log("request err: " + err); 
        // Error occured, evoke callback 
        return cb(error); 
       } 

       console.log("db result count: " + result.recordsets[0].length); 
       result.recordsets[0].forEach(row => { 
        myData.push(row); 
       }); 

       // Call the callback, no error occured no undefined comes first, then myData 
       cb(undefined, myData); 
      }); 

     }); 
    } 
} 

无极

无极是一个特殊的对象,它允许您控制异步功能,避免回调地狱因为你不必使用嵌套的回调函数,只能使用一个级别thencatch函数。了解更多关于无极here

组件

export class LinkDocRetriever { 

    constructor(private myService: MyService) { } 

    results = ""; 

    loadMyData(id: number): void { 
    this.myService.getMyData() 
     .then((tcData) => { 
     // Promise uses then function to control flow 
     tcData.forEach((element) => { 
      this.results += element.FileName + " " + "....\n"; 
     }); 
     }) 
     .catch((error) => { 
     // Handle error here 
     }); 

    }; 
} 

服务

@Injectable() 
export class MyService { 
    // Now getMyData doesn't take any argument at all and return a Promise 
    getMyData() { 

     let myData = []; 

     let config = { 
      user: "sa", 
      password: "xxx", 
      server: "localhost", 
      database: "mydb" 
     }; 

     // This is what getMyData returns 
     return new Promise(function (resolve, reject) { 
      const pool1 = new sql.ConnectionPool((config, err) => { 

       if (err) { 
        // If error occurs, reject Promise 
        reject(err) 
       } 

       let q = `SELECT TOP 10 * FROM MyTable;`; 

       let final = pool1.request() 
        .query(q, (err, result) => { 
         if (err) { 
          // If error occurs, reject Promise 
          reject(err) 
         } 

         console.log("db result count: " + result.recordsets[0].length); 
         result.recordsets[0].forEach((row) => { 
          myData.push(row); 
         }); 

         // 
         resolve(myData); 
        }); 

      }); 
     }) 

    } 
} 

异步/等待

异步/ AWAIT被引入到解决与回调打交道时,你是有这个困惑并承诺。了解更多关于异步/等待here

组件

export class LinkDocRetriever { 

    constructor(private myService: MyService) { } 

    results = ""; 

    // Look. loadMyData now has to have async keyword before to use await. Beware, now loadMyData will return a Promise. 
    async loadMyData(id) { 

    // By using await, syntax will look very familiar now 
    let tcData = await this.myService.getMyData(tcData); 
    tcData.forEach((element) => { 
     this.results += element.FileName + " " + "....\n"; 
    }); 
    }; 
} 

服务是完全一样的无极因为异步/等待是专门为处理这些问题。

注意:我从代码中删除了一些Typescript功能,因为我更习惯于vanilla JS,但是您应该能够编译它们,因为Typescript是JS的超集。

+0

我认为我的问题是试图做到“老”的方式,返回一个promise.defer(),然后设置拒绝并解决。这种新的方式将整个承诺定义包装在异步代码的周围。 +1为额外的解释和清晰度。 – Ben