如何按顺序执行javascript?

3

我期望的输出是:A,B,C。但它没有达到预期效果。假设函数 handleClick(element) 不能改变,我该如何更改其他函数以确保所有代码按顺序执行并按预期输出 A,B,C?

async function handleClick(element) {
  setTimeout(function(){
    console.log(`Click on Element_${element}`);
  }
  , Math.random(5)*1000);
}

async function clickLetter(letter) {
  await handleClick(letter);
}

async function clickGroup(group) {
  await handleClick(group);
}

const letters = ['A', 'B', 'C'];

function clickLetters(letters, fn) {
  let index = 0;
  return new Promise(function(resolve, reject) {
    function next() {
      if (index < letters.length) {
        fn(letters[index++]).then(next, reject);
      } else {
        resolve();
      }
    }
    next();
  });
}

clickLetters(letters, clickLetter);


你可以使用 async 库,https://caolan.github.io/async/docs.html#eachSeries - XCS
你得到了答案吗? - Yasser Hussain
@Cristy 不行,你不能这样做。在使用 Promises 时是无效的。 - Bergi
@Bergi能否详细说明一下?它不能像async.eachSeries(letters, clickLetter)这样使用吗? - XCS
@Cristy 不行,它不可能。clickLetter 返回一个 Promise,它不接受节点风格的回调。 - Bergi
3个回答

1
正如提及的那样,async库是/曾经是一种解决方法。
如果您想继续使用当前的解决方案,则问题出在您的handleClick()函数中,隐式Promise会立即返回,超时之前。然后,根据每次传递的随机超时时间,结果可能会导致执行错误或顺序错误。修复方法只是在超时后解决Promise。

function handleClick(element) {
  return new Promise(resolve => {
    setTimeout(function(){
      console.log(`Click on Element_${element}`);
      resolve();
    }
    , Math.random(5)*1000);
  });
}

async function clickLetter(letter) {
  await handleClick(letter);
}

function clickLetters(letters, fn) {
  let index = 0;
  return new Promise(function(resolve, reject) {
    function next() {
      if (index < letters.length) {
        fn(letters[index++]).then(next, reject);
      } else {
        resolve();
      }
    }
    next();
  });
}

const letters = ['A', 'B', 'C'];
clickLetters(letters, clickLetter);


1

在这里阅读有关异步和等待的信息。

以下是代码。解释在结尾处。

async function handleClick(element) {
   return new Promise((resolve, reject) => {
     setTimeout(function(){
       console.log(`Click on Element_${element}`);
       resolve();
     }, Math.random(5)*1000);
  });
}

async function clickLetter(letter) {
  await handleClick(letter);
}

async function clickGroup(group) {
  await handleClick(group);
}

const letters = ['A', 'B', 'C'];

async function clickLetters(letters, fn) {
  for(let i=0; i<letters.length; i++) {
    await clickLetter(letters[i]);
  }
}

clickLetters(letters, clickLetter);

解释所需的更改内容 -

  • 步骤1 - 将您的handleClick函数转换为返回Promise

  • 步骤2 - 在您的clickLetters函数中使用await按顺序打印值。


1

setTimeout 函数是异步的,并且结果会立即返回,您需要将其包装在一个 Promise 构造函数中,然后解决它。

function handleClick(element) {
   return new Promise((resolve, reject) => {
     setTimeout(() => {
       console.log(`Clicked on Element_${element}`);
       resolve();
     }, Math.random(5) * 1000);
  });
}

async function clickLetter(letter) {
  await handleClick(letter);
}

async function clickGroup(group) {
  await handleClick(group);
}

const letters = ['A', 'B', 'C'];

async function clickLetters(letters, fn) {
  for(let i = 0; i < letters.length; i++) {
    await clickLetter(letters[i]);
  }
}

clickLetters(letters, clickLetter);


所以如果我想让异步函数等待完成,我应该将其包装在 Promise 内?如果异步函数包含多层嵌套的异步调用,我必须使用 Promise 包装每个级别吗? - Linh
每当你处理回调函数时,例如在 setTimeout 的第一个参数中,你都会想要这样做。 - codejockie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接