
半程马拉松两小时二十分 18 秒。继续努力加油(ง•̀_•́)ง
半程马拉松两小时二十分 18 秒。继续努力加油(ง•̀_•́)ง
疫情三年,家里也发生了好多变化,尤其是今年,医院进进出出,见过了更多悲欢离合。
什么最重要,对我来说肯定不是某个项目某个发明,现在那些成败其实无足轻重。再看某些人耿耿于怀或者执着的事情,也会感觉好笑不过如此。
年底了,希望明年有些向好的变化吧,祝福自己。
#top 数字技术让没有银行账户的人拥有了账户 | 盖茨笔记
“我对今年Findex报告中记录的巨大进步感到兴奋。世界各地拥有和使用银行账户的人比以往任何时候都要多,其中包括更多的女性和低收入人群。尽管很多人仍然被排除在外,但我们有了一个可行的路线图,并且不需要额外投入数十亿美元的资金来建立为他们提供服务的系统。遵循该路线图图,我们可以帮助他们摆脱贫困,让世界变得更公平。”
#AI 一些Disco Diffusion的资料,来自和菜头
#特斯拉 当公司来了特斯拉人
这位曾在特斯拉多年的新同事不仅在入职第一天便摸清了公司的组织架构、制度与流程,而且在迅速进入工作状态后,表现出强大的控场能力,“她在找到项目对接人之后便马上开始把控流程”。
随着时间的推进,Elsa还凭借一己之力逐渐影响团队原本软绵绵的氛围。具体表现是,在给领导或同事发邮件时,直切正题,不会加任何多余的话;原本冗长看似花哨的PPT也被“内卷”为轻易不超过10页;开会遇到更重要的工作,则会直接退出会议。
#Lottie Lottie动画gallery
#安卓 Jetpack Compose 到底优秀在哪里?| 开发者说·DTalk
#diagram 我以前推荐过这个网站,重新refresh一下,每次我画架构图都上这里找形状相似的然后改吧改吧 https://real-world-plantuml.com/
#架构 秒杀系统如何设计?
#阿里 阿里换个活法
最近碰到这样一个问题,JavaScript可以通过Promise.resolve()来转化一个值或者thenable对象成为一个Promise。
Promise可以通过then串联起来(chain),then的函数中,可以直接return val,也可以return Promise.resolve(val),那么这两种方式有什么区别么?
我听到的回答是没什么不同,但是我理解不深,所以打算自己研究一下。构造以下代码例子,猜猜运行结果是什么呢?
Promise.resolve(1)
.then(v => Promise.resolve(v + 1))
.then(v => Promise.resolve(v + 3))
.then(v => console.log(`First: ${v}`));
Promise.resolve(1)
.then(v => v + 1)
.then(v => Promise.resolve(v + 5))
.then(v => console.log(`Second: ${v}`));
Promise.resolve(1)
.then(v => v + 1)
.then(v => v + 7)
.then(v => console.log(`Third: ${v}`));
根据我对并发asynchronous的理解,如果这两种形式一样的话,结果有可能是顺序的First,Second,Third。也有可能是乱序的,First Second Third顺序不一定,在浏览器运行有可能因为某种原因,一直出现同样的结果,所以我们分别试试Chrome和Safari的操作台。但是结果很一致,哪怕在本地node直接跑nodejs也是一样。
结论是什么呢?return Promise.resolve(val)和return val这两种方式在结果上是一样的,对于不关注运行顺序的代码来说效果也是一样的。但对于开发人员来说,需要知道这两种方式的运行时间点是不同的,这个不同在某些复杂情况下需要考虑到。简单的说,如果不是故意要延迟结果的产生返回,return val这种方式既简单又快捷,用它就好了。
BTW。
参考这篇SO回答https://stackoverflow.com/questions/58217603/what-is-the-difference-between-returned-promise 以及这一篇https://dev.to/deepal/promises-next-ticks-and-immediates-nodejs-event-loop-part-3-2f57 可以知道Promise.resolve是一种微任务。
我大概能理解开发人员对于这些名词的怨念,微任务(microtask)又是什么?参考MDN这篇文章https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide 大概就是如下图所示。一个task完成以后,开始查询微任务队列microtask queue然后运行,接着运行下一个任务或者开始render。
这些内容有些高阶了,但对于JavaScript框架作者来说是必须的,想写框架的,可以参考这一篇https://blog.risingstack.com/writing-a-javascript-framework-execution-timing-beyond-settimeout/
(Updated)开发者自己做了一个事后分析,比我讲的清晰多了,当然主要原因还是JS module依赖设计的复杂度https://medium.com/javascript-in-plain-english/is-promise-post-mortem-cab807f18dcc 在这一点上我很看好deno这个新工具。
——————————-
看到微信群里有人转关于“is-promise”更新导致的问题,公众号文章说的非常夸张,但又语焉不详,看了毫无头绪。于是看了些英文文章,做了点技术分析。
首先声明,因为水平不够理解不深,这篇文章并没有解释清楚问题的原因,只是说了一下我看到的现象,确保将来写类似代码的时候,心里有点谱。
“is-promise“有问题的版本更新是2.2.0,看了更新diff没发现什么明显问题。更新的目的主要是增加ES module风格的默认import。
首先得熟悉一下ES Module的import,还有commonjs的require。
先说一下ES6标准化的module,在浏览器中可以通过<script type=”module”>导入模块脚本,代码是这样的:”import xxx from ‘module-name'”。如果用CommonJS呢,就是“const package = require(‘module-name’)”。
在Nodejs v12之前使用的是commonjs,在v12的时候引入了ES Module的支持。在node中可以通过条件导入同时支持两种方式(麻烦!)https://nodejs.org/dist/latest-v12.x/docs/api/esm.html#esm_conditional_exports
在nodejs的官方文档中https://nodejs.org/dist/latest-v12.x/docs/api/esm.html#esm_dual_commonjs_es_module_packages 特意解释了双模式package的问题,其中特意提到了“Dual Package Hazard”(双Package风险),说实话这部分有些复杂,我也没有太理解。在后面提到了“Differences Between ES Modules and CommonJS“,其中第一条就是”Mandatory file extensions“,但是文档说的还是不清不楚的。
我们看一下is-promise的bug fix能理解更深一些。https://github.com/then/is-promise/commit/0b69f52ee73c9f6ad4480f02c9bccb14d2038656 可以看到主要就是对文件路径指定,变成使用”./xxx.js”方式。为什么原来有问题,现在就能fix,说实话我还是没看懂。我在本地做了一个极为简单的node js脚本文件,引入了is-promise 2.2.0版本,尝试了import和require两种方式,没发现有问题。我也尝试从bug report中找点线索,但是大多数都是说xxx有问题了,没有细节。我甚至到create-react-app中查找is-promise,根本就没有,简直是磕了。
先这样吧,等我理解更多了再更新此文。
另外在HN上关于这件事的讨论https://news.ycombinator.com/item?id=22979245 也是非常热烈,不过没人分析原因,要么吐槽,要么建议用npm指定版本方式(版本号不用^和~)。
简单的说结论:可以这么说。但我不能确定它是百分百等同,因为标准没有这么说。
根据这篇文章https://mathiasbynens.be/notes/async-stack-traces Mathisas提到的,以及MDN上面的这一篇https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await 当我们使用await的时候,JS Engine会block当前运行代码,然后启动新的Promise(task)运行,等待它的结束或者异常抛出。
这个部分我可能还要看一下emcascript的spec,确定真的理解了。但是很明显这与C#是截然不同的,差别就在于JS Engine是单线程的,而C#中会自动启动一个新的Task来做事情,当前的主Task和新启动Task是并行运行的。
在async文档中有slow async和fast async的例子,便于更深入的理解https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
那到底是用async/await还是promise?我的建议是,能用async/await的尽量用,也尽量不要和promise混用(我见过这么干的)。更细节上的判断可以参考MDN https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach
另外需要注意的一点是,如果await多个promise,那么await和Promise.all在时序上和错误处理上是有所不同的。知道了这一点,trouble shooting的时候可以更仔细的研究细节。在这里Google Chrome团队就写了一篇很实用的文章,里面提到了如何对应转换promise代码成为async/await代码 https://developers.google.com/web/fundamentals/primers/async-functions
先理解到这层面吧,如果有更深入了解再更新。
继续看mdn的文档,今天看regexp部分。我想到一个小功能,把字符串中每个首字母大写。我看到的代码使用了split加上reduce,我呢,对于reduce总有些疑虑,因为它不直观,需要想一想才能把流程在脑子里理清楚。这样的功能用正则表达式正好,虽然正则也不容易理解,但是这貌似就是正则能打的领域,不用都可惜了。
看了一会文档,拼凑出一个代码来,在chrome devtool跑了一下是期望的结果。
function replacer(match, p1, p2, p3, offset, string) {
console.log(arguments);
const x = match.charAt(0).toLowerCase();
return x + match.substring(1);
}
let re = /(\w+)/g;
let str = 'john smith haha';
let newstr = str.replace(re, replacer);
console.log(newstr);
其实我并不是从string的replace函数看起的,而是看到了一个奇怪的用法。https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/@@replace 我在怎么写replacer一开始没搞懂,因为没有例子。甚至跑到这里看测试用例https://github.com/tc39/test262/tree/master/test/built-ins/RegExp/prototype/Symbol.replace 后来看ecmascript的文档才发现提到了string.replace,这才把知识点串联起来。
var re = /-/g;
var replacer = function() {
console.log(arguments);
return '.';
};
var newstr = re[Symbol.replace]('2016-01-01', replacer);
今天少写一点,就这些吧。