成就达成:伟大的脱逃
有些问题,譬如宇宙中是否还有其他智慧生命,或者我们人类的最终结局如何,它们像黑洞一样,一旦开始思考就很难从中挣脱。不管你是深陷贫穷的痛苦,还是容貌的焦虑,甚至只是陷入青春期回忆的尴尬中,当面对浩瀚的宇宙时,都只会让你觉得渺小。
缺氧就是这样的一款游戏,在旧日的家园分崩离析后,你的三个复制人将要踏上前往陌生的小行星的旅程,并艰难求生。
展开 >>有些问题,譬如宇宙中是否还有其他智慧生命,或者我们人类的最终结局如何,它们像黑洞一样,一旦开始思考就很难从中挣脱。不管你是深陷贫穷的痛苦,还是容貌的焦虑,甚至只是陷入青春期回忆的尴尬中,当面对浩瀚的宇宙时,都只会让你觉得渺小。
缺氧就是这样的一款游戏,在旧日的家园分崩离析后,你的三个复制人将要踏上前往陌生的小行星的旅程,并艰难求生。
展开 >>最近换了手机号码,我的整蛊之魂蠢蠢欲动,让我发现了这个好玩的软件——MorphVOX,听说各大主播都在用,某宝搜索更是有一大堆“远程调音服务”。
但这个软件对Mac的支持不算好,如果用Windows的话,体验应该会更好。
首先,这是一个收费软件,但如果只是为了整蛊的话已经够了,它有一天的免费试用,通过简中官网下载软件后安装,接着打开软件会弹出联网激活的对话框,什么也不用管点下一步即可进入试用。
第一次运行时,软件会自动运行MorphVOX Doctor,“傻瓜式”地帮你配置该配置的。不过就像之前说过的,这个软件对Mac的支持并不太好,所以这个可能是个“真·傻瓜式”,下面是我在使用时遇到的问题和应对的解决方案:
Q: 第一次安装之后,它自动运行MoprphVOX Doctor(帮助程序)成功后,在MorphVOX里面不能听到声音。
这个问题有很多可能性,比如:
展开 >>3月份因为眼伤辞职的我,在养病期间断断续续地搞了些乱七八糟的东西,却在接近一年的结尾,又感受到时间的荒芜。一周的失眠和一周的嗜睡轮回,让我几近崩溃。
一年中数次奔往派出所、医院和法院,相关的证明开出一大堆,同时也有了生命里第一次打官司的经历,体验到人生不一样的酸甜苦辣。随着案情逐渐明朗,病痛的痕迹也在一天天地被身体修复,有一天睁眼,心底猛然萌生去海边的念头,去感受沙滩、骄阳和海风。
虽然不再是teens了,也过了那种对新事物有强烈的enthusiasm的年纪,不过还是想苦苦挣扎地抓着青春的尾巴。
展开 >>M1芯片出了大半年,甚至登陆了新款iPad Pro,虽然我们仍无法直接在M1上安装Windows。但Parallels Desktop早就用虚拟机方案解决了此问题,而且体验还非常好,但是它收费,所以…
这篇文章主要介绍的是基于UTM的Windows安装过程,UTM老早就登陆了iPhone/iPad的应用商店了,所以理论上来说,使用M1芯片的iPad也可以使用这个APP安装Windows。
如果这个链接错误,打开 https://mac.getutm.app/support/ 拖动到最底部下载
酸胀 放大 易碎的边缘我在爬行
沉默 敲打 贮存逐渐升温的失控
在此刻 我是一个没有时钟的旅客
在此刻 宇宙背景辐射的声波嘈杂
达维安骑士的冷漠 盔甲卸下
迈向高原的泪水 在欢声作响
我看你 就像是 你看我
根号三与根号三的融合
暴雨撞击 猛兽迎起
婆娑的耳语 暴露在世界的直播里
万般愤怒落下 水池泛起涟漪
化成花园的爱意 园丁的甜蜜
我在 我在 我在 你高悬的太阳下
我在 我在 我在 你刺眼的赤道中
我在 我在 我在 你咸湿的季风上
我在 我在 我在 你忧郁的洋流里
一泻千里 肿胀还有它的意识
在这里 在那里 小说里 漫画里
音乐里 电影里 游戏里 幻想里
有它的痕迹 可恶的痕迹
和我酩酊大醉 我有我的酒和杯
和你大汗淋漓 每个时刻从零到一
和我乘风破浪 想你 和我在一起
如果你和我一样,刚开始编程的时候学习的并非Javascript,而是类似于Java / C# / C++这些类似的语言。那么你在初写js(或泛前端应用)的时候,应该会和我遇到相似的疑问。那就是,我期望的代码执行顺序为什么和实际上的代码执行顺序不相同呢?
1 | // Javascript |
我们知道,程序在读文件的时候是一行一行的读取的。(别问为啥,你也可以写个解释器先读取2n行,再读2n-1行)
然而js中的表现却和我们的预期不一致,做个对比,我们拿Python重复一遍上述的逻辑。
1 | # Python |
Python的逻辑符合我们的“直觉”,即代码总是按照码农给定的顺序执行。
但为啥就你js搞特殊?因为早期的js主要运行在浏览器,负责的工作则是对用户的输入(鼠标点击、移动、悬浮或键盘事件)进行反馈。注定了其代码不能是同步执行的,而是监听式的,即代码块在等待一个时机被执行,而这个执行时机程序员大概率是无法预知的。
虽然一个异步程序的执行时机无法预知,但我们可以使用回调提前对数据进行处理。例如:
1 | function doSomethingFeature (callback) { |
我们用回调函数来处理一个个事件,于是代码中的括号也越来越多。
- 鲁迅
想象一下:网页中的一个弹窗,它有一个按钮,在这个按钮被按下时,浏览器开始向远程服务器获取数据,当数据到达后,网页中的标题变了。由于每一次发生的事件都要依赖于上一次事件(因为不触发事件就无法获取数据), 用回调函数进行数据处理就会变成:
1 | openCustomWindow(()=>{ |
这样的代码,不仅难以阅读,而且维护时多一个括号少一个括号的也很容易让人心态崩溃,只能用用编辑器的智能提示勉强混混这样子。
那如果有一种写法,可以让被依赖的数据像自来水管流动一样就好了。按照顺序地从自然水源中经由水厂消毒,在流向小区供水中心,再流向你家的净水器,最后从水龙头流入你的杯子里。
把上面的列子用链式调用的方案改写一下,就得到一个类似于下面的东西:
1 | // js伪代码:理想状态的链式调用模式 |
2003年JQuery横空出世,当时的JQuery就采用了这种做法,从而大大地提高了前端代码的可读性,加之提供完整的类库功能和简单的学习曲线,使得JQuery成为了几乎“人手必会”的前端类库。而受到JQuery的启发地ES委员会,创造性地在Javascript中引入了Promise对象。
Promise字面意义上代表承诺,在现实生活中,一个承诺也会有履行完成的状态和未履行的状态。因此,Promise对象也可以处理程序成功和失败后的数据。一个典型的Promise写法如下:
1 |
|
Promise除了擅长链式调用以外,还可以搭配关键字await写出更易读的同步式代码。
1 |
|
如果你只是需要一个第三方包来实现APN服务的话,推荐直接使用现有的项目 node-apn
确保你是 Apple Developer 会员
点这里生成一个 *.p8 格式的私钥,仅能下载一次,注意妥善保存。(由于我使用的是Token-Based的认证方式,所以需要此格式。*.p12格式的证书不适用于本文的内容)
获取APNsAuthKeyId(Key ID):下好的 *.p8文件中就包含有Key ID。如’AuthKey_AXN12P9G17.p8’,那么’AXN12P9G17’就是Key ID。
获取AppleDeveloperId(Team Id): 进此页查看
获取BundleId: 注册App Id时填写的名称,一般其格式为 ‘com.app-name.app’
获取deviceToken
deviceToken相当于用户手机的id, 用户在下载App启动后就可以获取deviceToken。开发者可以在Xcode中拿到自己手机的deviceToken。
参见:
基于node v12.19.0版本
1 | // typescript |
在生成签名后,作者尝试向苹果服务器发出请求,结果遇到了报错
1 | Parse Error: Expected HTTP/ |
作者一度怀疑是node版本的问题(甚至还升级了版本 XD)。然而待作者仔细阅读Apple的文档后发现,原来是APNs只支持http/2的协议,难怪一直跑不通呢!这里也非常佩服苹果,总是投入资源来推动新技术的普及。
不过问题找到了,其实也会很容易解决
1 | // typescript |
1 | //typescript |
请求成功后,Apple会返回对应的状态码和reason。一般出现403状态都说明生成的签名错误,请检查你是否使用错了证书(本文中的签名方法仅针对 *.p8格式的私钥)
参考:Apple官方文档
APN服务对应的状态码:
status code | reason | 描述 |
---|---|---|
200 | / | 成功 |
400 | BadDeviceToken | DeviceToken无效,或者环境错了。 |
400 | BadTopic | apns-topic值无效 |
400 | DeviceTokenNotForTopic | DeviceToken和Topic不匹配 |
400 | MissingDeviceToken | 没有DeviceToken |
400 | MissingTopic | 请求头缺少apns-topic |
403 | BadCertificate | 证书无效 |
403 | BadCertificateEnvironment | 证书的环境不对 |
403 | ExpiredProviderToken | Token过期了 |
403 | MissingProviderToken | 没有提供客户端认证证书,也没有设置authorization |
413 | PayloadTooLarge | payload太大。(不得大于4 KB) |
429 | TooManyProviderTokenUpdates | Token更新太过频繁(小于20分钟) |
429 | TooManyRequests | 同时向同一台设备发送了过多请求 |
睁开眼,已经一片黑暗,四周仍然寂静,像极了《我是传奇》中的场景。
不点烟,也不小酌两口,就这样发着呆。片刻,脑袋中的混沌蒸发干净了,才开始穿衣。
“弄点吃的吧”
冰箱里剩下的冷冻水饺仍然可以将就一餐,在网络上义愤填膺过后,还是需要工业食品来果腹。
抽油烟机在轰鸣声中运作着,铁锅上升腾起一股蒸汽,吐向他不食人间烟火的脸。
“不知道··· 他们现在在干嘛?” 他望向厨房的窗户,外边漆黑一片,只有他自己被映照在那里面。
对有些人来说,回家当然是很重要的事情,所以当我告诉他我不回家的时候,他仿佛受到了很大的惊吓。
“你不回家,你家里人不会念叨吗?” 他说。
“当然会,但是我找不到一个好理由回去” 我回答道。
“这可是过年!” 他义正言辞地惊呼到。
“感觉回家都回腻了,我可能是一个不爱回家的男人。”
“哈哈哈···”,齐鹏和我都笑了起来。
大家肯定都知道,JavaScript其实和Java并没有什么关系,当时推出JS时,只是为了趁一下当时如日中天Java大哥的热度。JS中的语法和数据结构太简单了,以至于很长一段时间内,JS程序员都被称为脚本员。而被如此嘲讽的原因,是因为当时的JS不存在”类”的这个概念的,更不用说”模组”这种东西了。
在JS世界中,人们常说,函数是一等公民(first-class object),但为什么要这么说呢?
举个例子:
1 | > var a = 1 |
从上面的列子可以看出,
1 | > var b = new Number(1) |
当然,由于
JS的原生值类型包含以下几种
以上的值类型中,除开
再举个例子:
1 | > var a = {} |
上面的例子显示出,函数直接参与了对象的构建工作(constructor)。虽然JS并没有实际“类”的概念,但还是可以将之称为构造函数。
除了参与构建JS世界其他部分的工作外,函数自己也是这个世界的一部分。它无处不在,除了作为对象被引用,还经常作为参数被传递,偶尔还客串返回值。它的父类是Object,Object的父类是它。
1 | > Function.__proto__ |
讨论JS对象,绕不开的就是 _proto 和 prototype,除了 undefined 和 null__ 以外,JS中所有对象都含有 _proto__ 属性,那么这个属性是干嘛的?
让我们先写一个函数:
1 | function Person(name) { console.log(`I'm ${name}`) } |
单独执行它:
1 | > Person('EvinK') |
执行该函数时,输出了一句话,返回了一个 undefined
加上
1 | function Person(name) { |
发现了吗?new关键字调用函数时,该函数返回了一个以它自身为原型的对象。同时,在执行Person函数的过程中,将挂载于Person作用域下的属性,也一同挂载到生成对象上(函数闭包)。
现在,让我们看下person的属性
1 | Person {name: "EvinK"} |
除了挂载到身上的name属性外,person的_proto__属性暴露了它的原型 —— Person函数,而我们亦可以沿着 _proto 属性一直深究下去,会发现,对象person 的原型是 Person函数, 对象person 原型的原型是 Object函数,而再往后面就是null了,也就意味着这条 原型链_ 终止了。
总结一下,对象中的 _proto_属性指向的是自身原型的 prototype属性, 并且依靠条链接层层递进,直到找到最终原型函数Object。
tag:
缺失模块。
1、请确保node版本大于6.2
2、在博客根目录(注意不是yilia根目录)执行以下命令:
npm i hexo-generator-json-content --save
3、在根目录_config.yml里添加配置:
jsonContent: meta: false pages: false posts: title: true date: true path: true text: false raw: false content: false slug: false updated: false comments: false link: false permalink: false excerpt: false categories: false tags: true