Próbuję napisać kawałek kodu za pomocą obietnic, unikając ich zagnieżdżenia, ale utknąłem w testowaniu zwróconych wyników, aby obsługiwać obietnice przepływ.

// zestaw zadań obietnictwa zwracające wartości

    function doTask1() => {
        return apiPromise1()
         .then((result1) => {
             return result1;
         })
    }
    function doTask2(result1, paramOne) => {
        return apiPromise2(result1, paramOne)
         .then((result2) => {
             return result2;
         })
    }
    function doTask3(result1) => {
        return apiPromise3()
         .then((result3) => {
             return result3;
         })
    }
    function doTask4(result1, paramOne) => {
        return apiPromise4()
         .then((result4) => {
             return result4;
         })
    }

// Główna obietnica w obsłudze przepływu obietnic zgodnie z obietnicami zwróconych wyników

    function getCurrentProcess(paramOne) {
        const promises = [];

   // how to get the returned result1 to be used by other promises ?
        promises.push(doTask1); 
        if (result1 === 'OK') {
            promises.push(doTask2(result1, paramOne));

            if (result2 === 'OK') {
                promises.push(doTask3(result1));

                if (result3 === 'OK') {
                    promises.push(doTask4(result1, paramOne));
                }
            }
        }

        return Promisz.all(promises)
        .then(() => {
            return 'well done'
        });

    }

// Początkowa funkcja wywołania

    exports.newJob = functions.https.onRequest((req, res) => {
      const paramOne = { ... }
      getCurrentProcess(paramOne).then((res) => {
        return { status: 200, infos: res };
      }, error => {
        return {status: error.status, infos: error.message};
      }).then(response => {
        return res.send(response);
      }).catch(console.error);
    });
2
user762579 4 czerwiec 2018, 09:48

5 odpowiedzi

Najlepsza odpowiedź

Możesz napisać funkcję opakowania, która zajmuje tablicę doTaskN jako funkcje odroczone:

const conditional = (...fns) => {
  if(fns.length === 0) return Promise.resolve();
  const [next] = fns;
  return next()
    .then(() => conditional(...fns.slice(1)));
};

Pomysł byłby przekazywany w odniesieniu do funkcji {X0}}, dzięki czemu funkcja conditional wykonuje je. Można to użyć jak:

conditional(doTask1, doTask2, doTask3, doTask4)
    .then(() => {
      console.log("all done");
    })
    .catch(() => {
      console.log("failed");
    });

Oto pełny przykład, jak go używać:

const conditional = (...fns) => {
  if(fns.length === 0) return Promise.resolve();
  const [next] = fns;
  return next()
  	.then(result => {
      console.log("task:", result);
      if(result === "OK") {
        return conditional(...fns.slice(1))
      }
    });
};

const task1 = (param1, param2) => Promise.resolve("OK");

const task2 = (param1) => Promise.resolve("OK");

const task3 = () => Promise.resolve("failed");

const task4 = () => Promise.resolve("OK");

conditional(() => task1("one", 2), () => task2(1), task3, task4)
	.then(() => {
      console.log("all done");
    })
	.catch(() => {
      console.log("failed");
    });
0
CodingIntrigue 4 czerwiec 2018, 07:36

Jeśli chcesz napisać obietnice w bardziej proceduralny sposób, którego potrzebujesz, użyj async / czekaj (ES6). Jeśli potrzebujesz kompatybilności wstecznej z ES5, musisz użyć Babel lub maszynozistom, który tłumaczy oczekiwania / asynchronizacji do ES5.

async function getCurrentProcess(paramOne) {
    const result1 = await doTask1(); 
    if (result1 === 'OK') {
        const result2 = await doTask2(result1, paramOne);

        if (result2 === 'OK') {
            const result3 = await doTask3(result1);

            if (result3 === 'OK') {
                await doTask4(result1, paramOne);
            }
        }
    }

    return 'well done'

}

Bez asynchronizacji / czeka, musisz użyć łańcucha obietnictwa:

doTask1().then((result1)=>{
   if (result1 === 'OK') {
      ...
   }
   ...
})

Jednak nie będzie to spowodować czytelnego kodu.

1
Aik 4 czerwiec 2018, 07:20

