Js — Как вызвать асинхронную функцию в Promise .then()

Во-первых, я должен упомянуть, что я уже просматриваю много вопросов в stackoverflow, но многие не отвечают на мой вопрос. Не говоря уже о том, что многие даже не имеют ответа.

Как мне добиться следующего, убедившись, что functionB() выполняется после завершения functionA()?


Примечание. Я не хочу преобразовывать свои асинхронные функции в new Promise(resolve=>{...})
потому что мне также придется преобразовать someServiceThatMakesHTTPCall() и любые другие асинхронные функции в стеке вызовов, что является большим изменением.

  function functionThatCannotHaveAsyncKeyword() {
      functionA()
        .then(async function() {
            await functionB();
        })
        .then(function() {
            console.info('last');
        });
  }

  async function functionA() {
      console.info('first');
      await someServiceThatMakesHTTPCall();
  }

  async function functionB() {
      console.info('second');
      await someServiceThatMakesHTTPCall();
  }

🤔 А знаете ли вы, что...
JavaScript имеет множество библиотек и фреймворков, таких как jQuery, Angular, и Vue.js.


19
26 853
3

Ответы:

Решено

Ваш подход с использованием await в обратном вызове asyncthen будет работать, но он излишне сложен, если все, который вы хотите сделать, это вызвать функцию async и распространить ее результат по цепочке. Но если вы занимаетесь другими делами и хотите использовать преимущества синтаксиса функций async, это нормально. Я вернусь к этому через минуту.

async функции возвращают промисы, поэтому вы просто возвращаете результат вызова вашей функции:

function functionThatCannotHaveAsyncKeyword() {
    functionA()
        .then(function() {
            return functionB(someArgument);
        })
        .then(function() {
            console.info('last');
        }); // <=== Note: You need a `catch` here, or this function needs
            // to return the promise chain to its caller so its caller can
            // handle errors
}

Если вы хотите передать значение разрешения functionA в functionB, вы можете сделать это еще более прямо:

functionA()
    .then(functionB)
    // ...

Когда вы возвращаете промис из обратного вызова then, промис, созданный вызовом then, является решил промисом, который вы возвращаете: он будет ждать, пока этот другой промис будет выполнен, а затем согласуется таким же образом.

Пример:

const wait = (duration, ...args) => new Promise(resolve => {
    setTimeout(resolve, duration, ...args);
});

async function functionA() {
    await wait(500);
    return 42;
}

async function functionB() {
    await wait(200);
    return "answer";
}

functionB()
.then(result => {
    console.info(result); // "answer"
    return functionA();
})
.then(result => {
    console.info(result); // 42
})
.catch(error => {
    // ...handle error...
});

Возвращаясь к вашему подходу с использованием обратного вызова asyncthen: это тоже работает и имеет смысл, когда вы делаете больше вещей:

const wait = (duration, ...args) => new Promise(resolve => {
   setTimeout(resolve, duration, ...args);
});

async function functionA() {
    await wait(500);
    return 42;
}

async function functionB() {
    await wait(200);
    return "answer";
}

functionB()
.then(async (result) => {
    console.info(result); // "answer"
    const v = await functionA();
    if (v < 60) {
        console.info("Waiting 400ms...");
        await wait(400);
        console.info("Done waiting");
    }
    console.info(v);      // 42
})
.catch(error => {
    // ...handle error...
});

если someServiceThatMakesHTTPCall является асинхронным, вы можете избежать всего этого, выполнив следующие действия:

function functionThatCannotHaveAsyncKeyword() {
    functionA()
        .then(function() {
            return functionB()
        })
        .then(function() {
            console.info('last');
        });
  }

  function functionA() {
      console.info('first');
      return someServiceThatMakesHTTPCall();
  }

  function functionB() {
      console.info('second');
      return someServiceThatMakesHTTPCall();
  }

Вы можете использовать обещание внутри первого метода как

function functionThatCannotHaveAsyncKeyword() {
    return new Promise(async(resolve, reject)=> {
          await functionA();
          await functionB();
          console.info('last');
          resolve();    
      });
  }

  async function functionA() {
      console.info('first');
      await someServiceThatMakesHTTPCall();
  }

  async function functionB() {
      console.info('second');
      await someServiceThatMakesHTTPCall();
  }