-1

Objective: I want to set all values of the array to (valueofIndex + 1) and log the new array in the end.

    **EDIT:**

This DOESNT WORK:

var async = require('async');

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

function attemptAtAsyncEach (arr) {

    return async.map(arr, function (member, callback) {
        callback(null, member + 1);
    }, function (err, results) {
        return results;
    });
}

console.log(attemptAtAsyncEach(arr));

THIS WORKS:

var async = require('async');

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

function attemptAtAsyncEach (arr) {

    return async.map(arr, function (member, callback) {
        callback(null, member + 1);
    }, function (err, results) {
        console.log( results);
    });
}

attemptAtAsyncEach(arr);

If I return results instead of console.log in the callback, why does it show undefined?

user7361276
  • 219
  • 2
  • 3
  • 11
  • You want to use `.map`, not `.forEach`. http://caolan.github.io/async/docs.html#map, but anyways, have a look at the [documentation](http://caolan.github.io/async/docs.html#each). It has an example that shows how to perform operations after the array was processed. `elem = 4;` won't change any of the array elements btw. Here is a simpler example: `var foo = 42; var bar = foo; bar = 21;`. `foo` still has the value `42`. – Felix Kling Jan 02 '17 at 23:38
  • @FelixKling, I've edited the code using map, nothing prints in the logs – user7361276 Jan 02 '17 at 23:48
  • Why are you using the async library here? You don't show any asynchronous operation. If your code is all synchronous, then the async library just unnecessarily complicates things. – jfriend00 Jan 02 '17 at 23:52
  • From the documentation: *"The iteratee is passed a callback(err, transformed) which must be called once it has completed with an error (which can be null) and a transformed item."* Therefore `function (member) { return member + 1; }` should be `function (member, cb) { cb(null, member + 1); }`. However, note that you don't need to use `async` at all if you are not performing any asynchronous operations. – Felix Kling Jan 02 '17 at 23:52
  • @FelixKling, I am just trying to get used to async – user7361276 Jan 02 '17 at 23:54
  • @FelixKling, then where do I define cb? – user7361276 Jan 02 '17 at 23:55
  • It is passed to the function by `async.map`, just like `async.forEach` did. – Felix Kling Jan 02 '17 at 23:55
  • @FelixKling, can you edit my code and show me? I am completely lost and would really appreciate it. I am using this as a learning opportunity – user7361276 Jan 02 '17 at 23:57
  • My comment already contains what you need to change, but here it is again: Replace `function (member) { return member + 1; }` with `function (member, cb) { cb(null, member + 1); }`. You can also rename `cb` to `callback` if that's easier for you to understand. But how you name the parameter is irrelevant. – Felix Kling Jan 02 '17 at 23:58
  • @FelixKling, I've got one version working. I have a few questions. If you look in my edited version, the one with RETURN doesn't work, why? Also I didn't DEFINE callback, is the callback function automatically the last one? – user7361276 Jan 03 '17 at 00:07
  • @FelixKling, also, if I am calling callback(null, member + 1) on every one of them, does it call the last function after ALL of them are done? – user7361276 Jan 03 '17 at 00:08
  • You should read [How do I return the response from an asynchronous call?](http://stackoverflow.com/q/14220321/218196) and [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](http://stackoverflow.com/q/23667086/218196) to learn more about asynchronous code in general. That should answer your question about `return`. *" I didn't DEFINE callback, is the callback function automatically the last one?"* No, the callback function is passed to your function by `async.map`, just like `member`. – Felix Kling Jan 03 '17 at 00:09
  • *"does it call the last function after ALL of them are done"* Yes. About the third argument from the documentation: *"A callback which is called when all iteratee functions have finished, or an error occurs."* http://caolan.github.io/async/docs.html#map – Felix Kling Jan 03 '17 at 00:10
  • @FelixKling, I know that the callback is passed to the function, but my third function ISNT called "callback." How does it detect the third function as the callback? – user7361276 Jan 03 '17 at 00:12
  • The third argument as nothing to do with `callback`. `callback` is a function defined by `async.map`. When you call `callback`, `async.map` knows that it can continue to process the next element in the array. Then, after all elements are processed, the third argument you pass is called. – Felix Kling Jan 03 '17 at 00:15
  • Oh alright, that sounds good @FelixKling. Then if all elements are processed and THEN the third function is called, why can I not use "return results"? If the third function already has everything then I don't see a problem. – user7361276 Jan 03 '17 at 00:22
  • Have a look at the other questions I linked to. At the moment the third function is executed, `attemptAtAsyncEach` is already terminated. When you do `console.log(attemptAtAsyncEach(arr))`, then `attemptAtAsyncEach` is executed first. It returns what `async.map` returns, but `async.maps` doesn't return anything. Then `console.log` is executed and passed the value `undefined`. *Then* the array is processed and your second function is executed for each element. *Then* after all elements are processed, the third function is executed. At that moment there is nowhere to return to. – Felix Kling Jan 03 '17 at 00:23
  • @user7361276: You can't return results because it's async. Async means "this function will execute at a later time in the future". Are you familiar with DOM events? Like `onclick` and `onmouseover`? They're async. Same idea here. Async APIs can be implemented using either event handlers or callbacks. Event handlers used to be more popular but these days callbacks have become more popular. – slebetman Jan 03 '17 at 00:28
  • @slebetman: I'd argue that "callback" is simply a generic term for a function that is called some time in the future. An event handler is also a callback in that sense. – Felix Kling Jan 03 '17 at 00:35
  • @FelixKling: I'm trying to differentiate passing the function to a function and assigning the function to a property. – slebetman Jan 03 '17 at 00:36
  • @slebetman: I don't see why differentiating this would be useful. If you just take DOM event handlers as example, you can bind an event handler either via `element.onclick = ...;` or `element.addEventListener('click', ...)`. So saying that an "event handler" is different than a "callback" based on *how* it is passed/assigned is confusing IMO. – Felix Kling Jan 03 '17 at 00:38
  • @FelixKling: Yes, the first is what I'd call event handler style, the second callback style. The former style was much more popular than the later prior to around 2005. It was used by lots of libraries. Then at around 2005 we start seeing passing functions becoming more popular. The point is, the event handler style is more intuitive to some people (notice that we never really had questions about async behavior with `on...` events). So if someone is familiar with events it may be good to remind them that async callbacks behave the same way. – slebetman Jan 03 '17 at 00:42

3 Answers3

1
var async = require('async')

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

async.forEach(Object.keys(arr), function (i, callback){
    // if you mean: value of the index + 1
    arr[i] = parseInt(i) + 1
    // OR if you mean: value at the index + 1
    arr[i] += 1

    callback()
}, function(err) {
    console.log(arr)
}); 

Notes: In order to take the index of the element you are about to edit you pass the keys of the array and not the array. Keys are strings, so you need to parse it.

MaanooAk
  • 2,213
  • 13
  • 27
1

async lib

Example using map.

var async = require('async')

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

async.map(arr, function (i, callback) {
    callback(null, i + 10);
}, function(err, result) {
    console.log(result)
});

If you check the documentation on map you will see that it says that the parameters are:

  • collection
  • iteratee

    function
    A function to apply to each item in coll. The iteratee is passed a callback(err, transformed) which must be called once it has completed with an error (which can be null) and a transformed item. Invoked with (item, callback).

  • callback

It does not work with a simple return because you are dealing with async operations, a return would be sync.

I would also like to include other ways to do the same without async lib:


Async / await

Requires TypeScript or Babel or Node 7+ with --harmony flag.

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

(async function () {
  var x = await Promise.all(arr.map(i => new Promise(r => r(i + 10))));
  console.log(x);
}());

Promise

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

Promise.all(arr.map(i => new Promise(r => r(i + 10))))
  .then(console.log);
BrunoLM
  • 88,362
  • 76
  • 272
  • 427
0

First of all, unless you are doing asynchronous operations inside your forEach/map a synchronous forEach/map will be quicker. Your entire code function essentially translates to console.log(arr.map(member => member+1));

Anyway, inside an async.map(...), you must call the provided callback function to indicate the end of your 'asynchronous' process.

function attemptAtAsyncEach (arr) {
    return async.map(arr, function (member, callback) {
        callback(null, member+1);
    }, function (err, result) {
        console.log(result);
    });
}
djones
  • 1,748
  • 1
  • 13
  • 12
  • Why can I not use return instead of console.log(result)? – user7361276 Jan 03 '17 at 00:04
  • @user7361276 Because the whole point of an asynchronous operation is that it returns straight away but carries on processing in the background. Put simply, the results of the map operation cannot be assumed to be available when your function (attemptAtAsyncEach) returns. – djones Jan 03 '17 at 00:16