Почему время моей "жизнеспособной" функции истекло? - PullRequest
1 голос
/ 03 мая 2020

Я возился с идеей отмены обещания - прозрачный способ использования функции более высокого порядка. И я придумал это:

export const fnGetter = state => fn => (...args) => {
  if (!state.canceled) return fn(...args)
  return Promise.resolve()
}

export const cancelable = (promise, state = {}) => {
  const getFn = fnGetter(state)

  return {
    then: fn => cancelable(promise.then(getFn(fn)), state),
    catch: fn => cancelable(promise.catch(getFn(fn)), state),
    cancel: () => {
      state.canceled = true
    }
  }
}

export const withCancel = promiseReturningFn => (...args) =>
  cancelable(promiseReturningFn(...args))

А вот несколько юнит-тестов, в которых я проверяю желаемое поведение.

const delay = withCancel(ms => new Promise(run => setTimeout(run, ms)))

test('works like normal promise when not canceled', async () => {
  const first = jest.fn()
  const second = jest.fn()

  await delay(1000).then(first).then(second)

  expect(first).toHaveBeenCalledTimes(1)
  expect(second).toHaveBeenCalledTimes(1)
})

test('when ignored, does not call callbacks', async () => {
  const first = jest.fn()
  const second = jest.fn()

  const promise = delay(1000).then(first).then(second)
  promise.cancel()

  await promise

  expect(first).not.toHaveBeenCalled()
  expect(second).not.toHaveBeenCalled()
})

Я не могу понять, почему первый тест пройден, но вызов .cancel() во втором модульном тесте истекает.

Edit

I думаю это как-то связано с тем, что await обрабатывает then метод под капотом. Мне просто нужна помощь на данный момент. Я бы хотел, чтобы он был совместим с asyn c await. Вот проходная версия, которая не зависит от await.

test('when ignored, does not call callbacks', async () => {
  const first = jest.fn()
  const second = jest.fn()

  const promise = delay(1000).then(first).then(second)
  promise.cancel()

  setTimeout(() => {
    expect(first).not.toHaveBeenCalled()
    expect(second).not.toHaveBeenCalled()
  }, 2000)
})

Ответы [ 2 ]

1 голос
/ 04 мая 2020

Одна проблема состоит в том, что then должен принимать два параметра для обработки отклонений .

Что касается того, почему оно истекло: вы используете await promise, а await - используйте then, и ваш promise отменяется, поэтому он никогда не вызывает свои обратные вызовы. Отмененное обещание должно вызвать обратный вызов onreject, а ваш fnGetter должен игнорировать эту ошибку отмены только для тех обратных вызовов, которые действительно ожидали отмены.

0 голосов
/ 03 мая 2020

Мне кажется, я знаю, что происходит. Из чтения это выглядит так: await просто берет последующий код, оборачивает его в функцию и затем передает эту функцию в метод then того, что ожидается. Если это так, то мой код работает, и операторы expect никогда не выполняются, потому что мое обещание (ожидаемое) отменено. Вот почему запуск теста с setTimeout работает.

Вот базовый c пример функциональности, о которой я говорю.

const func = async () => {
  await { then: () => console.log("test") }
  console.log("after")
}

Приведенный выше код выводит "test" и никогда не печатает "after", потому что console.log("after") упаковывается в функцию и передается методу then объекта, который никогда не вызывает его.

...