-1

I know this question have been asked many times, but I can't make it work.

Here is my situation. I had a string called data, and I want to unshorten all the link inside that string.

Code:

var Bypasser = require('node-bypasser');
var URI = require('urijs');

var data = 'multiple urls : http://example.com/foo http://example.com/bar';

var result = URI.withinString(data, function(url) {
    var unshortenedUrl = null;
   
    var w = new Bypasser(url);
    w.decrypt(function(err, res) {
      // How can I return res ?
      unshortenedUrl = res;
    });
    // I know the w.descrypt function is a asynchronous function
    // so unshortenedUrl = null
    return unshortenedUrl;
});

Let's me walk you through the code.

URI.withinString will match all the URLs in data, manipulate it and return the result.

You can view an example from URI.js docs

What I want to with these URLs is to unshorten all of them using node-passer.

This is from node-bypasser document:

var Bypasser = require('node-bypasser');

var w = new Bypasser('http://example.com/shortlink');
w.decrypt(function(err, result) {
    console.log('Decrypted: ' + result);
});

This is the result that I want multiple urls : http://example.com/foo_processed http://example.com/bar_processed

I created a notebook at tonicdev.com


Solution

var getUrlRegEx = new RegExp(
        "(^|[ \t\r\n])((ftp|http|https|gopher|mailto|news|nntp|telnet|wais|file|prospero|aim|webcal):(([A-Za-z0-9$_.+!*(),;/?:@&~=-])|%[A-Fa-f0-9]{2}){2,}(#([a-zA-Z0-9][a-zA-Z0-9$_.+!*(),;/?:@&~=%-]*))?([A-Za-z0-9$_+!*();/?:~-]))"
        , "g"
      );

      var urls = data.match(getUrlRegEx);

      async.forEachLimit(urls, 5, function (url, callback) {
        let w = new Bypasser(url);
        w.decrypt(function (err, res) {
          if (err == null && res != undefined) {
            data = data.replace(url, res);
            callback();
          }
        });
      }, function(err) {
        res.send(data);
      });
thangngoc89
  • 1,320
  • 9
  • 13
  • Yes, many times. But unless you don't show us what you've attempted to make it work, we only can point you to the old answers. – Bergi Nov 12 '15 at 08:48
  • @Bergi I edited my question. Is it enough information now? – thangngoc89 Nov 12 '15 at 09:00
  • 1
    OK, that's a very different question now. Still, the problem remains: [You **cannot** `return` from the future](http://stackoverflow.com/q/14220321/1048572). Now, the bummer is: [`URI.withinString`](http://medialize.github.io/URI.js/docs.html#static-withinString) simply doesn't work with asynchronous callbacks. You will have to manually parse out the URIs, start decryption of them, await those all to finish, and then throw them back together. – Bergi Nov 12 '15 at 09:19
  • Thank you very much. I updated my solution above – thangngoc89 Nov 12 '15 at 11:03

1 Answers1

0

You don't really understand what callback is. The callback serves to allow asynchronous code to run without Javascript waiting for it. If you were less lazy and added some debug in your code:

console.log("Started parsing");
var result = URI.withinString(data, function(url) {
    console.log("URL parsed (or whatever)");
    var unshortenedUrl = null;

    var w = new Bypasser(url);
    w.decrypt(function(err, res) {
      // How can I return res ?
      unshortenedUrl = res;
    });
    // I know the w.descrypt function is a asynchronous function
    // so unshortenedUrl = null
    return unshortenedUrl;
});
console.log("Call to library over");

You would (most likely) see messages in this order:

Started parsing
Call to library over
URL parsed (or whatever)

The answer: Callback is not guaranteed to run before any code you execute after assigning it. You can't put data in your result variable because the data might not be fetched yet.