Exploring nested promises in TypeScript and Angular 2

I have a method called

fallbackToLocalDBfileOrLocalStorageDB
, which returns a promise and calls another method named getDBfileXHR, also returning a promise.

In the code snippet provided, I am unsure whether I need to use 'resolve()' explicitly or if resolving getDBfileXHR will automatically resolve

fallbackToLocalDBfileOrLocalStorageDB
.

Although I have commented out the then().catch() parts, I am uncertain about whether I should remove them entirely.

fallbackToLocalDBfileOrLocalStorageDB() {
        return new Promise(function (resolve, reject) {
            if (this.storageService.get('prodata') === null) { 
                if (this.connectionStatus.f() !== 'online') {
                } else {
                    this.sendErrorEmail("BL: online but falling back to local proDB", 10);
                }
                console.log('...falling back to local proBD.jsonp.');
                return this.getDBfileXHR('proDB.jsonp');
                    // .then(function () {
                    //    console.log('...falling back to local proBD.jsonp succeeded.');
                    //    resolve();
                    // })
                    // .catch(, function () {
                    //    console.log('...error, shit.');
                    //    reject();
                    // });

EDIT showing the full nested functions, with partially fixed code:

import { Injectable } from '@angular/core';
...

export class UpdateProDB {

    constructor(
        ) {
    }   


    get() {
        var debugOptionUseLocalDB = 0,
        prodata = [],
        serverAttempts = 0;     return new Promise((resolve, reject) => {
            if (debugOptionUseLocalDB) {
                return this.fallbackToLocalDBfileOrLocalStorageDB();
            }
            if (this.connectionStatus.f() === 'online') {
                console.log("Fetching DB from the server:");
                return this.getDBfileXHR(this.dbUrl(), serverAttempts)
                .then(function (data) { 
                    console.log('-normal XHR request succeeded.');

                    resolve(data);
                })
                .catch((reason)=> {
                    if (typeof serverAttempts !== "undefined") serverAttempts++;
                    console.log('on passe dans le catch, serverAttempts = ', serverAttempts)
                    if (serverAttempts < 2) {
                        return this.getDBfileXHR(this.dbUrl(), serverAttempts)
                        .then(function () { 
                            console.log('-basic XHR request succeeded.');

                        })
                        .catch(function (){
                            console.log("-basic XHR request failed, falling back to local DB file or localStorage DB...");

                        })
                    } else {
                        console.log("-basic XHR request failed, falling back to local DB file or localStorage DB...");
                        return this.fallbackToLocalDBfileOrLocalStorageDB()
                        .then((data)=>{
                            resolve(data);
                        })
                        .catch((reason)=> {
                            reject(reason);
                        });
                    }
                });
            });
    }   

    getDBfileXHR(url, serverAttempts) {
        return new Promise((resolve, reject) => {
            var request = new XMLHttpRequest();
            request.open("GET", url, true);             
            request.onload = ()=> {
                if ( (request.readyState === 4) && ( (request.status >= 200 && request.status <= 299) || request.status === 304 || request.status === 0) ) {
                    console.log('-we get response '+request.status+' from XHR in getDBfileXHR');

                    var jsonText = request.responseText.replace("callback(", "").replace(");", ""); 

                    if (jsonText === '') {
                        console.error('-error');

                        reject({
                            status: request.status,
                            statusText: request.statusText
                        });

                    } else {
                        var parsedJson;
                        try {
                            parsedJson = JSON.parse(jsonText);
                        } catch (e) {
                            resolve(request.response);
                        }
                    }
                };
                request.onerror = ()=> {
                    reject({
                        status: request.status,
                        statusText: request.statusText
                    });
                };
                console.log("sending request.send()");
                request.send();

            });
    }   


    fallbackToLocalDBfileOrLocalStorageDB() {
        return new Promise((resolve, reject) => {
            if (this.storageService.get('prodata') === null) { 
                if (this.connectionStatus.f() !== 'online') {

                } else {
                    this.sendErrorEmail("BL: online but falling back to local proDB", 10);
                }
                console.log('...falling back to local proBD.jsonp.');
                return this.getDBfileXHR('proDB.jsonp', undefined)
                .then(function (data) {
                    console.log('...falling back to local proBD.jsonp succeeded.');
                    resolve(data);
                })
                .catch((reason)=> {
                    console.log('...error, shit.');
                    reject(reason);
                });
            } else { 
                resolve();
            }
        });
    }   

Answer №1

Start using arrow functions => instead of the traditional function to maintain the context of this keyword:

fallbackToLocalDBfileOrLocalStorageDB() {
        return new Promise((resolve, reject) => {
            if (this.storageService.get('prodata') === null) { 
                if (this.connectionStatus.f() !== 'online') {
                } else {
                    this.sendErrorEmail("BL: online but falling back to local proDB", 10);
                }
                console.log('...falling back to local proBD.jsonp.');
                return this.getDBfileXHR('proDB.jsonp');
                      .then(function (data) {
                         console.log('...falling back to local proBD.jsonp succeeded.');
                        resolve(data);
                     })
                      .catch((reason)=> {
                         console.log('...error, stuff.');
                        reject(reason);
                      });

You can access your data like this:

fallbackToLocalDBfileOrLocalStorageDB().then((data)=>{
   console.log(data);
})

Answer №2

An executor function is the argument passed to new Promise(). It is responsible for either resolving or rejecting the promise.

Attempting to return another Promise from this executor function will not work as explained on MDN, stating that "The return value of the executor is ignored."

This indicates that using an inner Promise in the manner you are trying won't be effective; instead, you must explicitly resolve or reject the promise as shown in your commented code.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Issue: Incompatibility in metadata versions detected for module .../ngx-masonry/ngx-masonry.d.ts. Level 4 version identified, whereas level 3 version

When using ngx-masonry, I encountered the following error message- ERROR in Error: Metadata version mismatch for module .../ngx-masonry/ngx-masonry.d.ts, found version 4, expected 3 Specifications: Angular 4 ngx-masonry 1.1.4 ...

Why async functions don't require a 'then' keyword

There are two functions that produce the same outcome: const p1 = async () => { return 1; }; const p3 = new Promise((resolve, reject) => { resolve(1); }); console.log(typeof p1.then); console.log(typeof p3.then); It is surprising that both fu ...

Is it possible to utilize pinia getter as the initial parameter in Vue3's watch function?

Issue Recap In Vue3, can Pinia getters be utilized as a watch target's first argument? System Details Vue version: 3.2.13 Pinia version: 2.1.4 TypeScript version: 4.5.5 Problem Description An error was encountered when attempting to reference the ...

Performing simultaneous document queries within a single API in MongoDB

I am currently working with an API written in typescript and attempting to execute parallel queries for the same document by using Promise.allSettled. However, I have noticed that it is performing poorly and seems to be running sequentially instead of in p ...

Issue with Reusable Component in Angular 11- not functioning as expected

Attempting to grasp and implement the concept of reusability in Angular. I am working on creating a reusable component using <mat-card> which I intend to use across different modules' components. Currently, I have set up a framework for reusabi ...

I encountered a problem while trying to install Angular Material within my Nx workspace

Currently in the process of setting up an Angular and React project within a Nx monorepo workspace. Encountering trouble while attempting to install Angular Material using npm i @angular/material I'm running Angular v16. Below is the specific error me ...

Discover the steps to dynamically set global data in Vue during runtime

I am currently working on a Vue application that requires fetching data from JSP at runtime, which means I cannot use .env files. As a solution, I am attempting to set data in Vue that can be accessed throughout the entire application (components, mixins, ...

Tips for defining types for specific CSS properties in TypeScript, such as variables

Perhaps there are already solutions out there, and I appreciate it if you can share a link to an existing thread. Nevertheless... In React, when I use the style prop, I receive good autocompletion and validation features like this example: What am I look ...

When using Angular 4 CanActivate guard in conjunction with a service, the component may not load properly. However, by simply using Observable

When attempting to implement the CanActivate guard in Angular, I encountered an issue where it didn't work when calling a service and using return true, or even return Observable.of(true);. However, the guard did work and the component loaded success ...

Error: Unable to locate the type definition file for the '@babel' package

I am currently working on a new project and here is the content of my package.json file. { "name": "dapp-boilerplate", "version": "1.0.0", "main": "index.js", "license": "MI ...

Obtain the count of unique key-value pairs represented in an object

I received this response from the server: https://i.stack.imgur.com/TvpTP.png My goal is to obtain the unique key along with its occurrence count in the following format: 0:{"name":"physics 1","count":2} 1:{"name":"chem 1","count":6} I have already rev ...

Error: Angular ngFor directive not displaying list item

I am trying to create a simple ul element with some li items in it using a component I designed: import { Component } from '@angular/core'; @Component({ selector: 'skin', templateUrl: './skin.component.html', styleUrls: ...

Guide on running PHP (WAMP Server) and Angular 2 (Typescript with Node.js) concurrently on a local PC

My goal is to create a Web app utilizing PHP as the server-side language and Angular 2 as the MVC framework. While researching Angular 2, I discovered that it is best practice to install Node.js and npm first since Angular 2 utilizes Typescript. Despite ha ...

Delete element from the array upon removal from the AutoComplete component

I am facing a challenge with the Material UI AutoComplete component in my project. The issue arises when I try to update the state of the associateList after clearing a TextField. Additionally, I would appreciate any guidance on how to handle removing an ...

Bidirectional data binding in Angular 2 for the class attribute

Utilizing twitter bootstrap tabs, I aim to monitor the application of the active class on the li tag as users switch between different tabs. My objective is to control tab activation through custom buttons by modifying the class attribute to activate direc ...

Ensuring the presence of TypeScript variables

Take a look at this code snippet: let str: string | null; function print(msg: string) { console.log(msg); } print(str); When running this code, the typescript compiler correctly identifies the error, stating that Argument of type 'string | nu ...

Utilizing custom i18n blocks for Vue 3 and Vuetify 3 to enhance locale messages

Looking to localize messages separately for each component? Check out this example for Vue 2. But how can it be done for Vue 3 and Vuetify 3? Here's what I've tried: package.json "dependencies": { "@mdi/font": "6.5 ...

Refreshing Angular 4 route upon modification of path parameter

I have been struggling to make the subscribe function for the params observable work in my Angular project. While I have successfully implemented router.events, I can't seem to get the subscription for params observable working. Can anyone point out w ...

Oops! There was an error: Unable to find a solution for all the parameters needed by CountdownComponent: (?)

I'm currently working on creating a simple countdown component for my app but I keep encountering an error when I try to run it using ng serve. I would really appreciate some assistance as I am stuck. app.module.ts import { BrowserModule } from &apo ...

What are the reasons behind the compilation failure of the react-sortable-hoc basic example when using typescript?

Take a look at this sample code snippet extracted from the official react-sortable-hoc webpage. import React, {Component} from 'react'; ... // Code snippet goes here ... render(<SortableComponent/& ...