"Небольшая помощь!" с асинхронным синтаксисом в javascript. Я старый новичок ie, и я нахожу это более чем разочаровывающим - PullRequest
1 голос
/ 04 марта 2020

Я просто хотел бы запустить асинхронную функцию c, подождать, пока она не получит возвращаемое значение, передать это возвращаемое значение другой асин * c функции и wa sh и повторить несколько раз. Я видел несколько примеров, но я изо всех сил стараюсь заставить их работать в тестовом коде. Прости весь бейсбольный контекст, но мне пришлось немного повеселиться с этим самоназванным носовым кровотечением.

Я даже не могу заставить его работать без передачи возвращаемых значений в прикрепленном коде, чувствуя себя довольно глупо на данный момент ...

whosOnFirst(1)
.then(whatsOnSecond(2))
.then(iDunnosOnthird(3)) 

Я хотел бы увидеть синтаксис для выполнить whosOnFirst (1), передать возвращаемое значение в whatsOnSecond () и передать возвращаемое значение в iDunnosOnthird (). Создание желаемого результата (без пробелов), на который есть ссылка в нижней части фрагмента.

Я очень ценю помощь!

// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { // 
    console.log(`${callerName} called, waiting ${pause} second(s)...`)
    setTimeout(function () {
        console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
        return pause + 1; // delayed return value / adds 1 to input param 
    }, pause * 1000);
}

// Who's On First - run this first with an input param = 1
async function whosOnFirst(i) {
    waitSec("who's on first", 1).then(result => {
        return result;
    })
}

// What's on Second - run after completion of whosOnFirst() using return for param
async function whatsOnSecond(i) {
    waitSec("what's on second", i).then(result => {
        return result;
    })
}

// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
async function iDunnosOnthird(i) {
    waitSec("iDunno's on third", i).then(result => {
        return result;
    })
}

whosOnFirst(1)
    .then(whatsOnSecond(2))
    .then(iDunnosOnthird(3))


// CURRENT OUTPUT: 
// who's on first called, waiting 1 second(s)...
// what's on second called, waiting 2 second(s)...
// iDunno's on third called, waiting 3 second(s)...
// who's on first sent 2 in a return, and done!
// what's on second sent 3 in a return, and done!
// iDunno's on third sent 4 in a return, and done!

// DESIRED OUTPUT:
// who's on first called, waiting 1 second(s)...
// who's on first sent 2 in a return, and done!

// what's on second called, waiting 2 second(s)...
// what's on second sent 3 in a return, and done!

// iDunno's on third called, waiting 3 second(s)...
// iDunno's on third sent 4 in a return, and done!

Ответы [ 4 ]

3 голосов
/ 04 марта 2020

Рабочий раствор

Ваша проблема в том, что waitSec находится в другом контексте, чем остальная часть кода. Вам нужно поднять его до контекста Promise.

Тогда у вас есть «обещанный» код, и вы можете связывать обещания. Вот это работает (дальнейшее объяснение ниже):

// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { // 
    return new Promise(resolve => {
      console.log(`${callerName} called, waiting ${pause} second(s)...`)
      setTimeout(function () {
        console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
        resolve(pause + 1); // delayed return value / adds 1 to input param 
      }, pause * 1000);
    })
}

// Who's On First - run this first with an input param = 1
   function whosOnFirst(i) {
   return waitSec("who's on first", 1)
}

// What's on Second - run after completion of whosOnFirst() using return for param
function whatsOnSecond(i) {
   return waitSec("what's on second", i)
}

// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
function iDunnosOnthird(i) {
    return waitSec("iDunno's on third", i)
}

whosOnFirst(1)
    .then(whatsOnSecond)
    .then(iDunnosOnthird)
    .then(console.log)

Дальнейшее объяснение

Ваша первоначальная реализация waitSec всегда возвращает undefined вызывающей стороне:

// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { // 
    console.log(`${callerName} called, waiting ${pause} second(s)...`)
    setTimeout(function () {
        console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
        return pause + 1; // delayed return value / adds 1 to input param 
    }, pause * 1000);
    // return undefined happens here
}

