alexbuki
@alexbuki
программист js

Какой тест не пройдет мое решение задачи?

Извиняюсь за повторение вопроса, но никак не могу найти ошибку в решении задачи.
Условия:
Ваш коллега-разработчик из параллельной вселенной прислал вам свою новую библиотеку для управления космическим кораблем. Т.к. космический корабль штука сложная, то и API у библиотеки довольно «развесистый», точное число методов неизвестно, документации, разумеется, нет. Зато известно, что в параллельной вселенной люди ходят по потолку, спят днём, работают ночью, а ещё используют только асинхронные функции и всегда передают callback первым аргументом. Странные ребята! У нас на Земле уже давно все на промисах пишут. Однако библиотеку нужно интегрировать в проект. Поэтому вам поступила задача написать обёртку, которая будет предоставлять тот же API, но на промисах.

Формат ввода
Пример исходного API:

const api = {  
  a: {  
    b: {  
      c: callback => setTimeout(() => callback(null, ’hello’), 100)  
    }  
  },  
  aa: {  
    bb: (callback, x, y) => setTimeout(() => callback(null, x + y), 200)  
  }  
};
Формат вывода
Отправьте решение в виде:

/**  
 * @param {Object} api - исходное API  
 * @returns {Object}  
 */  
module.exports = function promisify(api) {  
  // ...  
  return promisedApi;  
};
Пример использования:

const promisedApi = promisify(api);  
promisedApi.a.b.c()  
  .then(res => console.log(res)); // => ’hello’


Примечания
обёртка должна возвращать rejected promise в случае ошибки при вызове исходного API, callback всегда принимает ошибку первым аргументом:
callback(error, data)
в исходном API могут встречаться константы (числа, строки и булевые), их нужно возвращать как есть:
api.foo.myConst = 1;
promisedApi.foo.myConst === 1;
инициализация обёртки должна быть «ленивой»: в исходном API может быть большое количество неймспейсов, и обращаться к ним нужно по мере использования.

Решение:
function promisify (api) {
  if (!api) return null // на случай если нам ничего не пришло
  const promisedApi = {}
  for (const prop in api) {
    if (typeof (api[prop]) === 'function') {
      promisedApi[prop] = (...args) => {
        return new Promise((resolve, reject) => {
          api[prop]((err, result) => {
            if (err) reject(err)
            else resolve(result)
          }, ...args)
        })
      }
    } else if (api[prop] && typeof (api[prop]) === 'object') {
      promisedApi[prop] = promisify(api[prop]) // рекурсивно обходим все вложенные свойства
    } else {
      promisedApi[prop] = api[prop] // статические свойства возвращаем как есть
    }
  }
  return promisedApi
}

const api = {
  foo: {
    myConst: 12, p: true, c: '12dsf'
  },
  a: {
    b: {
      c: callback => setTimeout(() => callback(null, 'hello'), 100),
    },
    foo: {
      myConst: 14, p: 2
    }
  },
  aa: {
    bb: (callback, x, y) => setTimeout(() => callback(null, x + y), 200)
  }
}
const promisedApi = promisify(api)

console.log(promisedApi.foo.myConst, promisedApi.foo.p, promisedApi.foo.c) // => 12 true '12dsf'
promisedApi.a.b.c().then(res => console.log(res)).catch(err => console.error(err))// => hello
promisedApi.aa.bb(1, 2).then(res => console.log(res)).catch(err => console.error(err)) // => 3
  • Вопрос задан
  • 191 просмотр
Решения вопроса 1
miraage
@miraage
Старый прогер
Не уверен, что для Ваших целей подходит, но как идея сойдёт: https://codesandbox.io/s/eager-frost-5rm7o

function promisify(obj) {
  const cache = {}

  return new Proxy(obj, {
    get(target, prop) {
      const value = target[prop]
      const type = Object.prototype.toString.call(value)

      if (type === '[object Object]') {
        if (!cache[prop]) {
          cache[prop] = promisify(value)
        }

        return cache[prop]
      } else if (type === '[object Function]') {
        if (!cache[prop]) {
          cache[prop] = function (...args) {
            return new Promise((resolve, reject) => {
              const callback = (err, result) => {
                if (err) {
                  reject(err)
                } else {
                  resolve(result)
                }
              }

              value.call(this, callback, ...args)
            })
          }
        }

        return cache[prop]
      }

      return value
    },
  })
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы