How do I return the response from an asynchronous

2019-08-20 01:53发布

I have a function foo which makes an Ajax request. How can I return the response from foo?

I tried returning the value from the success callback as well as assigning the response to a local variable inside the function and returning that one, but none of those ways actually return the response.

function foo() {
    var result;

    $.ajax({
        url: '...',
        success: function(response) {
            result = response;
            // return response; // <- I tried that one as well
        }
    });

    return result;
}

var result = foo(); // It always ends up being `undefined`.

30条回答
何必那么认真
2楼-- · 2019-08-20 02:32

Angular1

For people who are using AngularJS, can handle this situation using Promises.

Here it says,

Promises can be used to unnest asynchronous functions and allows one to chain multiple functions together.

You can find a nice explanation here also.

Example found in docs mentioned below.

  promiseB = promiseA.then(
    function onSuccess(result) {
      return result + 1;
    }
    ,function onError(err) {
      //Handle error
    }
  );

 // promiseB will be resolved immediately after promiseA is resolved 
 // and its value will be the result of promiseA incremented by 1.

Angular2 and Later

In Angular2 with look at the following example, but its recommended to use Observables with Angular2.

 search(term: string) {
     return this.http
  .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`)
  .map((response) => response.json())
  .toPromise();

}

You can consume that in this way,

search() {
    this.searchService.search(this.searchField.value)
      .then((result) => {
    this.result = result.artists.items;
  })
  .catch((error) => console.error(error));
}

See the original post here. But Typescript does not support native es6 Promises, if you want to use it, you might need plugin for that.

Additionally here is the promises spec define here.

查看更多
男人必须洒脱
3楼-- · 2019-08-20 02:32

Js is a single threaded.

Browser can be divided into three parts:

1)Event Loop

2)Web API

3)Event Queue

Event Loop runs for forever i.e kind of infinite loop.Event Queue is where all your function are pushed on some event(example:click) this is one by one carried out of queue and put into Event loop which execute this function and prepares it self for next one after first one is executed.This means Execution of one function doesn't starts till the function before it in queue is executed in event loop.

Now let us think we pushed two functions in a queue one is for getting a data from server and another utilises that data.We pushed the serverRequest() function in queue first then utiliseData() function. serverRequest function goes in event loop and makes a call to server as we never know how much time it will take to get data from server so this process is expected to take time and so we busy our event loop thus hanging our page, that's where Web API come into role it take this function from event loop and deals with server making event loop free so that we can execute next function from queue.The next function in queue is utiliseData() which goes in loop but because of no data available it goes waste and execution of next function continues till end of the queue.(This is called Async calling i.e we can do something else till we get data)

Let suppose our serverRequest() function had a return statement in a code, when we get back data from server Web API will push it in queue at the end of queue. As it get pushed at end in queue we cannot utilise its data as there is no function left in our queue to utilise this data.Thus it is not possible to return something from Async Call.

Thus Solution to this is callback or promise.

A Image from one of the answers here, Correctly explains callback use... We give our function(function utilising data returned from server) to function calling server.

CallBack

 function doAjax(callbackFunc, method, url) {
  var xmlHttpReq = new XMLHttpRequest();
  xmlHttpReq.open(method, url);
  xmlHttpReq.onreadystatechange = function() {

      if (xmlHttpReq.readyState == 4 && xmlHttpReq.status == 200) {
        callbackFunc(xmlHttpReq.responseText);
      }


  }
  xmlHttpReq.send(null);

}

In my Code it is called as

function loadMyJson(categoryValue){
  if(categoryValue==="veg")
  doAjax(print,"GET","http://localhost:3004/vegetables");
  else if(categoryValue==="fruits")
  doAjax(print,"GET","http://localhost:3004/fruits");
  else 
  console.log("Data not found");
}

Read here for new methods in ECMA(2016/17) for making async call(@Felix Kling Answer on Top) https://stackoverflow.com/a/14220323/7579856

查看更多
等我变得足够好
4楼-- · 2019-08-20 02:33

You are using Ajax incorrectly. The idea is not to have it return anything, but instead hand off the data to something called a callback function, which handles the data.

That is:

function handleData( responseData ) {

    // Do what you want with the data
    console.log(responseData);
}

$.ajax({
    url: "hi.php",
    ...
    success: function ( data, status, XHR ) {
        handleData(data);
    }
});

Returning anything in the submit handler will not do anything. You must instead either hand off the data, or do what you want with it directly inside the success function.

查看更多
劳资没心,怎么记你
5楼-- · 2019-08-20 02:33

Short answer is, you have to implement a callback like this:

function callback(response) {
    // Here you can do what ever you want with the response object.
    console.log(response);
}

$.ajax({
    url: "...",
    success: callback
});
查看更多
贼婆χ
6楼-- · 2019-08-20 02:33

Use a callback() function inside the foo() success. Try in this way. It is simple and easy to understand.  

var lat = "";
var lon = "";
function callback(data) {
    lat = data.lat;
    lon = data.lon;
}
function getLoc() {
    var url = "http://ip-api.com/json"
    $.getJSON(url, function(data) {
        callback(data);
    });
}

getLoc();
查看更多
倾城 Initia
7楼-- · 2019-08-20 02:33

Using Promise

The most perfect answer to this question is using Promise.

function ajax(method, url, params) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.onload = function() {
      resolve(this.responseText);
    };
    xhr.onerror = reject;
    xhr.open(method, url);
    xhr.send(params);
  });
}

Usage

ajax("GET", "/test", "acrive=1").then(function(result) {
    // Code depending on result
})
.catch(function() {
    // An error occurred
});

But wait...!

There is a problem with using promises!

Why should we use our own custom Promise?

I was using this solution for a while until I figured out there is an error in old browsers:

Uncaught ReferenceError: Promise is not defined

So i decided to implement my own Promise class for ES3 to below js compilers if its not defined. Just add this code before your main code and then safely use Promise!

if(typeof Promise === "undefined"){
    function _classCallCheck(instance, Constructor) {
        if (!(instance instanceof Constructor)) { 
            throw new TypeError("Cannot call a class as a function"); 
        }
    }
    var Promise = function () {
        function Promise(main) {
            var _this = this;
            _classCallCheck(this, Promise);
            this.value = undefined;
            this.callbacks = [];
            var resolve = function resolve(resolveValue) {
                _this.value = resolveValue;
                _this.triggerCallbacks();
            };
            var reject = function reject(rejectValue) {
                _this.value = rejectValue;
                _this.triggerCallbacks();
            };
            main(resolve, reject);
        }
        Promise.prototype.then = function then(cb) {
            var _this2 = this;
            var next = new Promise(function (resolve) {
                _this2.callbacks.push(function (x) {
                    return resolve(cb(x));
                });
            });
            return next;
        };
        Promise.prototype.catch = function catch_(cb) {
            var _this2 = this;
            var next = new Promise(function (reject) {
                _this2.callbacks.push(function (x) {
                    return reject(cb(x));
                });
            });
            return next;
        };
        Promise.prototype.triggerCallbacks = function triggerCallbacks() {
            var _this3 = this;
            this.callbacks.forEach(function (cb) {
                cb(_this3.value);
            });
        };
        return Promise;
    }();
}
查看更多
登录 后发表回答