LowDB 轻量级 JSON 本地数据库

作为轻量级的本地存储方式,对于构建不依赖服务器的小型项目,用LowDB存储和管理数据是十分理想的选择。在Nodejs, Electron and browser等一些小型项目中经常能看到LowDB的身影。

https://github.com/typicode/lowdb

1. 使用方式

npm install lowdb

或者:

yarn add lowdb

const low = require(‘lowdb’);

const FileSync = require(‘lowdb/adapters/FileSync’); // 有多种适配器可选择

const adapter = new FileSync(‘db.json’); // 申明一个适配器

const db = low(adapter);

db.defaults({posts: [], user: {}, count: 0})

.write();

db.get(‘posts’)

.push({id: 1, title: ‘lowdb is awesome’})

.write()

db.set(‘user.name’, ‘typicode’)

.write()

db.update(‘count’, n => n + 1)

.write()

运行程序会在项目中添加db.json文件,里面存储了添加的数据:

{

“posts”: [

{

“id”: 1,

“title”: “lowdb is awesome”

}

],

“user”: {

“name”: “typicode”

},

“count”: 1

}

lowdb是基于lodash构建的,所以可以使用任何lodash强大的函数,比如: _.get() 和 _.find(),并且可以串联地使用:

db.get(‘users’)

.find({sex: ‘male’})

.value()

2. API

函数 功能

low(adapter) 返回一个具有特定属性和功能的 lodash chain

db.[…].write() / .value() 写 / 读数据

db.getState() / .setState() 获取 / 设置数据库的状态

db._ 数据库lodash的实例,可以利用这个添加自己的函数或者第三方的mixins,比如lodash-id

db._.mixin({

second: function(array) {

return array[1]

}

})

db.get(‘posts’)

.second()

.value()

3. Adapters API

针对lowdb自带的适配器:FileSync、FileAsync 和 LocalBrowser,有以下可选参数:

defaultValue: 文件不存在时的默认值;

serialize/deserialize: 写之前和读之后的操作。

const adapter = new FilSync(‘db.json’,{

serialize: (data) => encrypt(JSON.stringify(data)),

deserialize: (data) => JSON.parse(decrypt(data))

})

4. 查询

可以直接使用lodash的函数进行查询。需要注意的是有些操作可能会导致原数据被修改,为了避免这种误操作,需要使用 .cloneDeep(),操作都是惰性的,只有调用 .value()或 .write()后才会正式执行。

检查users是是否存在

db.has(‘users’)

.value()

设置users

db.set(‘users’, [])

.write()

排序、选择

db.get(‘users’)

.filter({sex: ‘male’})

.sortBy(‘age’)

.take(5)

.value()

获取特定字段

db.get(‘users’)

.map(‘name’)

.value()

获取数量

db.get(‘users’)

.size()

.value()

获取特定信息

db.get(‘users[0].name’)

.value()

更新信息

db.get(‘users’)

.find({name: ‘Tom’})

.assign({name: ‘Tim’})

.write()

删除信息

db.get(‘users’)

.remove({name: ‘Time’})

.write()

移除属性

db.unset(‘users.name)

.write()

深拷贝

db.get(‘users’)

.cloneDeep()

.value()

5. 使用id索引

可以使用 shortid 和 lodash-id 为数据库中的每一条记录创建唯一的id索引,然后通过id检索操作记录:

const shortid = require(‘shortid’)

const postId = db

.get(‘posts’)

.push({ id: shortid.generate(), title: ‘low!’ })

.write()

.id

const post = db

.get(‘posts’)

.find({ id: postId })

.value()

const lodashId = require(‘lodash-id’)

const FileSync = require(‘lowdb/adapters/FileSync’)

const adapter = new FileSync(‘db.json’)

const db = low(adapter)

db._.mixin(lodashId)

// We need to set some default values, if the collection does not exist yet

// We also can store our collection

const collection = db

.defaults({ posts: [] })

.get(‘posts’)

// Insert a new post…

const newPost = collection

.insert({ title: ‘low!’ })

.write()

// …and retrieve it using its id

const post = collection

.getById(newPost.id)

.value()

6. 自定义Adapter

low( ) 函数接受自定义的Adapter

class MyStorage {

constructor() {

// …

}

read() {

// Should return data (object or array) or a Promise

}

write(data) {

// Should return nothing or a Promise

}

}

