How can you retrieve a value from a JavaScript closure function?

I'm struggling with getting a value from a closure function in Javascript. In my initial attempt, I placed the return statement inside the inner function, but it was not effective. Then, I tried moving the return statement to the outer function, however, the result still came back as undefined. Is there a reason why returnVal remains without a value when returned from the outer function even though it is assigned a value within the inner function?

console.log('Returned: ' + getColumn('CPC'));

function getColumn(header) {
  var returnVal = undefined;

  ptor.findElements(protractor.By.className('ngHeaderText')).then(function(headers) {

    for (var i = 0; i < headers.length; i++) {
      (function(i){
        headers[i].getText().then(function(headerResult) {
          if (headerResult == header) {
            console.log('i: ' + i);
            returnVal = i;
          }
        });
      })(i);
    }
  });

  return returnVal;
};

I would greatly appreciate any assistance on this matter!

EDIT: moved the return statement

Answer №1

In JavaScript, a "non-local return" where an inner function returns to an outer function is not possible.

The issue at hand is not with closures, but rather with the need to structure your control flow using promises. Unlike languages like C# or Python that pause the current function when making an async request, JavaScript continues executing without waiting for the request to complete. This results in calling code to initiate an async request and returning undefined before the request finishes. The solution is to return a promise immediately (instead of undefined) and handle all control flow within the promise event handler using promise-specific methods. While it may be inconvenient that return and for loops behave differently in JavaScript compared to other languages, adapting to this nuance is necessary until widespread adoption of ES6 generators.

Your getColumn function should return a promise that includes the value of the column instead of doing computations without returning anything:

function getColumn(header){
     return ptro.findElements(...);
   // ^^^^^ 
}

Additionally, inserting async code directly inside a loop is not standard practice. You must decide whether to execute requests sequentially (fetching one header after another) or concurrently (initiating all header requests simultaneously and awaiting all results). Implementation will vary based on manual processing requirements and chosen promise library.

If opting for sequential processing, recursion can replace traditional for loops:

then(function(headers) {

    function loop(i){
        if( i >= headers.length) {
            return null; //not found
        }else{
            return headers[i].getText().then(function(headerResult) {
                if (headerResult == header) {
                    console.log('i: ' + i);
                    return i;
                }else{
                    return loop(i+1);
                }
             });
         }
     }

     return loop(0);
});

Performing parallel requests will slightly differ depending on the promise library used, with most libraries offering functions designed for such scenarios.

Answer №2

Your reasoning is accurate - you have the ability to return a value from an internal function to an external function, and then return that same value from the external function. To illustrate this concept more clearly, here is a simplified version of your code:

console.log('Result: ' + getColumn());

function getColumn() {

  var returnValue = undefined;
  (function(){
      returnValue = 'example';     
  })();  

  return returnValue;
};

When executed, this will display the message in the console:

Result: example

The issue lies in the fact that you are only returning from the function specified in when(), rather than the encompassing function it resides within.

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 with React and Mongoose: State Change Not Being Saved

I am facing an issue with changing the state of my checkbox. Initially, the default option in my Mongoose model is set to false. When a user checks the box and submits for the first time, it successfully updates their profile (changing the value to true). ...

I'm having trouble displaying the content of my list items within the div

In my code, I have a class called "ignicoes" that includes a list as one of its attributes. This list contains other attributes such as dispositivo, latitude, longitude, and more. My goal is to retrieve the contents of this list and display them within my ...

What are the steps to retrieve JSON data and display it using an unordered list in an HTML document?

My JSON data structure looks like this: { "fID": "00202020243123", "name": "John Doe", "List": ["Father", "Brother", "Cousin"] } When I render this JSON element in my model and view it in the HTML, everything works fine. However, when I try t ...

Troubleshooting issues with Vue.js page routing

Currently, I am diving into the world of vue.js and encountering difficulties with setting up routing. My goal is to utilize templates stored in separate HTML files, rather than inline templates. The issue I'm facing is that the routing does not seem ...

Utilizing Javascript to Generate a Comma-Separated List from Multiple Select Elements

