Are Complex Pledges Possible in Typescript or Javascript?

I've encountered a problem while developing my Angular2-based mobile app using Typescript with Nativescript runtime. The issue revolves around Promises when working with Bluetooth functions in my HomeComponent. These Bluetooth functions require human interaction and have wait periods for scanning, which results in delayed completion of several seconds.

To tackle this issue, I decided to abstract these methods as promises. Here's what I did:

HomeComponent.ts:

bluetoothAdd() {
    this.isScanning = true;
    this._ble.scan().then(
        // Log the fulfillment value
        function (val) {
            this.isScanning = false; //hide activity indicator
            this.Connect(this.ble._peripheral);
        })
        .catch(
        function (reason) {
            this.isScanning = false; //hide activity indicator
            console.log('Handle rejected promise (' + reason + ') here.');
        });
}

BluetoothUtils.ts (this is imported above as this._ble):

var devices: Array<string>;
var _peripheral: any;

export function scan() {
    return new Promise((resolve, reject) => {
        bluetooth.hasCoarseLocationPermission().then(
            (granted) => {
                if (!granted) {
                    bluetooth.requestCoarseLocationPermission();
                } else {
                    bluetooth.startScanning({
                        serviceUUIDs: ["133d"],
                        seconds: 4,
                        onDiscovered: (peripheral) => {
                            console.log("Periperhal found with UUID: " + peripheral.UUID);
                        }
                    }).then(() => {
                        console.log("scanning complete");

                    }, (err) => {
                        console.log("error while scanning: " + err);
                    });
                }
            });
    });
}

During debugging, when bluetoothAdd() is called in my HomeComponent, the scan() function in BluetoothUtils behaves as expected. Under certain circumstances, it even displays an error message saying:

error while scanning: Bluetooth is not enabled

However, neither the then nor the catch parts of the HomeComponent's this._ble.scan() promise are executed. Why is this happening? Can you nest Promises (i.e., a promise within a promise) as I am attempting here? Any suggestions on how to debug this further?

Answer №1

There are a couple of issues to address.

1/ The use of an anti pattern is unnecessary in this scenario. Creating a new promise in scan when dealing solely with promises is redundant.

2/a) If opting to continue with the anti pattern, remember to invoke the resolve and reject functions. Currently, the new promise remains unresolved, causing the "main" promise in scan to stay in limbo.

2/b) A more effective approach is to return the existing promises instead of creating new ones. Failing to return them will result in separate branches of promises, which will not impact the "main" branch in scan. See the improved solution below:

export function scan() {
    return bluetooth.hasCoarseLocationPermission().then(
        (granted) => {
            if (!granted) {
                return bluetooth.requestCoarseLocationPermission();
            } else {
                return bluetooth.startScanning({
                    serviceUUIDs: ["133d"],
                    seconds: 4,
                    onDiscovered: (peripheral) => {
                        console.log("Peripheral found with UUID: " + peripheral.UUID);
                    }
                }).then(() => {
                    console.log("Scanning complete");

                }, (err) => {
                    console.log("Error while scanning: " + err);
                });
            }
        });
}

Note the three additional returns: one at the beginning of scan, and before

bluetooth.requestCoarseLocationPermission
and bluetooth.startScanning.

To explore other common promise anti patterns, check out this informative resource.

Answer №2

When working with typescript, it's advisable to avoid using the traditional way of handling asynchronous operations with await/async. This improves code clarity, especially when dealing with multiple promises simultaneously.

async function bluetoothAdd() {
    this.isScanning = true;
    try {
        const val = await this._ble.scan();
        this.Connect(this.ble._peripheral);
    } catch (reason) {
        console.log('Handle rejected promise (' + reason + ') here.');
    }finally{
        this.isScanning = false;
    }
}


// Bluetoo.....ts
var devices: Array<string>;
var _peripheral: any;

export async function scan() {
    const granted = await bluetooth.hasCoarseLocationPermission();
    if(!granted){
        return bluetooth.requestCoarseLocationPermission();
    }else{
        try {
            const val = await bluetooth.startScanning({
                    serviceUUIDs: ["133d"],
                    seconds: 4,
                    onDiscovered: (peripheral) => {
                        console.log("Periperhal found with UUID: " + peripheral.UUID);
                    }
                });
            console.log("scanning complete");
            return val;
        } catch (err) {
            // you can rethrow err here such that user `bluetoothAdd` will recieve it/
            console.log("error while scanning: " + err);
        }
    }
}

Answer №3

Upon further examination, it appears that the initial code block within the first "then" statement may not be returning any value, specifically a promise. A proper sequence would involve returning something like 'bluetooth.startScanning(...)' in order to fulfill the expected behavior. While it is possible to nest promises, a more organized approach would involve chaining them together for improved readability. In this case, consider moving the following console.log statement to the same level of nesting as the preceding "then" statement for a clearer structure.

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

"Graphs not Displaying Properly in ChartJs

