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

mai*_*_73 8 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']
});
Run Code Online (Sandbox Code Playgroud)

我的工作解决方案:

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)
      }
    });
}
Run Code Online (Sandbox Code Playgroud)

Vac*_*tny 5

问题是这部分:

funcArray.forEach(function(f) {
  f(x)
  i++;
  if(i == 2) {
    doneAll(result.arr)
  }
});
Run Code Online (Sandbox Code Playgroud)

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

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

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

function child(arg) {
    if (this.arr.push(arg) === this.allCount) this.doneAll(this.arr);
}
Run Code Online (Sandbox Code Playgroud)

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

var result = {
    arr: []
    , allCount: funcArray.length
    , doneAll: doneAll
};
Run Code Online (Sandbox Code Playgroud)

这应该有效,但有一个缺点 - 结果的位置不能保持函数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);
}
Run Code Online (Sandbox Code Playgroud)

并修改你的waiter功能

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

    funcArray.forEach(function(f, i) {
        f(child.bind(result, i));
    });
}
Run Code Online (Sandbox Code Playgroud)