sunny
sunny

Reputation: 125

Mixing setTimeout with the callback functions - problem with returning values before the setTimeout ends

according to what I asked yesterday: Taking a value from Promise and returning it instead of console.log

I still have a problem, because when I try to turn on the list of functions, the return results happen before it even gets into the functions. I can't use async/await, so that's why I struggle with this exercise.

Is there any way to:

  1. If I console.log(fun1(1000,callback)) it doesn't return anything (undefined), but I would like it to return the value res, but not console.logging it, but just to make the callback return it.
  2. The idea is to put into results those results, that the pred accepts, so e.g. greater than 5.
  3. I know that the problem is with setTimeout probably, but as mentioned in the post I posted yesterday - I can't use async/await to fix that problem.

My code:

function fun1(value,cb) {
    if ((value * 100) > 400)  {
        setTimeout(() => cb(null, value*100), 1000)
    }
    else {
       setTimeout(() => cb(new Error("error")), 1000)
    }
}
function fun2(value,cb) {
    if ((value * 20) > 50)  {
        setTimeout(() => cb(null, value*20), 2000)
    }
    else {
        setTimeout(() => cb(new Error("error")), 2000)
    }
}

function fun3(value,cb) {
    if ((value -30 ) > 0)  {
        setTimeout(() => cb(null, value-30), 3000)
    }
    else {
        setTimeout(() => cb(new Error("error")), 3000)
    }
}
function callback(err, res) {
    if (err) {
        console.log(err)
    }
    else {
        console.log(res)
        return res
    }


}
console.log(fun1(1000,callback))

const together = (funcs, pred) => (n) => {
    let results = []
    funcs.reduce((prev,curr) => {
        if (curr(n,callback) > pred) {
            results.push(curr(n,callback))
        }

    }, 0)
    return results
};

console.log(together([fun1,fun2,fun3], 5)(10))

Upvotes: 0

Views: 60

Answers (2)

This works when use the callback function

Your Example Include the callback after timeout:

 function fun1(value, calculate, callback) {
  if (value * 100 > 400) {
     setTimeout(() => {
      let result = calculate(null, value * 100);
      callback(result)
    }, 1000);
  } else {
     setTimeout(() => cb(new Error("error")), 1000);
  }
}

function calculate(err, res) {
  if (err) {
    console.log(err);
  } else {
    console.log(res);
    return res;
  }
}

fun1(1000, calculate, function(result) {
  console.log(`this is the result in the callback after timeout ${result}`)
});

Upvotes: 0

Nur
Nur

Reputation: 2473

In past people afraid to write async code because of callback, As so I, So I will use promise,

So that you need to return a Promise object from your function like:

function fun1(value) {
    return new Promise((res, rej) => {
        if ((value * 100) > 400)
            setTimeout(() => res(value * 100), 1000)
        else
            setTimeout(() => rej(new Error("error")), 1000)
    });
}

Instead of warping a Promise object, I took deferent approach, I wrote a utility function (callFuture) that call cl and return a Promise object for us.

function callFuture(fn, value, cl) {
    return new Promise((res, rej) => {
        fn(value, (...v) => {
            let result = cl(...v);
            if (result instanceof Error)
                rej(result)
            else
                res(result)
        })
    });
}

function fun1(value, cb) {
    if ((value * 100) > 400)
        setTimeout(() => cb(null, value * 100), 1000)
    else
        setTimeout(() => cb(new Error("error")), 1000)
}
function fun2(value, cb) {
    if ((value * 20) > 50)
        setTimeout(() => cb(null, value * 20), 2000)
    else
        setTimeout(() => cb(new Error("error")), 2000)
}

function fun3(value, cb) {
    if ((value - 30) > 0)
        setTimeout(() => cb(null, value - 30), 3000)
    else
        setTimeout(() => cb(new Error("error")), 3000)
}

function callback(err, res) {
    return err ? err : res
}

callFuture(fun1, 100, callback)
    .then(console.log)
    .catch(console.log)

async function together(funcs, pred, n) {
    let results = [];
    for (const fn of funcs) {
        try {
            let v = await callFuture(fn, n, callback);
            if (v > pred)
                results.push(v);
        } catch (error) {
            console.log(`error`)
        }
    }
    return results;
}

together([fun1, fun2, fun3], 5, 10).then(console.log)

You can think await callFuture(fn, n, callback) is like synchronous (this is not true), There is no need to do anything to handle async stuff, it will return result or throw error (much like a sync function), Any you can handle error with try/catch as like you do in a sync function...

Upvotes: 1

Related Questions