如何从头开始在Javascript中编写异步Map函数?

时间:2016-07-15 01:50:20

标签: javascript node.js dictionary asynchronous functional-programming

我需要帮助从头开始编写这个asyncMap函数。我想我几乎得到了它,但我不确定为什么我一直得到错误的答案。这是我到目前为止的代码:

function wait3For1(callback){
    setTimeout(function(){
        callback('one')
    }, 300)
}

function wait2For5(callback){
    setTimeout(function(){
        callback('five')
    }, 200)
}


function asyncMap(tasks, callback){
    return callback(
    tasks.map((item) => 
        item((element) => element)))
}

asyncMap([wait3For1, wait2For5], function(arr){
    console.log(arr) //expect ['one', 'five']
});

我一直在[undefined, undefined] 我很确定这是因为我没有正确地执行回调wait2For5和wait3For1,但不确定问题是什么。

提前致谢!

3 个答案:

答案 0 :(得分:1)

问题是你不是在等待结果回来,收集它们,然后通过回调发回它们。看看这段代码是否有帮助。 (它在您的程序测试时有效。)

function asyncMap(tasks, callback) {
    // array to collect the results
    let results = [];

    // count of how many results we're waiting for
    let remaining = tasks.length;

    tasks.forEach((task, i) => {
        task((result) => {
            // Store the result in the right position.
            results[i] = result;

            // See how many results we're still waiting for.
            remaining -= 1;

            // If we're done, invoke the callback.
            if (remaining === 0) {
                callback(results);
            }
        });
    });
}

答案 1 :(得分:0)

你基本上是在创造穷人的承诺,但没有任何错误处理能力。

尝试

   function waitFor(val, dur){
       return new Promise(function(resolve, reject) {       
        setTimeout(function() {
          resolve(val)
        }, dur);
      });    
    }

    
    Promise.all([waitFor('one',600), waitFor('five', 100)]).then( function(arr) {
      console.log(arr) //expect ['one', 'five']
    }).catch(function(err){
      console.log('ooops error:' , err)
    });

答案 2 :(得分:0)

在您的代码中,您使用的是同步Array.prototype.map

function asyncMap(tasks, callback){
    return callback(
    tasks.map((item) => 
        item((element) => element)))
}

由于wait3For1wait2For5没有return,因此它们将隐式返回undefined.map将在map(items)调用的结果中使用。显然,我们希望在将映射值分配给最终结果之前等待调用回调。

另一个问题是数组上的映射使用了函数 - asyncReduce没有用于映射项目的函数就没有意义。因此,我们也将在下面的解决方案中解决这个问题。

如果您从asyncMap开始,然后将function wait3For1(callback){ setTimeout(function(){ callback('one') }, 300) } function wait2For5(callback){ setTimeout(function(){ callback('five') }, 200) } function asyncReduce(xs, f, initial, callback) { if (xs.length === 0) callback(null, initial) else f(initial, xs[0], function(x) { asyncReduce(xs.slice(1), f, x, callback) }) } function asyncMap(xs, f, callback) { asyncReduce(xs, function(acc, x, k) { f(x, function(y) { k(acc.concat([y])) }) }, [], callback) } asyncMap([wait3For1, wait2For5], function(f,callback) { f(callback) }, function(err, arr) { console.log(arr) //=> ['one', 'five'] })实现为异步reduce,则会有所帮助。请注意,下面的代码将处理系列中的项目。如果您希望并行处理项目,则需要稍微不同的方法。请在评论中告诉我,我很乐意写下另一个变体。

// ES6
const wait3For1 = callback=>
  setTimeout(callback, 300, 'one')

const wait2For5 = callback=>
  setTimeout(callback, 200, 'five')

const asyncReduce = ([x,...xs], f, initial, callback) =>
  x === undefined
    ? callback(null, initial)
    : f(initial, x, y=> asyncReduce(xs, f, y, callback))

const asyncMap = (xs, f, callback)=>
  asyncReduce(xs, (acc, x, k)=>
    f(x, y=> k([...acc, y]))
  , [], callback)

asyncMap(
  [wait3For1, wait2For5],
  (f, callback)=> f(callback),
  (err, arr)=> console.log(arr) // ['one', 'five']
)

继续并运行代码段以查看其是否有效

我看到你使用了一些箭头功能,所以你可能有一个新版本的节点。这是完全相同的事情,但使用ES6而不是

Promise.all

从头开始制作高阶函数是一项非常有价值的练习,但正如另一个答案所指出的那样,你只是实现了一个“穷人的wait3For1”,但却不那么通用。您应该将wait2For5Promise.all转换为Promise创作者并改为使用Promise.all

你的下一个问题可能是如何实施pageview ...我最近做了这个,发现这是一个非常有趣的挑战。我希望如果您选择从头开始探索实现,本回答中分享的一些技术将有所帮助^ _ ^