const adapter = new MyStorage(args)

const db = low(adapter);

==============================================

英文官网介绍,更加简洁

Install


npm install lowdb

Usage

Lowdb 3 is a pure ESM package. If you’re having trouble importing it in your project, please read this.

import { join, dirname } from 'path'
import { Low, JSONFile } from 'lowdb'
import { fileURLToPath } from 'url'

const __dirname = dirname(fileURLToPath(import.meta.url));

// Use JSON file for storage
const file = join(__dirname, 'db.json')
const adapter = new JSONFile(file)
const db = new Low(adapter)

// Read data from JSON file, this will set db.data content
await db.read()

// If file.json doesn't exist, db.data will be null
// Set default data
// db.data = db.data || { posts: [] } // Node < v15.x
db.data ||= { posts: [] }             // Node >= 15.x

// Create and query items using plain JS
db.data.posts.push('hello world')
const firstPost = db.data.posts[0]

// Alternatively, you can also use this syntax if you prefer
const { posts } = db.data
posts.push('hello world')

// Finally write db.data content to file
await db.write()
// db.json
{
  "posts": [ "hello world" ]
}

TypeScript

You can use TypeScript to type check your data.

type Data = {
  words: string[]
}

const adapter = new JSONFile<Data>('db.json')
const db = new Low(adapter)

db.data
  .words
  .push('foo') // ✅

db.data
  .words
  .push(1) // ❌

Lodash

You can also add lodash or other utility libraries to improve lowdb.

import lodash from 'lodash'

type Post = {
  id: number;
  title: string;
}

type Data = {
  posts: Post[]
}

// Extend Low class with a new `chain` field
class LowWithLodash<T> extends Low<T> {
  chain: lodash.ExpChain<this['data']> = lodash.chain(this).get('data')
}

const adapter = new JSONFile<Data>('db.json')
const db = new LowWithLodash(adapter)
await db.read()

// Instead of db.data use db.chain to access lodash API
const post = db.chain
  .get('posts')
  .find({ id: 1 })
  .value() // Important: value() must be called to execute chain

More examples

For CLI, server and browser usage, see examples/ directory.

API

Classes

Lowdb has two classes (for asynchronous and synchronous adapters).

new Low(adapter)

import { Low, JSONFile } from 'lowdb'

const db = new Low(new JSONFile('file.json'))
await db.read()
await db.write()

new LowSync(adapterSync)

import { LowSync, JSONFileSync } from 'lowdb'

const db = new LowSync(new JSONFileSync('file.json'))
db.read()
db.write()

Methods

db.read()

Calls adapter.read() and sets db.data.

Note: JSONFile and JSONFileSync adapters will set db.data to null if file doesn’t exist.

db.data // === null
db.read()
db.data // !== null

db.write()

Calls adapter.write(db.data).

db.data = { posts: [] }
db.write() // file.json will be { posts: [] }
db.data = {}
db.write() // file.json will be {}

Properties

db.data

Holds your db content. If you’re using the adapters coming with lowdb, it can be any type supported by JSON.stringify.

For example:

db.data = 'string'
db.data = [1, 2, 3]
db.data = { key: 'value' }

Adapters

Lowdb adapters

JSONFileJSONFileSync

Adapters for reading and writing JSON files.

new Low(new JSONFile(filename))
new LowSync(new JSONFileSync(filename))

MemoryMemorySync

In-memory adapters. Useful for speeding up unit tests.

new Low(new Memory())
new LowSync(new MemorySync())

LocalStorage

Synchronous adapter for window.localStorage.

new LowSync(new LocalStorage(name))

TextFileTextFileSync

Adapters for reading and writing text. Useful for creating custom adapters.

Third-party adapters

If you’ve published an adapter for lowdb, feel free to create a PR to add it here.

Writing your own adapter

You may want to create an adapter to write db.data to YAML, XML, encrypt data, a remote storage, …

An adapter is a simple class that just needs to expose two methods:

class AsyncAdapter {
  read() { /* ... */ } // should return Promise<data>
  write(data) { /* ... */ } // should return Promise<void>
}

class SyncAdapter {
  read() { /* ... */ } // should return data
  write(data) { /* ... */ } // should return nothing
}

For example, let’s say you have some async storage and want to create an adapter for it:

import { api } from './AsyncStorage'

