1

私はこのasyncMap関数を最初から書くのに助けが必要です。私はほとんどそれを持っていると思うが、なぜ私は間違った答えを得続けているのか分からない。ここで私が持っているコードは、これまでのところです:Javascriptでゼロから非同期マップ関数を作成するにはどうすればよいですか?

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'] 
}); 

私は問題が何であるかわからない私が正しくコールバックwait2For5とwait3For1をやっていないよので、それはだかなり確信しているが、[undefined, undefined] を得続けます。

ありがとうございます!

+0

これは、コールバックを使うよりもはるかに優れたエラーキャッチを持つ約束のユースケースです – charlietfl

+0

asyncMapは並行して、または順番に物事を行う?言い換えれば、すべての非同期操作が同時に飛行することができるか、またはそれらを次々と実行することを期待していますか? – jfriend00

答えて

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); 
      } 
     }); 
    }); 
} 
+0

関数は、マッピング関数を使用しない場合は、 'asyncMap'以外の関数を呼び出す必要があります。 – naomik

+1

@naomik合意。 – smarx

0

あなたは基本的に貧しい男の約束を作成しますが、エラー処理能力なしています。 wait3For1wait2For5は一切returnを持っていないので、あなたが同期Array.prototype.map

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

を使用している

があなたのコードで

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) 
 
    });

1

を試してみて、彼らは暗黙のうちにundefinedたが返されます。の結果に使用されます呼び出し。明らかに、マップされた値を最終結果に割り当てる前に、コールバックが呼び出されるのを待つ必要があります。

他の問題は、アレイ全体マッピングが本当にと項目をマッピングする機能なしには意味がない機能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'] 
 
})

先に行くと、あなたはおそらくノードの多少の最近のバージョンを使用しているので、それは私があなたには、いくつかの矢印の機能を使用して参照


を働く見にコードスニペットを実行します。ここではまったく同じことだが、代わりに最初から高階関数を工芸

// 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」だが、汎用性はあまりない。 wait3For1wait2For5をPromiseクリエイターに変換し、代わりにPromise.allを使用してください。

あなたの次の質問は、実現する方法かもしれませんPromise.all ...私はこれを最近行っており、かなり楽しいチャレンジであることがわかりました。この答えで共有されているいくつかのテクニックが、最初から実装を探検するのに役立つことを願っています^^^

関連する問題