Executing asynchronous functions synchronously

I am relatively new to JavaScript programming and I am currently trying to grasp the concepts of asynchronous processes. In my project, I am looking to execute the following code synchronously. Despite watching numerous tutorials on the subject, I find most of them to be too superficial for my understanding...

The code itself is quite simple - it involves making a call to the Google Maps API with an address as input and receiving back the latitude and longitude coordinates. Following this, the code should then make a call to the server with the lat/lng data in the URL to retrieve all locations near the specified location.

Client:

$scope.findLocations = function () {
        var dist = 0.1;
        
        // Execute this
        getLatLong();
        
        // Before this
        $http.get('/api/locations/findByLocation/' + $scope.form.lng + '/' + $scope.form.lat + '/' + dist)
            .success(function(data) {
                $scope.locations = data;
                $scope.form = {};
                console.log("locations: ", data);
            })
            .error(function(data) {
                console.log('Error: ' + data);
            });
    };
    
    var getLatLong = function() {
        var geo = new google.maps.Geocoder;
        var address = $scope.form.adress;
        
        console.log(address);
        
        geo.geocode({'address': address}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Status geocoder OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();
                
                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);
                
                var mapProp = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };
                
                var map = new google.maps.Map(document.getElementById("map"), mapProp);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });
            } else {
                alert(status);
            }
        });
    };
    

Server:

router.get('/api/locations/findByLocation/:lng/:lat/:dist', function(req, res){
        var coords = [];
        coords[0] = req.params.lng;
        coords[1] = req.params.lat;
        
        Location.find({
            loc: {
                $near: coords,
                $maxDistance: req.params.dist
            }
        }).limit(30).exec(function(err, locations){
            if(err){
                res.json(err);
                console.log(err);
            }
            
            res.json(locations);
        });
    });
    

Answer №1

Implement JS Promise in your code

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

$scope.searchLocations = function() {

    var distance = 0.1;

    // Trigger this
    fetchCoordinates().then(function(resolve) {
        // Before this
        $http.get('/api/locations/findByLocation/' + $scope.form.lng + '/' + $scope.form.lat + '/' + distance)
            .success(function(data) {
                $scope.locations = data;
                $scope.form = {};
                console.log("Locations found: ", data);
            })
            .error(function(data) {
                console.log('Error occurred: ' + data);
            });
    }, function(error) {
        alert("An error has occurred!");
    });

};



var fetchCoordinates = function() {

    var geocoder = new google.maps.Geocoder;

    var address = $scope.form.adress;

    console.log(address);

    return new Promise(function(resolve, reject) {

        geocoder.geocode({
            'address': address
        }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Geocoder status is OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();

                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);

                var mapProperties = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };

                var map = new google.maps.Map(document.getElementById("map"), mapProperties);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });

                resolve(200);
            } else {
                reject(status);
            }

        });
    });
};

Answer №2

It is important to understand how Promises work in JavaScript. Here is an example:

var getLastCoordinates = function() {
    return $q(function(resolve, reject) {

        var geocoder = new google.maps.Geocoder;

        var address = $scope.form.address;

        console.log(address);

        geocoder.geocode({ 'address': address }, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                console.log("Geocoder status OK");
                $scope.form.lat = results[0].geometry.location.lat();
                $scope.form.lng = results[0].geometry.location.lng();

                var latlng = new google.maps.LatLng($scope.form.lat, $scope.form.lng);

                var mapProperties = {
                    center: latlng,
                    zoom: 18,
                    mapTypeId: google.maps.MapTypeId.ROADMAP,
                    mapTypeControl: false
                };

                var map = new google.maps.Map(document.getElementById("map"), mapProperties);
                var marker = new google.maps.Marker({
                    position: latlng,
                    map: map,
                    title: name
                });
                // Resolve with the marker payload.
                resolve(marker);

            } else {
                // Reject with the status code.
                reject(status);
            }
        });
    });
}