class CustomAsyncAdapter {
  // Optional: your adapter can take arguments
  constructor(args) {
    // ...
  }

  async read() {
    const data = await api.read()
    return data
  }

  async write(data) {
    await api.write(data)
  }
}

const adapter = new CustomAsyncAdapter()
const db = new Low(adapter)

See src/adapters/ for more examples.

Custom serialization

To create an adapter for another format than JSON, you can use TextFile or TextFileSync.

For example:

import { Adapter, Low, TextFile } from 'lowdb'
import YAML from 'yaml'

class YAMLFile {
  constructor(filename) {
    this.adapter = new TextFile(filename)
  }

  async read() {
    const data = await this.adapter.read()
    if (data === null) {
      return null
    } else {
      return YAML.parse(data)
    }
  }

  write(obj) {
    return this.adapter.write(YAML.stringify(obj))
  }
}

const adapter = new YAMLFile('file.yaml')
const db = new Low(adapter)

Limits

Lowdb doesn’t support Node’s cluster module.

If you have large JavaScript objects (~10-100MB) you may hit some performance issues. This is because whenever you call db.write, the whole db.data is serialized using JSON.stringify and written to storage.

Depending on your use case, this can be fine or not. It can be mitigated by doing batch operations and calling db.write only when you need it.

If you plan to scale, it’s highly recommended to use databases like PostgreSQL or MongoDB instead.