Jeśli chcesz, aby wynik zwrotu obietnicy jest używany przez inne obietnice, nie powinieneś używać metody Promise.all(), ponieważ nie działa metodami w żądanym zamówieniu, po prostu czeka na wszystkie metody obietnicy do zakończenia i zwraca wszystkie wyniki.

Może coś takiego jak Promise-Array-Runner pomoże?

Może możesz sprawdzić, czy result === 'OK' wewnątrz metody zadania? Lub utwórz Factory, co dba o to.

0
Tomislav 4 czerwiec 2018, 07:07
 .then((result1) => {
     return result1;
 })

Jest no-op i należy pominąć, ale przypuszczam, że prawdziwy kod nie ma tego problemu.

Jest to przypadek użycia dla async funkcji, ponieważ mogą bezproblemowo obsłużyć tego rodzaju przepływu sterowania, ponieważ inna odpowiedź sugeruje. Ale od async jest cukrem składniowym dla surowych obietnic, można go napisać w ES6. Ponieważ zadania zależą od wyników siebie, nie mogą być przetwarzane z Promise.all.

To samo jest to samo przypadek, co Ten, który używa async.

Możesz porwać z łańcucha obietnic, rzucając wyjątkiem i unikaj zagnieżdżonych warunków z:

// should be additionally handled if the code is transpiled to ES5
class NoResultError extends Error {}

function getCurrentProcess(paramOne) {
    doTask1()
    .then(result1 => {
      if (result1 !== 'OK') throw new NoResultError(1);
      return result1;
    })
    .then(result1 => ({ result1, result2: doTask2(result1, paramOne) }))
    .then(({ result1, result2 }) => {
      if (result2 !== 'OK') throw new NoResultError(2);
      return result1;
    })
    // etc
    .then(() => {
        return 'well done';
    })
    .catch(err => {
      if (err instanceof NoResultError) return 'no result';
      throw err;
    })
}

Ponieważ result1 jest używany w wywołaniach zwrotnych then, można go zaoszczędzić w zmiennej zamiast przekazywanej przez łańcuch obietnictwa.

Łańcuch obietnic może stać się prostszy, jeśli NoResultError s został rzucony w funkcje zadań.

0
Estus Flask 4 czerwiec 2018, 09:42

Dzięki wszystkim informacjom zwrotnym !!

Wszystkie odpowiedzi to prawa ... Głosowałem jednak na rozwiązanie funkcji CodingIntrigue Wtaper w moim przypadku ...

1 - Jak używam funkcji Firebase, nadal jest ES5, nie mogę używać synchronizacji / czeka. Korzystanie z Babel lub maszynopastu dla funkcji FireBase spowoduje znacznie więcej prac instalacyjnych ...

2 - Przetestowałem różne przypadki użytkowania, a ten wzór jest całkiem łatwy do zrozumienia z poziomem JS ... Jestem surowy, że można go poprawić później ..

Więc w końcu dostałem to ...

    let auth = null;
    let myList = null;

    const conditional = (...fns) => {
      if(fns.length === 0) return Promise.resolve();
      const [next] = fns;
      return next()
        .then(result => {
          if(result) {
            return conditional(...fns.slice(1));
          }
          return result;
        });
    };

    const task1 = (param1) => Promise.resolve()
        .then(() => {
        console.log('TASK1 executed with params: ', param1)
        auth = "authObject"
          return true;
        });

    const task2 = (param1, param2) => Promise.resolve()
        .then(() => {
        console.log('TASK2 executed with params: ', param1, param2)
          return true;
        });

    const task3 = (param1, param2) => Promise.resolve()
        .then(() => {
        console.log('TASK3 executed with params: ', param1, param2)
        myList = "myListObject"
        console.log('search for param2 in myList...')
        console.log('param2 is NOT in myList task4 will not be executed')
          return false;
        });

    const task4 = (param1) => Promise.resolve()
        .then(() => {
        console.log('TASK4 executed with params: ', param1)
          return true;
        });

    // FIREBASE HTTP FUNCTIONS ==================
    exports.newContactMessage = functions.https.onRequest((req, res) => {
      conditional(() => task1("senderObject"), () => task2(auth, "senderObject"), () => task3(auth, "senderObject"), () => task4("senderObject"))
        .then((res) => {
        return { status: 200, infos: res };
      }, error => {
        return {status: error.status, infos: error.message};
      }).then(response => {
        return res.send(response);
      }).catch(console.error);
    });
0
user762579user762579 4 czerwiec 2018, 10:42