Skip to content

Instantly share code, notes, and snippets.

@the-teacher
Last active March 2, 2023 21:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save the-teacher/47e66332918fb1db269eca71c8db5a78 to your computer and use it in GitHub Desktop.
Save the-teacher/47e66332918fb1db269eca71c8db5a78 to your computer and use it in GitHub Desktop.
Promise.All
// Идея. all принимает набор функций, которые возвращают промисы
// all содержит счетчик промисов к исполнению, массив с итоговым результатом, и итоговые коллбэки
// При выполнении промисы вызывают метод, который предоставляется all, чтобы проинформировать о совем выполнении и результате
// Внутри all счетчик снижается до нуля, пополняется массив результатов, при достижании нуля вызывается массив финальных колбэков,
// которые были устанавлены через then
// Какая идея предполагалась по "красоте" в оригинальном решении?
// Я предполагаю что оригинальный Promis.all и прочие промисы имеют общий интерфейс и проблем с обментом информации об исполнении у них не возникает
// Если делать свой собственный all -- то тут надо что-то придумывать отдельное. А что предполагалось?
const FIRST_DELAY = 3000
const SECOND_DELAY = 1000
const all = (arrayOfPromisesFuncts) => {
const allState = {}
let counter = arrayOfPromisesFuncts.length
const callbacksAll = []
const result = []
const resolveForAll = (value) => {
counter--;
result.push(value)
if (counter < 1) {
console.log("All is done")
callbacksAll.map((callback) => callback(result))
}
}
const then = (callback) => {
callbacksAll.push(callback)
return allState
}
Object.assign(allState, {
counter,
result,
then,
resolveForAll
})
arrayOfPromisesFuncts.map((func) => {
func.call(allState)
})
return allState
}
function promiseValue(value, ms) {
return function () {
return new Promise((resolve) => (
setTimeout(() => {
// Как предполагается взаимодействовать с `all`?
// Хвост от `all`, который я устанавливаю при вызове функции
if (this['resolveForAll']) {
this.resolveForAll(value)
}
resolve(value)
}, ms))
)
}
}
all([
promiseValue("1", FIRST_DELAY),
promiseValue("2", SECOND_DELAY)
]).then((result) => {
console.log("result", result)
}).then((result) => {
console.log("result 2", result)
}).then((result) => {
console.log("result 3", result)
});;
console.log("Hello World!")
console.log(`In ${FIRST_DELAY} ms there must be Promise All result`)
@the-teacher
Copy link
Author

the-teacher commented Mar 2, 2023

Вопрос: Я не понимаю, как предполагается взаимодействовать между оригинальным Promise и кастомным методом all

Если бы promiseValue возвращала не промис, а функцию, которая возвращает промис, то тогда бы я мог вызвать каждую функцию с кастомным контекстом (func.call(allState)), который создаю в all и предоставить функции метод resolveForAll.

Какая идея предполагалась по "красоте" в оригинальном решении? Как это должно было быть сделано?

@the-teacher
Copy link
Author

the-teacher commented Mar 2, 2023

Если сделать предположение, что внутури all можно делать then для вродящих промисов, а сама all может тоже возвращать промис, то можно сделать что-то такое

это уже эстетически более красиво

const FIRST_DELAY = 3000
const SECOND_DELAY = 1000

const all = (arrayOfPromises) => {
  let counter = arrayOfPromises.length
  const results = []

  return new Promise((resolve) => {
    arrayOfPromises.forEach((promise) => {
      // отказ от общения через общий интерфейс снаружи
      // Дождаться когда промис выполниться и уже вторым этапом обновить информацию в all
      // тк then тоже возвращает промис, это должно быть эквивалентно
      promise.then((result) => {
        counter--;
        results.push(result)
        if (counter < 1) {
          resolve(results)
        }
        return result
      })
    })
  })
}

function promiseValue(value, ms) {
  return new Promise((resolve) => (
    setTimeout(() => {
      resolve(value)
    }, ms))
  )
}

all([
  promiseValue("1", FIRST_DELAY),
  promiseValue("2", SECOND_DELAY)
]).then((result) => {
  console.log("result", result)
  return result
}).then((result) => {
  console.log("result 2", result)
  return result
}).then((result) => {
  console.log("result 3", result)
  return result
});;

console.log("Hello World!")
console.log(`In ${FIRST_DELAY} ms there must be Promise All result`)

@the-teacher
Copy link
Author

тк по документации then(onFulfilled, onRejected) берет еще параметром и reject функцию, то можно добавить это в основную реализацию

  return new Promise((resolve, reject) => {
    arrayOfPromises.forEach((promise) => {
      promise.then((result) => {
        counter--;
        results.push(result)
        if (counter < 1) {
          resolve(results)
        }
        return result
      }, reject)
    })
  })

@the-teacher
Copy link
Author

const FIRST_DELAY = 3000
const SECOND_DELAY = 1000

const all = (arrayOfPromises) => {
  let counter = arrayOfPromises.length
  const results = []

  return new Promise((resolve, reject) => {
    arrayOfPromises.forEach((promise) => {
      promise.then((result) => {
        counter--;
        results.push(result)
        if (counter < 1) {
          resolve(results)
        }
        return result
      }, reject)
    })
  })
}

function promiseValue(value, ms) {
  return new Promise((resolve) => (
    setTimeout(() => {
      resolve(value)
    }, ms))
  )
}

all([
  promiseValue("1", FIRST_DELAY),
  promiseValue("2", SECOND_DELAY)
]).then((result) => {
  console.log("result", result)
  return result
}).then((result) => {
  console.log("result 2", result)
  return result
}).then((result) => {
  console.log("result 3", result)
  return result
});;

console.log("Hello World!")
console.log(`In ${FIRST_DELAY} ms there must be Promise All result`)

@the-teacher
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment