Carven Carven - 3 months ago 15
TypeScript Question

How to scope a callback function to be called from within a block?

I'm using a third-party API which requires a callback function called

callback_data(json)
when the response comes back.

However, it seems to be calling
callback_data(json)
at the global scope. I would like to scope the
callback_data(json)
function within a block so that I can control the flow through promise.

Here's my attempt to do this:

return new Promise(resolve => {
(function(callback_data) {
api.request({"q": term}); //The third-party API call
})(function(json) {
resolve({...json.data, q: term})
});
}
);


So, the line
api.request({"q": term});
will call
callback_data(json)
function when it receives the response from the server. But it calls the callback function at the global scope. I want it to call from within the block the
api.request()
was initiated.

What I did was I thought I could put everything into a self invoking function and pass in the
callback_data(json)
function as a parameter into the self invoking function. I thought this would scope everything within that self invoking function block. Unfortunately, this didn't work.

How can I do scope a callback function, which supposed to be at the global scope, to be called from within a block?

I'm using Typescript in my code.

Answer

If the API is really coded such that it issues:

callback_data(json);

...from within a scope you can't add functions to, there's nothing you can do. The API is badly designed (unless it's JSONP, in which case that's the only way it can work, but it should let you specify the name of the function) and callback_data must be global.

That doesn't mean that it has to be long-lived. You can declare it globally:

var callback_data = null; // At global scope

...and then in your code, assign a value to it and clear that value when done:

return new Promise(resolve => {
    callback_data = function() { // Assign
        callback_data = null;    // Clear on callback
        resolve({...json.data,
            q: term
        });
    };
    api.request({"q": term});
});

If it's JSONP and it lets you specify the callback name in the request, that would be better as you can create a different callback name for each request:

// Using `window` as JSONP is by definition in a browser
window.lastCallbackId = 0;
return new Promise(resolve => {
    ++lastCallbackId;
    var name = "myCallback" + lastCallbackId;
    window[name] = function() { // Assign, will be "myCallback1", "myCallback2", ...
        window[name] = null;    // Clear on callback
        resolve({...json.data,
            q: term
        });
    };
    api.request({
        "q": term,
        callbackName: name  // Note passing the name to it
    });
});