函数之间的promise.all()使用错误?

时间:2019-03-29 16:02:57

标签: javascript asynchronous es6-promise

我制作了这个虚拟代码,以更好地理解promise的工作方式,模仿了我必须“承诺化”的更复杂的软件。 在所附的代码中,我希望事件触发并按以下顺序记录:

  • “之前”字符串
  • “ ...已检测到”列表
  • “完成...”的列表
  • “之后”字符串

但是,如您所见,如果在运行它,则在步骤2和3之间将打印“ after”字符串。 显然,我在处理异步逻辑时一定做错了。 感谢您的帮助!

const obj = {
  "rows": [{
    "type": "A",
    "value": 0
  }, {
    "type": "B",
    "value": 0
  }, {
    "type": "C",
    "value": 0
  }]
}
let promises = [];

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const alter_value = async(row, to_add, time) => {
  await delay(time);
  row.value = row.value + to_add;
  console.log("done with " + row.type);
  return true;
}

const two = async() => {
  obj.rows.forEach(async(row) => {
    switch (row.type) {
      case "A":
        console.log("A detected");
        promises.push(alter_value(row, 1, 1000))
        promises.push(alter_value(row, 2, 1800))
        break;
      case "B":
        console.log("B detected");
        promises.push(alter_value(row, 5, 1400))
        break;
      case "C":
        console.log("C detected");
        promises.push(alter_value(row, 200, 2400))
        break;
    }
  });

  return promises;
}

const one = async() => {
  console.log("before");
  Promise.all(two()).then(console.log("after"));
}

one();

2 个答案:

答案 0 :(得分:1)

我看到您的代码至少有两个问题,解释了您得到的结果:

  1. 您的two函数不应为asyncasync函数返回隐式Promise。在这里,您只想返回一个已经构造好的Promise数组,因此您需要一个普通函数。
  2. .then(console.log("after"))将立即执行console.logthen()期望某个函数稍后执行,因此您必须将其更改为.then(() => console.log("after"))

它变成:

const obj = {
  "rows": [{
    "type": "A",
    "value": 0
  }, {
    "type": "B",
    "value": 0
  }, {
    "type": "C",
    "value": 0
  }]
};

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const alter_value = async (row, to_add, time) => {
  await delay(time);
  row.value = row.value + to_add;
  console.log("done with " + row.type);
  return true;
};

const two = () => {
  const promises = [];
  
  obj.rows.forEach(async(row) => {
    switch (row.type) {
      case "A":
        console.log("A detected");
        promises.push(alter_value(row, 1, 1000));
        promises.push(alter_value(row, 2, 1800));
        break;
      case "B":
        console.log("B detected");
        promises.push(alter_value(row, 5, 1400));
        break;
      case "C":
        console.log("C detected");
        promises.push(alter_value(row, 200, 2400));
        break;
    }
  });

  return promises;
};

const one = async () => {
  console.log('before');
  Promise.all(two()).then(() => console.log('after'));
};

one();

请注意,作为.then()的替代方案,您也可以在await上简单地使用Promise.all,以使代码更加一致:

await Promise.all(two());
console.log('after');

答案 1 :(得分:0)

OP似乎要求同步行为。

演示大纲

  • 函数modVal(i, value, time)参数是从异步函数syncro()参数派生的:const sync对象数组。每个对象都包含obj.rows的索引,该索引obj.rows[i].value的值以及modVal()的Promise中的超时时间。

  • 参数和参数: const sync = [{r: 0, v: 1, t: 1000}, ...];
    seq.r:obj.rows[ 数字 ]
    seq.v: obj.rows[seq.r].value += 编号
    seq.t: ...resolve(obj.rows[i].value += value), 数字);

  • sync数组通过for...of循环进行迭代。在每次迭代中,await modVal()被同步调用。

let obj = {
  "rows": [{
    "type": "A",
    "value": 0
  }, {
    "type": "B",
    "value": 0
  }, {
    "type": "C",
    "value": 0
  }]
}

const sync = [{
  r: 0,
  v: 1,
  t: 1000
}, {
  r: 0,
  v: 2,
  t: 1800
}, {
  r: 1,
  v: 5,
  t: 1400
}, {
  r: 2,
  v: 200,
  t: 2400
}];

const syncro = async(sync) => {
  const modVal = (i, value, time) => {
    return new Promise(resolve => {
      setTimeout(() => resolve(obj.rows[i].value += value), time);
    });
  }

  for (let seq of sync) {
    await modVal(seq.r, seq.v, seq.t);
    console.log(JSON.stringify(obj.rows));
  }
}

syncro(sync);
.as-console-row.as-console-row::after {
  content:'';
  padding:0;
  margin:0;
  border:0;
  width:0;
}

相关问题