Как реализовать функции получения и слияния, подобные lodash

JavaScript GraphQL

lodashВ основном он стал стандартом для написания библиотек инструментов javascript.Он широко используется в различных серверных и интерфейсных приложениях, но его размер пакета немного больше. Для сервера размер пакета не очень важен, или другими словами, он не так чувствителен к размеру пакета, как фронтенд, и каждая минута будет влиять на производительность открытия страницы, тем самым влияя на пользователя опыт.

Из-за важности размера внешнего пакета для взаимодействия с пользователем существуют различные способы уменьшить размер пакета. противlodashНапример, вам вообще не нужно импортироватьlodashВсе служебные функции , вам нужно только импортировать по мере необходимости или напрямую использовать единый пакет функций. Для ознакомления по запросу вы можете обратиться к следующим статьям

Lessons on tree-shaking Lodash with Webpack and Babel

на моемперсональный сайтсерединаlodashПри оптимизации, если я правильно помню,lodashсжато до80KBстал20KB, относительно большой. И когда я искал ссылки на lodash по всему миру, я обнаружил, что 90% сцен используют_.get.

Кроме того, сES6+разработка, а также поддержка браузера и Node для него, многиеlodashФункции просты в реализации или реализованы самостоятельно, например_.assign,_.trim,_.startsWithи т. д. были реализованы ES6+, а_.uniqлегко пройтиnew Set()решать. Кто-то выложил на гитхабеyou-dont-need/You-Dont-Need-Lodash-Underscore, который включает в себя очень простую реализацию многих служебных функций.

Поскольку этот сайт является тем, что я использую в качестве тестового поля для отработки различных техник, я решил реализовать его самостоятельно.lodashнекоторые полезные функции.getа такжеmergeЭти две функции относительно более сложны, когда я их использую Вот мой код реализации.

Адрес этой статьи:Mountain.Specialty/опубликовать/щелкнуть…

get

В js часто встречаются вложенные вызовы, напримерa.b.c.d.e, но таким образом легко генерировать исключения. вам нужно написатьa && a.b && a.b.c && a.b.c.d && a.b.c.d.e, но кажется немного многословным и многословным. Особенно в graphql таких вложенных вызовов избежать труднее.

Тогда вам нуженgetфункция, использованиеget(a, 'b.c.d.e')Просто и понятно, а отказоустойчивость значительно улучшена. Вот несколько тестовых случаев, которые необходимо пройти

get({ a: null }, 'a.b.c', 3)
// output: 3

get({ a: undefined }, 'a', 3)
// output: 3

get({ a: null }, 'a', 3)
// output: 3

get({ a: [{ b: 1 }]}, 'a[0].b', 3)
// output: 1

pathЭто также может быть путь к массиву, преобразованному в.оператор и сформировать массив

// a[3].b -> a.3.b
const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.')

Затем повторяйте свойства слой за слоем и обратите вниманиеnullа такжеundefinedВзятие атрибута сообщит об ошибке, поэтому используйтеObjectУпакуйте это.

function get (source, path, defaultValue = undefined) {
  // a[3].b -> a.3.b
  const paths = path.replace(/\[(\d+)\]/g, '.$1').split('.')
  let result = source
  for (const p of paths) {
    result = Object(result)[p]
    if (result === undefined) {
      return defaultValue
    }
  }
  return result
}

merge

mergeИспользуется для рекурсивного объединения объектов, что эквивалентно глубокомуObject.assign. существуетgraphqlбудет широко использоваться вmerge, если вы будете часто использоватьmergeСлиться всегоresolver,особенноMutationСледующий пример

const rootResolver = {
  Query: {
  
  },
  Mutation: {
    login () {}
  }
}

const userResolver = {
  User: {
    createUser() {}
  }
}

const resolver = merge(rootResolver, userResolver)
// output
// {
//   Query: {},
//   Mutation: {
//     login () {},
//     createUser () {}
//   }
// }

Кроме того, при запросе к graphql во внешнем интерфейсе часто необходимо использоватьmerge. Например, при оптимизации производительности страницы, чтобы запрос не занимал слишком много времени и отрисовка страницы не занимала слишком много времени, она будет разделена на два запроса, сначала будут отображаться данные с быстрым ответом, а затем данные с медленным откликом будет медленно ждать.

Ниже приведен запрос информации о профиле, но с полемdataNeedDelay3sЭто займет много времени на сервере, и это поле увеличит время ожидания пользователя, что приведет к недружественному взаимодействию с пользователем. В настоящее время это поле будет удалено отдельно, и в первую очередь будет отображаться другая личная информация.

query PROFILE {
  me {
    id
    age
    name
    # 需要耗时3s的字段
    dataNeedDelay3s
  }
}

# 拆为以下两个茶轩
query PROFILE_ONE {
  me {
    id
    age
    name
  }
}

query PROFILE_TWO {
  me {
    dataNeedDelay3s
  }
}

В это время естьmergeПосле завершения запроса результаты двух запросов объединяются.

Необходимость демонтировать Graphql Query есть везде, например, при рендеринге на стороне сервера необходимо отделить ресурсы разрешений от ресурсов непривилегий.

Вот как это сделатьmerge

function isObject (value) {
  const type = typeof value
  return value !== null && (type === 'object' || type === 'function')
}

// { a: [{ b: 2 }] } { a: [{ c: 2 }]} -> { a: [{b:2}, {c:2}]}
// merge({o: {a: 3}}, {o: {b:4}}) => {o: {a:3, b:4}}
function merge (source, other) {
  if (!isObject(source) || !isObject(other)) {
    return other === undefined ? source : other
  }
  // 合并两个对象的 key,另外要区分数组的初始值为 []
  return Object.keys({
    ...source,
    ...other
  }).reduce((acc, key) => {
    // 递归合并 value
    acc[key] = merge(source[key], other[key])
    return acc
  }, Array.isArray(source) ? [] : {})
}