Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async load inside replace function

I am working with replacements in Javascript. I did something like this:

var replacedText = originalText.replace(regex, function(value, i) { 
    return value + 'some_additional_data';
});

return replacedText;

But now I need to load a HTML template inside the replace method. The load method is called in this way:

res.render(location, json, function(error, html) {
    //i have the html loaded with my json data
});

I need to load it inside my replace method, but I am unable to do it:

var replacedText = originalText.replace(media, function(value, i) {
    var json = buildJSON(value);
    res.render(location, json, function(error, html) {
        //how could i return the "html" object for the replace function?
    });
});

I have tried something like this, but it didn't work:

var replacedText = originalText.replace(media, function(value, i) {
    var json = buildJSON(value);
    return res.render(location, json, function(error, html) {
        return html;
    });
});

Any help would be appreciated Thank you very much in advance

like image 393
Genzotto Avatar asked Dec 12 '14 09:12

Genzotto


2 Answers

When you have a callback that demands a synchronous return value, you cannot use an async operation inside that callback to get that value. The async operation (by definition) will finish sometime later AFTER the callback has returned so the results of the async operation are just not available to return from the callback and there is no way to make JS wait for an async operation.

I don't follow exactly what your code is trying to do, but judging from your words, it sounds like you want to load an HTML template and use that in the replace operation. There are some different ways to approach that problem.

For example, you could do this with two passes.

  1. The first pass doesn't actually change your string, instead it just builds a list of templates that are needed.

  2. Then, you load all the templates in that list.

  3. Then, when all the templates you will need are loaded, you can then do your replace, using the already loaded templates to do the synchronous replacement you planned.

like image 75
jfriend00 Avatar answered Oct 15 '22 18:10

jfriend00


No, replace does only support synchronous callbacks. However, here is a generic function that accepts a callback which yields promises, and returns a promise for the string with all replacements made:

function replaceAsync(str, re, callback) {
    // http://es5.github.io/#x15.5.4.11
    str = String(str);
    var parts = [],
        i = 0;
    if (Object.prototype.toString.call(re) == "[object RegExp]") {
        if (re.global)
            re.lastIndex = i;
        var m;
        while (m = re.exec(str)) {
            var args = m.concat([m.index, m.input]);
            parts.push(str.slice(i, m.index), callback.apply(null, args));
            i = re.lastIndex;
            if (!re.global)
                break; // for non-global regexes only take the first match
            if (m[0].length == 0)
                re.lastIndex++;
        }
    } else {
        re = String(re);
        i = str.indexOf(re);
        parts.push(str.slice(0, i), callback.apply(null, [re, i, str]));
        i += re.length;
    }
    parts.push(str.slice(i));
    return Promise.all(parts).then(function(strings) {
        return strings.join("");
    });
}
like image 23
Bergi Avatar answered Oct 15 '22 18:10

Bergi