ES6 JS Promises - как избежать условного вложения - PullRequest
0 голосов
/ 04 июня 2018

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

// набор заданий обещаний, возвращающих значения

    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;
         })
    }

// основное обещание для обработки потока обещаний в соответствии с возвращенными результатами обещаний

    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'
        });

    }

// начальная функция вызова

    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);
    });

Ответы [ 5 ]

0 голосов
/ 04 июня 2018

Спасибо за все отзывы !!

Все ответы являются правами ... однако я голосовал за решение функции wtapprer CodingIntrigue в моем случае ...

1 - Поскольку я использую функции Firebase, это все еще ES5, я не могу использовать синхронизацию / ожидание.Использование babel или машинописного текста только для функций Firebase приведет к гораздо большей работе по настройке ...

2 - я тестировал различные варианты использования, и этот шаблон довольно легко понять с уровнем JS ... Я уверен, что онможет быть улучшено позже ..

так что наконец я запустил это ...

0 голосов
/ 04 июня 2018
 .then((result1) => {
     return result1;
 })

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

Это вариант использования для функции async, потому что они могут беспрепятственно обрабатыватьэтот вид потока управления, как предполагает другой ответ.Но поскольку async является синтаксическим сахаром для необработанных обещаний, его можно записать на ES6.Поскольку задачи зависят от результатов друг друга, они не могут быть обработаны с помощью Promise.all.

. Это тот же случай, что и , который использует async.

Youможет выйти из цепочки обещаний, выдав исключение и избежав вложенных условий с помощью:

// 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;
    })
}

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

Цепочка обещаний могла бы стать проще, если бы в задачи были добавлены NoResultError.

0 голосов
/ 04 июня 2018

Если вы хотите писать обещания более процедурным способом, вам нужно использовать async / await (ES6).Если вам нужна обратная совместимость с ES5, вам нужно использовать babel или машинопись, которая переводит await / async в 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'

}

Без асинхронного / await вам необходимо использовать цепочку обещаний:

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

Однако он не даст читабельный код.

0 голосов
/ 04 июня 2018

Вы можете написать функцию-обертку, которая принимает массив doTaskN в качестве отложенных функций:

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

Идея состоит в том, чтобы передать ссылку на функции doTask, чтобы conditional функция выполняет их.Это можно использовать как:

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

Вот полный пример того, как его использовать:

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 голосов
/ 04 июня 2018

Если вы хотите, чтобы ваш результат возврата обещания использовался другими обещаниями, вы не должны использовать метод Promise.all(), потому что он не запускает методы в нужном вам порядке, он просто ожидает завершения всех методов обещанияи возвращает все результаты.

Может быть, что-то вроде обещание-массива-бегуна поможет?

Может быть, вы могли бы проверить, если result === 'OK' внутри вашего метода задачи?Или создайте Factory, который позаботится об этом.

...