我需要帮助从头开始编写这个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,但不确定问题是什么。
提前致谢!
答案 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)))
}
由于wait3For1
和wait2For5
没有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
”,但却不那么通用。您应该将wait2For5
和Promise.all
转换为Promise创作者并改为使用Promise.all
。
你的下一个问题可能是如何实施pageview
...我最近做了这个,发现这是一个非常有趣的挑战。我希望如果您选择从头开始探索实现,本回答中分享的一些技术将有所帮助^ _ ^