$scope.findLocations = function () {

    var distance = 0.1;
    getLastCoordinates()
    .then(function(marker) {
        $http.get('/api/locations/findByLocation/'+$scope.form.lng+'/'+$scope.form.lat+'/'+distance)
        .success(function(data) {
            $scope.locations = data;
            $scope.form = {};
            console.log("Locations: ", data);
        })
        .error(function(data) {
            console.log('Error: ' + data);
        });

    })
    .catch(function(error) {
        console.log(error)
    });
};

Official Promise API

Angular 1 implementation of Promise

Answer №3

My preferred approach to handling sequences of "this" and "that" in JavaScript is by utilizing promises. While there may be a slight learning curve involved, it ultimately results in cleaner and easier-to-maintain code, especially when working with asynchronous API calls. To begin, make sure to include the $q dependency in your Angular service (although it's not entirely clear from the provided code snippet which specific Angular component you're working within).

In the context of your example, the implementation would resemble the following:

 getLatLong()
 .then(function(longLat) {
      // handle response here
      $http.get('/api/locations/findByLocation/'+$scope.f...
      ...
      return something;
 })
 .then(function(something) {
      // do something else with 'something'
 });

Answer №4

When using the

geo.geocode({'address':address},function(results, status){...}
call, it's important to note that it operates asynchronously. This means that while the call is made to the Google Maps API, the rest of your code will continue executing without waiting for a response.

The callback function specified as the second parameter, function(results, status){...}, will only run once the asynchronous call has completed its task.

If you need to trigger a server call after receiving a response from the Google Maps API, make sure to place that code inside the callback like so:

geo.geocode({'address':address},function(results, status){
    if (status == google.maps.GeocoderStatus.OK) {
        console.log("Status geocoder OK");
        $scope.form.lat = results[0].geometry.location.lat();
        $scope.form.lng = results[0].geometry.location.lng();

        var latlng = new google.maps.LatLng($scope.form.lat,$scope.form.lng);

        var mapProp = {
                center:latlng,
                zoom:18,
                mapTypeId:google.maps.MapTypeId.ROADMAP,
                mapTypeControl: false
        };

        var map=new google.maps.Map(document.getElementById("map"),mapProp);
        var marker = new google.maps.Marker({
                position: latlng,
                map: map,
                title:name
        });

        // Execute server call here...
        //http.request(options, function(response){...})

    } else {
        alert(status);
    }

  });

To learn more about making HTTP calls, visit this link.

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

To begin, formulating a blank state entity containing a collection of key-value pairs with JSON objects as the values. Subsequently, modifying the contents of

I am working on setting up a reactJS state with an empty array to start. When I receive a message in the form of a JSON object, I want to add a key-value pair to the array, using the received message as the value and a specified key. For example: We have ...

Is it better to use Rollup for exporting individual components instead of lumping them all into one index.js

Currently, I am working on developing a custom component library using React and Rollup for bundling. The current setup bundles all components into two large files: dist ├ cjs │ └ index.js (1.7mb) └ esm └ index.js (1.7mb) I would like to ...

I would like to know the method for inserting an HTML element in between the opening and closing tags of another HTML element using

Recently, I came across a coding challenge involving a textbox. <input type="text></input> The task was to insert a new span element between the input tags using jQuery, as shown below: <input type="text><span>New span element< ...

The Passport authentication process continues indefinitely

I am facing an issue with my Node application where I am using Passport.js to connect to the Google+ API through a GoogleStrategy. Despite successfully reaching the auth/api route from my frontend (localhost:3000) to my server (localhost:5150), when the pa ...

retrieve Excel document via POST request

I have a scenario where my API endpoint accepts JSON input and returns an Excel file directly instead of providing a link to download the file. How can I use JQuery AJAX to download this file? Here is the backend code snippet: public function postExcel() ...

Angular 7 offers seamless synchronization for horizontal scrolling in a unique way

Can anyone provide guidance on how to achieve synchronized horizontal scrolling in an Angular project? I found a solution at the following link, but it uses jQuery code. Synchronized scrolling using jQuery? ...

Guide on applying a filter to the items in a listbox using the input from a text box

In my HTML form, I have the following elements: 1) A list box containing filenames: s1.txt2013 s2.txt2013 s3.txt2012 s4.txt2012 2) A text box where the user enters a pattern (e.g. 2013) 3) A button By default, the list box contains the 4 file ...