Seeking assistance with rendering a chart inside a bootstrap popover. Despite various debugging attempts, the chart refuses to render. Any help or insight would be greatly appreciated. Below is my HTML code: <div id="popover-content" style=&qu ...

Using the jQuery before() method to manipulate form fields

Is it possible to utilize the jQuery before method to insert a form? An example scenario could be as shown below: <script> $(document).ready(function() { $("button").click(function() { $("button").before('<form><input type="text ...

Utilizing IBM Worklight: Maximizing Function Reusability in a Multi-Page Application

I have implemented the doTimer() function on the first page, and now I am attempting to utilize the same function on the second page. However, it is not working as expected. Can someone provide assistance? Below are my HTML and JavaScript code snippets: ...

Struggling to transfer information from JavaScript to Python Flask?

I am currently working on a basic configuration where I need to send a string to my Flask application through Ajax, but unfortunately, I am encountering Error code 400: Bad request. Here is the JavaScript code snippet: headers = { 'Content-type&a ...

Is there a way to modify the document title using .ready()?

As I work with nested layouts in Ruby on Rails, one particular layout requires me to extract a string from a div and use it as the title of the document. What is the proper method (if there is one) to accomplish this task? <script type="text/javascri ...

Automated configuration of AWS Amplify JavaScript using Gitpod

Looking to streamline the setup process for an AWS Amplify JavaScript project on Gitpod. My goal is to eliminate the manual steps of configuring the amplify-cli, such as adding IAM users and generating the aws-exports.js file. Successfully installed the a ...

Issue with triggering onclick event in both parent and child components

I am working with 2 components in Vue.js: An Accordion header that opens its content when clicked on. A Cog icon that opens a mini-modal menu. The issue arises when I click on the cog icon - I do not want the Accordion to open its content. Before click ...

After a span of two minutes, the Node.js and Express server terminates the connection

I am currently working with Express 4.X and Node.js 0.12. One of the routes in my application is responsible for uploading and processing files. However, I have encountered an issue where some file uploads are taking longer than the default 2-minute timeo ...

Stop the items from moving around in a cdkDropList in Angular Material

I am encountering an issue with the Drag and Drop feature in Angular Material (Angular 8). Here is the code I have developed: <div class="example-container"> <div id="receiver-container" cdkDropListOrientation="horizo ...

Sorting from HTML5 Local Storage

I have implemented local storage for storing user entries and displaying them on a different page. I am now seeking a method to sort these entries based on the most recent date and time of edit. Is it possible to achieve this using HTML5? If not, what woul ...

Encountered a problem while initiating the HTTP server in a node.js

I'm currently attempting to initiate an HTTP server from my index.js file. After going through The Node Beginner tutorial, I've been encountering errors every time I try to start the server using the provided code: Server.js - var http = re ...

Use patchValue to assign a value and make the field inactive

After loading a list and pushing it into a FormArray, I am in need of dynamically setting the disabled property for certain fields. My question is: Can I achieve this by using only the patchValue method? I attempted something like this.rowArray.controls[i ...

I am facing an issue with properly linking my jQuery

After searching through numerous posts on this website, I have yet to find a solution to my problem. My issue involves trying to implement a simple jQuery function that is not functioning as expected. It appears that the jQuery link may not be properly set ...

Guide on dynamically adding elements to an array in key value format

Struggling to create a dynamic JSON array that stores name, email ID, and password of users every time someone signs up? I managed to do it for one user, but now I'm stuck trying to create a loop and push elements into the array. Any advice on how to ...

Error message: "SyntaxError: Unexpected token import was not caught by the foundation"

I have recently taken over development from a previous developer who integrated Zurb Foundation as a framework into our website. The Foundation framework was installed using npm. I am encountering errors in the console related to all of the foundation java ...

Guide on integrating next-images with rewrite in next.config.js

I'm currently facing a dilemma with my next.config.js file. I've successfully added a proxy to my requests using rewrite, but now I want to incorporate next-images to load svg files as well. However, I'm unsure of how to combine both functio ...

What is the best approach to extracting tightly-coupled code and converting it into an external library?

I have a question regarding paradigms that I would like to address, and if this is not the appropriate platform, please guide me to the right place. Your recommendations are most welcome :) Currently, I am tasked with extracting a significant piece of fun ...

The resolution of custom Vue modules appears to be malfunctioning

UPDATE Good news - I have successfully resolved the problem and provided the solution below. Question I started a new project in Vue using the command: vue create hello-world with all the default options selected. Subsequently, I created an index.ts fi ...

Executing gruntfile from the devDependencies module

Currently, I am testing out a .js framework. Within my package.JSON file, specifically inside devDependencies, I have the following: "devDependencies": { "myFramework": "https://github.com/myRepo/myFramework/tarball/master", "grunt": "~0.4.2", ...

Failed to retrieve the item stored in the local storage

I am encountering an issue where I am unable to retrieve an item from local storage and display it. In store.js, I am trying to get the shippingAddress from local storage but it is not showing up in the form. Although I am able to set the shippingAddress i ...