Возврат внутри setTimeout не возвращается ваш код вызова, потому что ваш код никогда не вызывает эту функцию . Он вызывается с помощью кода таймера JS асинхронно.

Возвращение значений из асинхронного кода c с использованием обратного вызова

Способ сообщить результат оттуда вызывающей стороне: либо возьмите обратный вызов в качестве параметра для внешней функции и вызовите этот обратный вызов в функции asyn c, например:

function waitSec({callerName, pause, callback}) {
      console.log(`${callerName} called, waiting ${pause} second(s)...`)
      setTimeout(function () {
        console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
        callback(pause + 1); // delayed return value / adds 1 to input param 
      }, pause * 1000);
}

В этом случае у вас есть шаблон обратного вызова classi c JS.

Использование обещаний и почему вы можете их предпочесть

Или вы возвращаете обещание и разрешаете его, чтобы вернуть значение - как я продемонстрировал в решении. Чтобы узнать больше об этом, поищите «как мне обещать обратный вызов».

Преимущество выполнения этого способа (с обещанием) состоит в том, что обещания являются составными, как показано в решении.

Обещания также возможны await, поэтому вы можете использовать async / await с функциями, возвращающими обещание.

Вам не нужно отмечать функции, возвращающие обещание, как async.

Если вы помечаете функцию как async, она возвращает Обещание, например:

// A function marked async returns a Promise
async function simple() {
  return 3
}

// Proof that it is a Promise 
simple().then(console.log)

// The equivalent code explicitly returning a Promise - this is what `async` does
function simpleP(n = 0) {
  return new Promise(resolve => resolve(n+1))
}

// Proof that it behaves the same
simpleP().then(console.log)

// Promise composition
simple()
  .then(simpleP)
  .then(console.log)
  
// Same functionality, using async/await
async function main() {
  const num = await simple()
  const res = await simpleP(num)
  console.log(`${num} + 1 = ${res}`)
}

main()

Маркировка функций синхронного возврата async делает их компонуемыми с помощью асинхронного c кода, который на самом деле нуждается в Promise для возврата значения. Вы можете использовать его, чтобы поднять ваши функции в тот же контекст asyn c и составить их.

// Synchronous function that is Promisified and composable
async function simple() {
   return 3
}

Чтобы фактически получить значение из асинхронной функции, которая принимает обратный вызов и обеспечивает его возврат через него, вы должны создать и вернуть Promise из своей функции, а затем вызвать Promise resolve внутри функции обратного вызова, которая предоставляет значение, которое вы хотите передать.

function getDBRecordP(id) {
  return new Promise((resolve, reject) => 
    dbLib.get(id, 
      (err, result) => err ? 
        reject(err) : 
        resolve(result)))
}

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

То, что он делает - это оборачивает интерфейс обратного вызова для вас.

function getDBRecordP(id) {
  return new Promise((resolve, reject) => 
    dbLib.get(id, 
      (err, result) => err ? 
        reject(err) : 
        resolve(result)))
}

Обратите внимание, что в примере обратного вызова вы должны были взять аргумент callback от вызывающей стороны в качестве параметра, а затем вызвать его с возвращаемым значением внутри обратного вызова, который предоставляет значение.

С механизмом Promise вы принимаете аргумент обратного вызова, но он не предоставляется вызывающей стороной, он предоставляется созданным вами Promise. А затем вы возвращаете обещание вызывающей стороне.

Вышеприведенная функция getDBRecordP представляет собой суть «как преобразовать функцию, которая принимает обратный вызов, в функцию, которая возвращает обещание?».

Затем вызывающая сторона передает обратный вызов методу Promise.then().

Таким образом, у вас есть машина, которая оборачивает соглашение о передаче обратного вызова в формальный API, который можно компоновать, а обратные вызовы - нет.

Другим аспектом машины Promise является метод .catch().

Принимая во внимание, что с обратными вызовами всегда было принято, что подпись обратного вызова (err, result), машина Promise позволяет вам предоставить два обратных вызовов - один для err и один для result.

1 голос
/ 04 марта 2020

Пожалуйста, используйте ключевое слово await, которое прекрасно для функции async. Ваша waitSec функция должна возвращать обещание, также, когда вы выполняете обещание, ваше значение равно .then((res)=> console.log(res)), используйте его для цепочки, как показано ниже:

// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { // 

  return new Promise((resolve, reject) => {
    console.log(`${callerName} called, waiting ${pause} second(s)...`)
    setTimeout(function() {
      console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
      resolve(pause + 1); // delayed return value / adds 1 to input param 
    }, pause * 1000);
  })

}

// Who's On First - run this first with an input param = 1
async function whosOnFirst(i) {
  const resp = await waitSec("who's on first", 1);
  return resp;
}

// What's on Second - run after completion of whosOnFirst() using return for param
async function whatsOnSecond(i) {
  const resp = await waitSec("what's on second", i);
  return resp;
}

// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
async function iDunnosOnthird(i) {
  const resp = await waitSec("iDunno's on third", i);
  return resp;
}


whosOnFirst(1).then((firstResp) => {
  whatsOnSecond(firstResp).then((secResp) => {
    iDunnosOnthird(secResp).then((thirdResp) => {
      console.log(thirdResp);
    })
  })
})

Вы также можете использовать значения в цепочке, как показано ниже, с async/await:

// Arbitrary timer with input/output parameters for async understanding;
function waitSec(callerName, pause) { // 

  return new Promise((resolve, reject) => {
    console.log(`${callerName} called, waiting ${pause} second(s)...`)
    setTimeout(function() {
      console.log(`${callerName} sent ${pause + 1} in a return, and done!`)
      resolve(pause + 1); // delayed return value / adds 1 to input param 
    }, pause * 1000);
  })

}

// Who's On First - run this first with an input param = 1
async function whosOnFirst(i) {
  const resp = await waitSec("who's on first", 1);
  return resp;
}

// What's on Second - run after completion of whosOnFirst() using return for param
async function whatsOnSecond(i) {
  const resp = await waitSec("what's on second", i);
  return resp;
}

// iDunno's on third - run after completion of whatsOnSecond(i) using return for param
async function iDunnosOnthird(i) {
  const resp = await waitSec("iDunno's on third", i);
  return resp;
}



let test = async() => {
  var res1 = await whosOnFirst(1);
  var res2 = await whatsOnSecond(res1);
  var res3 = await iDunnosOnthird(res2);
  console.log(res3);
}

test();
0 голосов
/ 04 марта 2020

Вот как это должно работать:

function delay(milliseconds){
  return new Promise((resolve)=>{
    setTimeout(()=>{
      resolve();
    }, milliseconds);
  });
}
async function test(){
  console.log('no delay, yet');
  await delay(1000);
  console.log('After 1 second');
  await delay(1000);
  console.log('2 seconds have passed');
  await delay(3000);
  console.log('Oh look, 5 seconds have passed!');
}
test();

async функционирует await до тех пор, пока Promise не станет resolve d, затем go до следующего блока кода после Promise, возможно await снова и снова ... и снова. Признаюсь, мне показалось странным, что функция async действительно выполняет await s синхронно, но сама функция async она асинхронная ... это означает, что другая функция, выполняемая сразу после выполненного async function, вероятно, вернет результаты до выполнения async function.

В отношении вашего примера:

class Counter{
  constructor(increment = 1, initially = 0){
    this.increment = increment; this.count = initially;
  }
  inc(){
    return this.count += this.increment;
  }
  dec(){
    return this.count -= this.increment;
  }
}
function delay(milliseconds){
  return new Promise((resolve)=>{
    setTimeout(()=>{
      resolve();
    }, milliseconds);
  });
}
const sec = new Counter;
function logCaller(callerName){
  console.log(`${callerName} called, after ${sec.inc()} second(s)...`);
}
async function what(){
  await delay(1000);
  logCaller("who's on first");
  await delay(1000);
  logCaller("what's on second");
  await delay(1000);
  logCaller("iDunno's on third");
}
what();
0 голосов
/ 04 марта 2020

Вам нужно ждать каждого результата, подобного этому:

async function main() {
  const result1 = await whosOnFirst(1);
  // whosOnSecond will not get called except after the whosOnFirst is done.
  const result2 = await whosOnSecond(result1);
}
...