【问题标题】:Typescript async function wrapping promise打字稿异步函数包装承诺
【发布时间】:2017-12-01 17:54:45
【问题描述】:

我目前正在使用 Typescriptionic 以及 async-await 的 JavaScript 新手。我试图很好地理解承诺,但我不知道如何包装调用多个承诺以返回承诺的方法。我会尽量详细说明:

基本上,我有一个可以创建SQLite 数据库的对象,当调用create() 方法时,它会在创建后返回带有实际数据库对象的Promise

那么,当promise解析并返回DB对象时,我需要用它在一个事务中执行一些语句来创建所有的表,当我调用时返回一个新的promise事务中所有语句的执行。

然后当事务完成并且一切顺利时,我需要将数据库对象分配给类属性并设置一个标志,指示数据库已创建并准备就绪。

所以我认为将这个数据库初始化内容包装在一个名为createDatabase() 或类似的方法中是个好主意,它返回一个Promise<SQLiteObject>,其中SQLiteObject 代表数据库。此方法将在初始化时调用,并且一旦一切正常,应该返回代表数据库的SQLiteObject,或者抛出一个错误,我将登录Promise.catch() 方法。

我对 Promise 以及如何使用 then()catch() 方法有基本的了解,但是当我必须创建数据库时,我有点困惑,然后在 Promise 解决时执行其他操作,并且当一切正常时完成后,返回一个包含 DB 对象的Promise,它是SQLiteObject 类的一个实例。


代码
以下是我当前的Typescript 代码。这不是有效的打字稿,因为我不知道如何从 async 函数返回 Promise<SQLiteObject>

async createDatabase(): Promise<SQLiteObject> {

        this.sqlite.create({
            name: this.dbName,
            location: this.dbLocation
        }).then( (db: SQLiteObject) => {
            // Insert all tables.
            let createTableParam: string = `CREATE TABLE IF NOT EXISTS param (name PRIMARY KEY NOT NULL, value TEXT)`;
            let createTableNews: string = `CREATE TABLE IF NOT EXISTS news (id PRIMARY KEY NOT NULL,title TEXT,
                content TEXT, image TEXT, date DATE)`;

            db.transaction(tx => {
                    tx.executeSql(createTableParam);
                    tx.executeSql(createTableNews);
                    // Add here more tables to create if needed
                }
            )
                .then( () => {
                    console.log('Tables were created');
                    this.isActive = true;
                })
                .catch(error => {
                    console.log(`Error creating tables - ${error}`);
                });
        }).catch(
            error => console.log(`Error at SQLite initialization - ${error}`)
        );
    }

研究至今

【问题讨论】:

    标签: javascript typescript asynchronous ionic-framework async-await


    【解决方案1】:

    您使用了async,这意味着您可以随时在函数中使用await,只要您有Promise,并且编写代码几乎就像它是同步的一样。

    async createDatabase(): Promise<SQLiteObject> {
        let db: SQLiteObject;
        try {
          db = await this.sqlite.create({
            name: this.dbName,
            location: this.dbLocation
          });
        } catch(error) {
            console.log(`Error at SQLite initialization - ${error}`);
            return;
        );
        // Insert all tables.
        let createTableParam: string = `CREATE TABLE IF NOT EXISTS param (name PRIMARY KEY NOT NULL, value TEXT)`;
        let createTableNews: string = `CREATE TABLE IF NOT EXISTS news (id PRIMARY KEY NOT NULL,title TEXT,
            content TEXT, image TEXT, date DATE)`;
    
         try {
           await db.transaction(tx => {
                    tx.executeSql(createTableParam);
                    tx.executeSql(createTableNews);
                    // Add here more tables to create if needed
                }
              );
    
           console.log('Tables were created');
           this.isActive = true;
           return db;
         catch(error) {
             console.log(`Error creating tables - ${error}`);
         });
    }
    

    如果没有await,您需要确保返回最初的承诺。

    return this.sqlite.create({...
    

    然后再往下你可以返回db 对象:

           this.isActive = true;
           return db;
    

    您还应该避免嵌套.then() 处理程序:当您获得另一个承诺时,只需从第一个处理程序返回它并在最后链接另一个.then

    createDatabase(): Promise<SQLiteObject> {
        let database: SQLiteObject = null;
        return this.sqlite.create({
            name: this.dbName,
            location: this.dbLocation
        })
        .catch(error => console.log(`Error at SQLite initialization - ${error}`))
        .then( (db: SQLiteObject) => {
            // Insert all tables.
            let createTableParam: string = `CREATE TABLE IF NOT EXISTS param (name PRIMARY KEY NOT NULL, value TEXT)`;
            let createTableNews: string = `CREATE TABLE IF NOT EXISTS news (id PRIMARY KEY NOT NULL,title TEXT,
                content TEXT, image TEXT, date DATE)`;
            database = db;
            return db.transaction(tx => {
                    tx.executeSql(createTableParam);
                    tx.executeSql(createTableNews);
                    // Add here more tables to create if needed
                }
            );
        })
        .then( () => {
            console.log('Tables were created');
            this.isActive = true;
            return database;
        })
        .catch(error => console.log(`Error creating tables - ${error}`));
    

    【讨论】:

    • 感谢您抽出时间 Ducan,使用异步是不是一个坏主意?我在 Typescript 2.1 上读到它是受支持的,它会转译为 ES5,所以我想没有任何问题......说到异步,如果我不使用异步函数并且不得不依赖,会不会一团糟直接管理Promises
    • 我猜你的意思是let db; try {不是try { const db,因为第二个在你以后使用db时会出错。
    • 很好,我正在那里进行重构,并在我已经完成其中的代码之后添加了try{}
    • @JorgeGRC 我添加了代码在没有异步的情况下的外观。转译为 ES5 适用于异步,但它生成的代码可能非常冗长,所以它实际上只是一个选择,您是否希望执行冗长且可能更慢的代码以换取在编译时更清晰的代码。
    • 哦,我现在明白了,不进入那种“承诺地狱”要清楚得多,感谢您提供的详细信息和指南,非常感谢
    【解决方案2】:

    看来你没有兑现承诺。

    必须解决或拒绝承诺,以便异步函数能够以值响应。

    来自 TypeScript 深入研究:

    const promise = new Promise((resolve, reject) => {
        resolve(123);
    });
    promise.then((res) => {
        console.log('I get called:', res === 123); // I get called: true
    });
    promise.catch((err) => {
        // This is never called
    });
    

    所以在我看来你应该创建一个promise,当数据库被创建并且一切都解决它时,如果数据库创建有问题,拒绝它。

    请记住,您可以链接承诺,因此您可以在创建数据库时链接它们。

    来自 TypeScript 深入研究:

    promise 的链式能力是 promise 提供的好处的核心。一旦你有了一个 Promise,从那时起,你就可以使用 then 函数来创建一个 Promise 链。

    查看URL 了解有关承诺的更多信息

    希望对您有所帮助! :)

    【讨论】:

    • 感谢您抽出宝贵时间亨利,这个答案确实也很有帮助,但我接受了邓肯的答案,因为它深入细节。我现在确实明白您想指出创建新承诺并在创建数据库时解决问题。谢谢
    • 只是想帮忙:)。我很高兴你现在更清楚了。祝你有美好的一天!
    猜你喜欢
    • 2021-06-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-14
    • 2019-03-18
    相关资源
    最近更新 更多