AngularJS DataGrid export options

Utilizing the angular-datatable plugin, complete with export buttons. You can see an example here: vm.dtOptions = DTOptionsBuilder.fromSource('data.json') .withDOM('frtip') .withPaginationType('full_numbers') // ...

What pitfalls come with having an abundance of dynamic URLs on a Node.js-Express.js server?

At the moment, I'm diving into the world of ExpressJs and NodeJs. My query revolves around the scenario where a substantial amount of URLs are dynamically registered in the server using the app.get("/xyz", page.xyz) method. I'm curious to know wh ...

Navigating Errors within Express Class Using Typescript

I encountered an issue while transforming my Express.js application into a Typescript class, specifically with error handling. Below is the content of my App.ts class file: import express from 'express'; import compression from 'compression& ...

Pressing the "Ctrl" key, click on the link that will display a

I received a link that utilizes AJAX to render a partial view. Below is the code for the link: <a href="#" onclick="LoadChildCategories(@i.CategoryId, @i.IsTrading.ToString().ToLower())">@i.Name</a> Here is the code for the LoadChildCa ...

Text that changes within a set-sized box

I'm working with a fixed-size div that contains dynamically generated text. Is there an easy method using DOJO or plain Javascript to truncate the text before the end of the div and add "..."? How can I accomplish this regardless of the font size bein ...

I am attempting to insert a collection of objects into my MongoDB database using Node.js

My goal is to store an array of objects into my mongodb database using the obj dummy data. However, when I run the code, it only saves an empty array instead of the objects. Here is the breakdown of my code: Schema const mongoose = require('mongoose& ...

Unable to execute the new firebase on node server

I'm currently watching this google talk. However, I am facing an issue trying to create a firebase object. Following my package.json file, I initiated with: npm install firebase --save Then proceeded with the following steps: let Firebase = requir ...

Experiencing difficulty retrieving individual :id information from a list in MEAN stack

**I'm experiencing issues retrieving a single :id from a list as the data returned is not what I expected... ** GET /article/5b0be8829f734a4e580a43c5 401 3.845 ms - 99 ===> response from my get request my api ===> var express = require ...

Complete the dynamic form submission in a non-blocking manner

My goal is to dynamically add text fields with the click of a button I also aim to extract data from these text fields and insert it into the database Currently, all functions work smoothly, I just need this additional feature. Per ...

Currently, I am in the process of developing an Express application that includes a user-friendly login form for individuals

I am currently developing an Express application with a login form. For the password encryption, I have implemented bcryptjs and made sure to include the secret_key in my git ignore file. My project consists of two controller files - one for users and anot ...

Ways to customize the appearance of an iframe's content from a separate domain

I am facing a challenge with my widget and multiple websites. The widget is hosted on one domain, but the websites use an iframe to display it. Unfortunately, because of the Same Origin Policy, I cannot style the content of the iframe from the parent websi ...

Creating a personalized webview in Appgyver Steroids: A step-by-step guide

I am planning to design the following layout: The main screen will display a web page There should be a sidebar on the left side The sidebar can be accessed by clicking on a 'hamburger' icon in the app header Currently, my app structure look ...

Limiting the number of promises in AngularJS

My web application allows users to select multiple files using a file input. After the user selects the files, I upload them one by one through my REST API. However, in Internet Explorer, if the user selects more than 10 files at once, some of the requests ...