javascript - 如何使用/重构嵌套的 Promise?

标签 javascript typescript promise

我在 TypeScript 应用程序中使用 Promises 从尽可能最佳的来源获取数据。首先应尝试 localStorage,然后对我的服务器进行 API 调用。我不确定这种方法是否是最好的,所以欢迎评论。

loadData(): Promise<void> {
    return this.loadFromLocalStorage()
        .catch(() => {
            this.loadFromApi();
        })
}

loadFromLocalStorage() : Promise<void> {
    return new Promise((resolve, reject) => {
        if( !this.isSupported(() => localStorage) ) reject("Localstorage is not supported");
        data = JSON.parse( localStorage.getItem('metadata') );
        if( !data || !data.date ) {console.log("no data"); reject("Not all data was present");}
        this.setData(data, false).then(() => {resolve()});
    });
}

loadFromApi() : Promise<void> {
    return new Promise((resolve, reject) => {
        this.http.get<{date?:string,ddi?:number,stoff?:number}>(this.apiUrl+'meta.json')
        .subscribe(data => {
            this.setData(data, true).then(() => resolve());
        },
        () => {
            reject("API call failed");
        });
    });
}

setData(data, saveToLocal: boolean) : Promise<void> {
    return new Promise((resolve) => {
        let promises: Promise<Pilot|void>[] = [];
        if (data.ddi) {
            promises.push( this.pilotService.getById(data.ddi).then(ddi => this.ddi = ddi) );
        }
        // There's more promises by the way, this is simplified
        Promise.all(promises).then(function() {
            resolve();
        });
    });
}

现在我知道这里有一些错误,但主要问题是:如何处理在 promise 中返回 promise ?有必要吗?我尝试寻找一种解决方案来解决问题,但找不到一个考虑到当第一个 promise (从 localStorage 获取)失败时某些操作不会发生的解决方案。

最佳答案

您发布的答案中改进的代码很好,但仍然可以使其更加简洁和可维护:

  1. 请注意,异步函数始终返回 Promise。您基本上只是将每个函数体包装在 Promise 中以使它们返回一个函数体,但如果您将包含的函数设为异步,则这是不必要的。
  2. 我没有使用 bool 值来指示成功/失败状态,而是使用了rejected Promises,因为它在JavaScript中更惯用,并且使用async/await,您可以以直观的“同步”方式编写它(异步函数中的throw导致返回的 Promise 拒绝)
  3. 当您可以返回一个指示成功的值时,我强烈建议您这样做 - 您是否实际使用它并不重要,但如果您确实需要它,它可以简化现有代码。
  4. 您可以使用try/catch当使用await时作为处理方法await ed Promise 拒绝,它使代码非常直观
  5. 风格挑剔:您对分号的使用不一致。使用分号或不使用分号都可以,但您应该坚持使用其中之一。它提高了可读性,如果其他人接触您的代码,他们不会对何时使用分号有任何疑问。
<小时/>
async loadData(): Promise<void> {
    try {
        return await this.loadFromLocalStorage(); //await this one to catch rejections
    } catch(e) {
        console.log(e.message); //handle error
        return this.loadFromApi(); //await or don't await this one, same result
    }
}

async loadFromLocalStorage() : Promise<Pilot[]> {
    if( !this.isSupported(() => localStorage) ) throw new Error("Not Supported");
    //if JSON.parse errors, the promise will also convert the exception to a rejection
    data = JSON.parse( localStorage.getItem('metadata') );
    if( !data || !data.date ) throw new Error("No Data");
    //this function returns a promise resolving with whatever `setData` resolves with
    //or rejects if `setData` rejects
    return this.setData(data, false);
}

//this one still needs to return a promise as it wraps a .subscribe()
loadFromApi() : Promise<(Pilot|void)[]> {
    return new Promise((resolve, reject) => {
        this.http.get<{date?:string,ddi?:number,stoff?:number}>(this.apiUrl+'meta.json')
            .subscribe( data => {
                resolve(this.setData(data, true)); //resolve with the data
            },
            reject); //if there's an error, just reject with the error
    });
}

async setData(data, saveToLocal: boolean) : Promise<(Pilot|void)[]> {
    let promises: Promise<Pilot|void>[] = [];
    if (data.ddi) {
        promises.push( this.pilotService.getById(data.ddi).then(ddi => this.ddi = ddi) );
    }
    //Promise.all will reject if any one of the inner promises rejects
    //To circumvent this, add a .catch() to the inner promises
    return Promise.all(promises);
}

此代码遵循 Promises 和 async/await 的更惯用用法。每个函数要么解析(如果成功),并返回一个有意义的值;要么拒绝(如果由于某种原因失败),并返回一个有意义的错误。

由于 async/await,任何错误也会导致拒绝将堆栈一直“冒泡”到调用者,即如果 loadFromApi() 中出现问题。 Promise 将拒绝并出现错误,然后导致 loadData()也拒绝同样的错误,将其暴露给调用 loadData() 的函数并允许您封装此数据 API 的错误处理(任何内部函数引起的任何错误都可以“冒泡”到入口点 loadData() 并根据您的意愿进行处理)

关于javascript - 如何使用/重构嵌套的 Promise?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59769371/

相关文章:

javascript - 如果在其字段中包含 SQL 语句,则验证对象

types - 定义 TypeScript 回调类型

javascript - 沿 Promise 链传递值

node.js - Bluebird promise 和回调,没有错误参数

javascript - Angular $q.reject().success(),这有意义吗?

javascript - mysql查询子孙

javascript - JavaScript 中从字符串获取函数

javascript - 如何递归地在 ES6 中编写箭头函数?

javascript - 更改传单上的图标

typescript - 自动从父类导入对象