I have a set of dynamic single-option select elements that I need to work with. My goal is to generate a list containing the indexes of all selected options, separated by commas. Currently, I am using elements = document.getElementsByClassName("my-class ...

Displaying an array within a method using Vue.js

As a complete newcomer to Vue, I wanted to experiment with methods a bit. Specifically, I attempted to print out an array of strings using the following method: printStringArray(objectWithArray) { i = 0; s = ''; while(i < ob ...

ng-repeat not functioning properly with data defined in XMLHttpRequest

I have a problem with my HTML and AngularJS code. Initially, I defined the list in my controller which worked fine: <li ng-repeat="a in idmasVesselstableList"><a>{{a.table_name}}</a></li> And here is how I set up the controller: ...

Retrieve data from FileReader's onload event asynchronously in Javascript

Although this question has been asked numerous times before, I have reviewed the answers provided and still cannot get my code to work. I am working with Angular 2. I have input tags for file insertion. The file successfully reaches the component, but when ...

Tips for passing a function to express-handlebars within a node.js-express application

I've been attempting to pass a function in express-handlebar, but for some reason it's not working. In my setup, I have app.js serving as the server file and index.handlebars as the handlebar file. In app.js: const express=require('expres ...

Having difficulty applying parseFloat directly following a JSON Stringify operation

There's a specific line of code I'm working with that reads -- let longitude = JSON.stringify(place.lon); After calling alert(longitude), I receive the output "44.54321". However, my intention is to retrieve just the number itself, so I attempt ...

Resetting the Angular provider configuration whenever the service is injected into a different location

Trying to wrap my head around a rather complex issue here. I have a service set up as a provider in order to configure it. Initially, this service has an empty array of APIs which can be dynamically added to by various configuration blocks. When adding API ...

Is the HTML5 type of button functioning properly, while the type of submit is not working as

Looking to validate a form before running a JavaScript function? Check out this code snippet: function updateMap() { //dummy } <form> <div class="group"> <input type="number" id="hour" min="0" max="23" required> <span cl ...

Angular credit card filter with replacement

Looking for an easy method to display information in a credit card input field using angular1, such as: #### - #### - #### - #### ? Substitute the numbers with any symbols and insert "-" between every set of 4 numbers. ...

I am unable to display my JSON data in Next.js using a fetch request

I'm having trouble understanding the code, and it seems like the API is open to anyone since it's just a simple JSON. However, I keep getting an error: Error Message: Reason: `undefined` cannot be serialized as JSON. Please use `null` or omit th ...

What is the best way to set one property to be the same as another in Angular?

In my project, I have defined a class called MyClass which I later utilize in an Angular component. export class MyClass { prop: string; constructor(val){ this.prop = val; } public getLength(str: string): number { return str.length; } ...

Properly handling the use of single and double quotation marks in variable declarations within a JavaScript file

I have a search box where users can enter their search text. For example, they can type book, 'book', or "book". The value entered in the search box is then assigned to a variable in the JavaScript file. var searchTerm = "${searchTerm}"; <br/ ...

Transmit JavaScript code from ASP.NET

Trying to transfer JavaScript code built using String Builder on the server-side (ASP.NET) to the HTML page's JavaScript. Here is my approach: Utilizing a Master Page and an ASPX page structured like this: <asp:Content ID="BodyContent" ContentPla ...

Protractor: What is the best way to retrieve the baseUrl from the command line input?

How can I retrieve the baseUrl that was passed through the command line in Protractor? For example: protractor conf.js --baseUrl=http://myawesomesite.com I attempted to use browser.baseUrl to access the baseUrl set in my conf.js file, but it does not see ...

Trouble with parsing dates in JavaScript using Moment.js

I'm retrieving dates from SQL Server that are passing through ASP.NET, and then iterating through a list of objects in jQuery to display the dates along with other data. However, regardless of the various date/time values coming from the database, the ...

Utilizing Moment.js: Transforming 12-hour format to a Date object

Is there a way to convert a 12-hour string into a 24-hour Date object? day.from = day.from || moment("6:00", ["h:mm"]).format("HH:mm"); Unfortunately, I am encountering the following error: angular.js:11706 Error: [ngModel:datefmt] Expected `6:00` to be ...