本文链接:https://www.dzdvip.com/34348.html 版权声明:本文内容均来源于互联网。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 395045033@qq.com,一经查实,本站将立刻删除。
(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年7月2日 18:25
下一篇 2022年7月2日 21:39

相关推荐

  • 买空调要注意什么(买空调怎么选择,需要注意什么)

    1.品牌:最好选择大型的空调供应商,全国售后广,对于后期维护非常有用。 2.控温面积:好好测量空调的控温面积,根据面积选择空调的大小。 3.能耗:注意空调的能耗比,尽量选择能耗低,能效高的空调;型号:空间较大的话,建议购买大型号的柜式机,制冷效果比较明显;独立开关:安装空调时,建议插座上安装一个空调智能开关,能够避免触电或空调烧坏。 畅谈关于装修的那些事,分享装修的各种经验和知识。大家好,我是畅谈装修,关注我即可了解更多关于装修的那些事! 空调是属于居家生活的“标配”家电,因此也被称为“室温调制器”。每到炎热的夏天,人们就想待在空调房里。 虽然说,家家户户都有空调,但真正了解空调的人却很少,所以在购买时往往会被“坑”到。本期,是用家里换了4台空调的经验,总结出一份超详细的选购指南,让您能做到花最少的钱,选到最适合新房的空调。 家用空调分类 对于家用空调来说,由于房屋的设计不同,因此也有着不同的空调类型。同时也因为生活水平的不同,空调档次也有所不同。 按技术特点可分为两种,分别是定频空调和变频空调。 变频空调是当下最常见的空调,也是多数人在选购时的第一选择,有着省电、性能更好等特点。 定频空调又称定速空调,只供电频率无法改变,当下已经很少生产了。 按结构也可分为两种,分别是整体式空调和分体式空调。 整体式空调主要包括窗式和移动式,这两类空调并不是家用的“主力军”,但也会配合使用。 作为分体式空调来说,是属于家用空调的“主力军”,这里面包括壁挂式、立式、中央空调、风管机。 家庭更适合于哪种空调 知道了空调的分类,那么作为家用空调来说,哪种更适合呢?相信这是大家最为关注的事,因此也将这个作为重点来说明。 1.壁挂式空调 作为家用空调中最常见的壁挂式空调来说,又称为壁挂机,它是一种分体式空调。 日常来说壁挂机的匹数一般在1P~2.5P之间,适合20㎡左右的区域来使用,最常见的是用于卧室和书房。 作为壁挂空调来说,最大的优势就是小空间使用,能够快速让其发挥出应有的优势。而且无论是前期购买还是后期的使用和维护保养,费用都是很便宜的,因此得到了众多消费者的喜欢,也成为家用空调的第一选择。 2.立式空调 立式空调简称柜机,也是分体式空调的一种,更是属于较大的空调种类了。 柜机的匹数一般在2P以上,相较于避挂机来说,它有着更大的功率、风力更强、制冷制热效果更好,因此多数情况下被用于适…

    2022年8月13日
    8
  • 人和大猩猩能生出孩子吗 人类和猩猩有生殖隔离吗

    2012年3月,英国的《自然》杂志上刊登了一篇有关于大猩猩基因研究的论文,该论文指出英国桑格研究所等机构的研究人员已经对大猩猩的基因组完成了测序。 而这一结果也代表着,科学家已经完成了对所有人科动物的基因组测序。 桑格研究所完成了对大猩猩基因组的测序 随着诸多基因测序结果的公布,大家意识到原来这些大猩猩真的与我们如此亲近,而科学家也在研究的过程中,发现了人类与大猩猩之间存在生殖隔离的原因。 那么,他们究竟是如何发现的呢? 人类和猩猩相似却有生殖隔离 基因研究揭露生殖隔离的真相 要弄清楚为什么人类和黑猩猩之间存在生殖隔离机制,就先要明白生殖隔离到底是什么。 它主要指的是亲缘关系相近的两个物种在自然环境之下不会交配,或者进行交配之后也无法诞下后代,有的即使能够生下后代,其后代也不具备繁衍特性。 以大家最熟悉的马和驴为例,它们之间就存在生殖隔离,这就导致它们虽然能交配并诞下后代,可是其后代却不能靠自身繁衍,自生下来就变成了“太监”。 驴和马的结合产下了无法繁育后代的骡子 生殖隔离可能发生在受精前或者受精后,二者的叫法有所不同。对于人类和大猩猩来说,生殖隔离应该就发生于受精前。 从分析来看,人类和各种灵长类动物的“分家时间”是不一样的,其中最早的是猩猩,它在1400万年以前就与人类分离了,而大猩猩在约1000万年以前才于人类分开,因此它与人类的基因相似度高达98%。 至于黑猩猩,它与人类的分离最晚,大约是600万年前。 各种灵长动物与人类的分家时间不同 该研究小组在对人类、黑猩猩和大猩猩体内超过11000个基因进行筛查之后发现,虽然表面上人类和黑猩猩之间的遗传关系更为密切,但实际上人类有15%的基因组序列更接近于大猩猩。 按理来说,基因的相似度都已经达到了如此恐怖的情况,想要实现交配并繁衍后代是有机会的。 人类和猩猩的基因相似度高达98% 可事实上,2%或者1%的差异都会让3000多万个基因点发生突变,在这种情况下,人体当中拥有的3万个基因,约有80%都会受到这些突变的影响。 资料显示由人的FOXP2基因(该基因有助于人类说话)制造出的蛋白质与黑猩猩体内该蛋白质相比,就有两个氨基酸不一样。此外,小脑症基因和ASPM基因的细微变化可能是造成人类和黑猩猩脑容量出现巨大差异的“幕后黑手”。 首先,人类的染色体数量是23对,大猩猩的染色体数量却有24对,在染色体数目不对等的情况下,…

    2022年10月27日
    40
  • 红米note12pro参数及价格

    这一次,红米Note 12 Pro在续航和性能方面依然会有所堆砌,价格也会一直亲民。“滚进去”也是严重的。至于外观,应该和前代没有太大区别,图像会继续沿用前代的1亿像素方案。 蓝牙支持蓝牙5.1,支持蓝牙Apt-X,音频规格:SBC,AAC,aptX HD,LDACNFC支持NFC(点对点模式,读卡器模式,卡模式),支持卡模拟WLAN双频WIFI,WiFi6(IEEE 802.11 a/b/g/n/ac/ax),支持WiFi 2×2 MIMO技术,支持8×8 MU-MIMO,WiFi Display定位系统GPS导航,A-GPS技术,Galileo导航,GLONASS导航,北斗导航手机功能感应器类型接近传感器,光线传感器,指纹识别 值得一提的是,由于红米Note12 Pro新机的曝光,导致红米Note11价格持续走低,甚至出现价崩。据搜狐科技报道,红米Note11在电商平台“拍易得”(paiyide.net)最新一期的活动中成交价仅162元,这不仅创下了该机上市以来的价格新低,更是智能机价格史上新的低价记录,使用浏览器输入paiyide.net访问“拍易得”即可获得最新详情。 因为今年的高通持续拉高,给了联发科很大的上升机会,天蝎目前的两款旗舰芯片都成了中端市场的“红人”。而红米Note 12 Pro也将是天机8100的一员。它基于TSMC的5nm工艺,在整体性能上碾压骁龙870,更不用说超越骁龙的888旗舰,拥有很高的口碑。有了这款芯片的加持,红米Note 12 Pro在游戏体验上肯定会更加出众。

    2022年6月9日
    83
  • 三只松鼠的营销策略

    “三只松鼠”是由安徽三只松鼠电子商务有限公司于2012年强力推出的第一个互联网森林食品品牌,代表着天然、新鲜以及非过度加工。“三只松鼠”仅仅上线65天,其销售在淘宝天猫坚果行业跃居第一名,花茶行业跃居前十名。其发展速度之快创造了中国电子商务历史上的一个奇迹。在2012年天猫双十一大促中,成立刚刚4个多月的“三只松鼠”当日成交近800万元,一举夺得坚果零食类目冠军宝座,并且成功在约定时间内发完10万笔订单,创造了中国互联网食品历史突破。 Phineas的回答 我之所以关注他,一开始是想知道,三只松鼠创始人章燎原的营销招数是否有效,因为事实上,他是传统营销人士转行做的电商,而非自成长的电商。 章燎原作为第一批触网的传统营销人士,透过他,我认为能观察到未来传统营销、传统商家对电商现有业态的胜负态势。 很幸运,见证了三只松鼠的崛起。或者说,第一阶段的崛起。三种松鼠有很强的团队,章燎原挖了很多人才,囊括了电商的各个方面。这是他崛起的第一前提:再好的设想、战略,没有靠谱的人去实施,那就等于空气。 其次是他合适现状的管理。很明显,大方向和小细节都抓的很好。大方向是,抓评论、抓客户回馈;细节则体现于是平面设计和客户体验全流程。 但是,上面的这些都是浮云——特别是对于那些,有一定稳定销售额的大中小卖家来说,他们好奇,为什么自己做不大,自己打不破行业第一的爆款式垄断,而章燎原可以打破原有的行业格局、打破原有的爆款,进而做大? 如果做沙盘推演,我以为章燎原的战略要点在于如下几点: 在红海中挖掘蓝海。 坚果类市场,是个红海市场。但是碧根果(松鼠家的主打产品)是个蓝海市场。 做个对比,再看看老产品开心果。 我们看到碧根果极具成长力,它离市场饱和还远得很。 这里举个例子,大概2006年左右,我第一次吃碧根果,奶油味的,口感很棒,感觉比核桃好。然后我请朋友吃了一颗,她后来在qq告诉我说,念念不忘,逼着男朋友找了很久,买到了,不过好像没有我的好吃。 所以,章燎原选择碧根果作为主打,是有深刻动机的。碧根果本身市场的扩大也是支撑三只松鼠目前业绩的第一个关键原因。 如果你觉得这就是蓝海,你就simple了。 中国商人足够多。任何蓝海都是红海。只不过,有的是浅红,有的是深红。碧根果为代表的新一代坚果市场,是个浅红,这里还不曾出现一个领导品牌。 碧根果市场,很热闹,竞争很残酷,不是你挂个三只松鼠牌子就可以卖…

    2021年12月27日
    17
  • 小白轻松月入10000+的闲鱼玩法分享

    今年不少人都感觉互联网氛围越来越严峻,绝大部分平台、项目都趋向于规范化,放眼望去,似乎阳光、正规、合法、长期的项目离自己很遥远。想启动这一类型项目,除非有充足的资金准备或者有强大的资源作为支撑,否则将举步维艰。 虽然互联网项目层次不穷,但坑也很多,乱花渐欲迷人眼。但只要肯细心观察,还是可以发现适合自己操作的好项目,比如闲鱼就是其中之一。 众所周知,闲鱼是阿里旗下的二手物品交易平台,据相关数据显示,该平台的活跃用户与日俱增,主要以80后、90后为主,产品需求日益多样化,物美价廉的商品逐渐成为主流趋势,早在去年一年闲鱼的成交金额已逾千亿,市场不容小觑。 有人的地方,就有流量,有流量的地方,肯定就有营销。 目前我的团队也在操作这个项目,下面就把操作实操方法分享给大家,之所以分享给大家,是因为这个项目是没有竞争对手,市场足够大,希望这一次的分享能给您带来帮助。 之所以分享闲鱼项目,因为门槛较低,几乎不用投入什么成本,不管您是个人,还是团队,只要您手上有一部手机就可以操作,兼职还是全职都可以。 接下来我实战一步步告诉您: 1、新手小白如何操作闲鱼? 想做好闲鱼,首先就要解决闲鱼号的问题。闲鱼号,顾名思义就是淘宝号,一个人可以注册3个。做这个项目,不光要有闲鱼号,还要有高权重的闲鱼号,就是支付宝的芝麻分数最好在650以上,如果您没达到也没关系,芝麻分数可以通过按时还款、支付宝缴纳物业水电费和租借充电宝等守信行为去涨分。 下面是支付宝芝麻信用分数一览表,分数越高,曝光量越大,分数等级划分如下: 700-950就表示信用极好 650-700就表示信用优秀 600-650就表示信用良好 550-600就表示信用中等 350-550就是信用较差的 2、如何找到优质的货源? 刚开始可以从淘宝联盟、阿里巴巴等一系列的资源找到自己的货源,如果自己本身有货源,在操作上无疑是锦上添花。 3、如何起一个“爆单”标题,好的标题就是成功的一半。 首先确定您要发布的商品,在闲鱼的搜索框输入商品名称或者关键词,输入时下面会出现一个下拉框,可以参考下拉框的词汇,这些都是闲鱼用户搜索的热词、高频词,可以作为组成标题的一部分! 除此之外,还可以搜索一些排名靠前的同行的标题作为参考,不建议照搬,照搬的流量相对会少很多,反之,原创标题和内容具有一定的权重。 4、详情内容该怎么写、图片怎么编辑标签? 详情内容的大致描…

    2021年6月11日
    15
  • vivoX80Pro和华为P50Pro哪个好?值得买吗?

    vivoX80Pro和华为P50Pro相比较,该如何选? 原创2022-05-01 22:55·大头熊sir vivo X80Pro的优势更多,毕竟作为一款刚发布的手机,各项技术都是最新的: 1、采用了天玑9000芯片,性能上比骁龙888好了一截,而且天玑9000的口碑确实好一些。 2、采用了三星E5的2K分辨率屏幕,还有3.0版本的LTPO自适应刷新率屏幕,峰值亮度、分辨率、屏幕色准以及色彩表现方面,全方位优于华为P50Pro这块屏幕。 3、拍照上,主摄为超大底三星GNV镜头,硬件素质碾压华为的IMX766,在超广角和人像镜头上硬件素质也更好。再加上自研芯片V1+软件加持,整体液晶表现可以和华为碰一碰了。 4、前置为3200万像素。 5、多了大面积超声波指纹解锁,区域更大、速度更快。识别更准确,体验更好得多。 6、快充速度更快,多了vivo家的HIFI。 而华为P50Pro的优势主要有:1、6400万的潜望式长焦镜头素质好得多;2、多了一颗原色镜头。 看看详细参数额皮质对比: vivo X80Pro,综合影像旗舰一是屏幕素质一流。三星2K E5超感自由屏,2K超清分辨率、120Hz屏幕刷新率、1000Hz瞬时触控采样率、LTPO自由帧率3.0。低至0.45的∆E数值,色彩表现更好。二是相机配置整体高端主流水平。超大底主摄+高素质超广角+人像镜头+潜望式镜头,焦段覆盖齐全,再加上V1芯片辅助夜景拍照(主摄、超广角和前置都有这个功能)表现非常强,硬件素质上虽然不如小米11ultra这种影像旗舰,但是软件调教算法确实是一流水准。三是4700毫安+80W有线+50W无线,主流水平,比不上百瓦快充,但也够用。四是外围配置非常全。大体积X轴线性马达,对称式立体双扬、红外、NFC、Hi-Fi 等配置,并支持IP68级防水防尘功能。 缺点:价格确实高。 建议:目前唯一一台天玑9000的全面综合旗舰,碾压目前各家的天玑9000手机。 华为P50pro详解 低内存版本是4G骁龙888,中高配是麒麟9000和骁龙888两个版本 整体拍照能力目前dxo榜一,主要相较于p50增加了一颗4000万黑白镜头,暗光拍照更强,三个主摄规格很高,光学防抖、潜望式长焦都配齐了,还改进了瀑布屏,和双挖孔屏幕。 鸿蒙os和华为品牌加持,目前国产最高端旗舰,也只有华为能做出这种大众认可的高端质感。 缺点,全…

    2022年5月2日
    49