JS:在异步函数中获取内部函数参数并执行回调

时间:2016-12-25 11:45:38

标签: javascript

我尝试编写返回异步函数的所有结果的函数,并执行一个回调,该回调推入一个数组并记录每个异步函数的结果。

作为服务员,在完成所有菜肴后带来所有菜肴。 我不明白如何获取应该返回的子参数。任务代码和我的工作解决方案如下:

任务:

var dishOne = function(child) {
    setTimeout(function() {
        child('soup');
    }, 1000);
};

var dishTwo = function(child) {
    setTimeout(function() {
        child('dessert');
    }, 1500);
};
waiter([dishOne, dishTwo], function(results) {
    console.log(results); // console output = ['soup', 'dessert']
});

我的工作解决方案:

function child(arg) {
    this.arr.push(arg)
}

function waiter(funcArray, doneAll) {
    var result = {
        arr: []
    };
    let i = 0;
    const x = child.bind(result)
    funcArray.forEach(function(f) {
      f(x)
      i++;
      if(i == 2) {
        doneAll(result.arr)
      }
    });
}

2 个答案:

答案 0 :(得分:5)

问题在于这部分:

funcArray.forEach(function(f) {
  f(x)
  i++;
  if(i == 2) {
    doneAll(result.arr)
  }
});

这是一个同步函数所以当你检查if(i == 2)时,你基本上检查一下,你已经调用了所有异步函数,但它们还没有返回任何内容,所以你所知道的是,函数已被调用,但result.arr尚未填充。

您必须将doneAll(result.arr)表达式移动到child回调中,然后它将由异步函数调用,因为它会返回结果。

我能想到的最简单的解决方案是将child写为

function child(arg) {
    if (this.arr.push(arg) === this.allCount) this.doneAll(this.arr);
}

并在您的waiter函数增强结果对象

var result = {
    arr: []
    , allCount: funcArray.length
    , doneAll: doneAll
};

这应该有效,但有一个缺点 - 结果的位置不能保持funcArray中函数的位置,结果的位置按异步函数的持续时间排序,只需先解析第一个结果等如果这是一个问题,你必须将index传递给你的child函数,将结果存储在结果数组中的宝贵位置,然后arr.length的检查不起作用,因为JS数组返回长度为最高指数+ 1,因此,如果您的上一个funcArray首先满足,它将填充最后一个索引,result.arr的长度将等于this.allCount,因此为了保持结果的顺序与funcArray相同,您需要将返回结果的数量存储为另一个数字,并在每个新结果中增加该数字,并将该数字与allCount进行比较。

或者像这样减少allCount

function child(idx, arg) {
    this.arr[idx] = arg;
    if (--this.allCount === 0) this.doneAll(this.arr);
}

并修改您的waiter功能

function waiter(funcArray, doneAll) {
    const result = {
        arr: []
        , allCount: funcArray.length
        , doneAll: doneAll
    };

    funcArray.forEach(function(f, i) {
        f(child.bind(result, i));
    });
}

答案 1 :(得分:0)

为什么不Promise

function dishOne() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() { resolve('soup') }, 1000)
    })
}

function dishTwo() {
    return new Promise(function(resolve, reject) {
        setTimeout(function() { resolve('dessert') }, 1500)
    })
}

您的waiter功能:

function waiter(dishes, callback) {
    return Promise.all(dishes).then(callback)
}

你可以像这样使用它

waiter([dishOne(), dishTwo()], function(results) {
    // Invoked when all dishes are done
    console.log(results) // ['soup', dessert']
})

更容易理解。正确?