Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace text occurrences with data returned by Promises

I've got a blog-post like this:

var post ="## Cool Post [embed]https://soundcloud.com/wonnemusik/teaser-schotone-dear-thomson-button-remix[/embed]"
+ "Here comes another one  [embed]https://soundcloud.com/straightech-bonn-podcast/straightech-and-friends-7-oscar-ozz[/embed]";

Now for every occurrence of [embed]soundcloud-url[/embed] I need to call their API endpoint http://api.soundcloud.com/resolve.json?url=soundcloud-url&client_id=my-id, parse the returned JSON and replace the [embed] with my own markup.

How can I use this using Promises?

var post ="## Cool Post [embed]https://soundcloud.com/wonnemusik/teaser-schotone-dear-thomson-button-remix[/embed]"
+ "Here comes another one  [embed]https://soundcloud.com/straightech-bonn-podcast/straightech-and-friends-7-oscar-ozz[/embed]"
var re = /\[embed\](.*)\[\/embed\]/gm;
var m;

do {
    m = re.exec(post);
    if (m) {
      var apiCallUrl = "http://api.soundcloud.com/resolve.json?url=" + m[1] '&client_id=...'
      request(apiCallUrl).then(function(body) {
        var trackinfo = JSON.parse(body[0].body)
        return trackinfo.title
     }
    }
} while (m);

// have all promises fulfilled and old embed in post-var replaced
like image 741
Hedge Avatar asked Mar 11 '26 16:03

Hedge


2 Answers

I haven't used bluebird specifically, but there's usually an all method that wraps an array of promises (or takes promises as arguments). A glance at the API documentation for bluebird shows they do have an all method that you can use. You'll want to create an array of promises inside your do/while loop, then call all at the end:

var resultPromises = [];
var m;
do {
    m = re.exec(post);
    if (m) {
        var apiCallUrl = "http://api.soundcloud.com/resolve.json?url=" + m[1] '&client_id=...'
        resultPromises.push(request(apiCallUrl));
    }
} while (m);

// have all promises fulfilled and old embed in post-var replaced
Promise.all(resultPromises).then(function (results) {
    // do stuff.
});

Now, if you want to replace the original text with the results of the promise, you'll need to store the matches in an array as well. The results argument to the then will be an array of the responses, in the order in which they were originally added to the array. So, you can do something like:

var resultPromises = [];
var matches = [];
var m;
do {
    m = re.exec(post);
    if (m) {
        var apiCallUrl = "http://api.soundcloud.com/resolve.json?url=" + m[1] '&client_id=...'
        resultPromises.push(request(apiCallUrl));
        matches.push(m);
    }
} while (m);

var i = 0;
// have all promises fulfilled and old embed in post-var replaced
Promise.all(resultPromises).then(function (results) {
    // haven't tested this. Will leave as practice for the OP :)
    post = post.replace(matches[i], results[i].body[0].body.title);
    i += 1;
});
like image 118
Heretic Monkey Avatar answered Mar 14 '26 06:03

Heretic Monkey


You can use this replace function that deals with asynchronous callbacks:

var post = "## Cool Post [embed]https://soundcloud.com/wonnemusik/teaser-schotone-dear-thomson-button-remix[/embed]"
         + "Here comes another one  [embed]https://soundcloud.com/straightech-bonn-podcast/straightech-and-friends-7-oscar-ozz[/embed]"
var re = /\[embed\](.*)\[\/embed\]/gm;

return replaceAsync(post, re, function(m, url) {
     var apiCallUrl = "http://api.soundcloud.com/resolve.json?url=" + url + '&client_id=…'
     return request(apiCallUrl).then(function(res) {
         return JSON.parse(res[0].body).title;
     });
});
like image 20
Bergi Avatar answered Mar 14 '26 06:03

Bergi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!