counterxing

Results 60 issues of counterxing

在上一篇文章[Service Worker学习与实践(二)——PWA简介](https://github.com/xingbofeng/xingbofeng.github.io/issues/38)中,已经讲到`PWA`的起源,优势与劣势,并通过一个简单的例子说明了如何在桌面端和移动端将一个`PWA`安装到桌面上,这篇文章,将通过一个例子阐述如何使用`Service Worker`的消息推送功能,并配合`PWA`技术,带来原生应用般的消息推送体验。 ## Notification 说到底,`PWA`的消息推送也是服务端推送的一种,常见的服务端推送方法,例如广泛使用的轮询、长轮询、`Web Socket`等,说到底,都是客户端与服务端之间的通信,在`Service Worker`中,客户端接收到通知,是基于[Notification](https://developer.mozilla.org/zh-CN/docs/Web/API/notification)来进行推送的。 那么,我们来看一下,如何直接使用`Notification`来发送一条推送呢?下面是一段示例代码: ```javascript // 在主线程中使用 let notification = new Notification('您有新消息', { body: 'Hello Service Worker', icon: './images/logo/logo152.png', }); notification.onclick = function() { console.log('点击了');...

JavaScript

## 什么是`Service Worker` `Service Worker`本质上充当Web应用程序与浏览器之间的代理服务器,也可以在网络可用时作为浏览器和网络间的代理。它们旨在(除其他之外)使得能够创建有效的离线体验,拦截网络请求并基于网络是否可用以及更新的资源是否驻留在服务器上来采取适当的动作。他们还允许访问推送通知和后台同步`API`。 * `Service Worker`的本质是一个`Web Worker`,它独立于`JavaScript`主线程,因此它不能直接访问`DOM`,也不能直接访问`window`对象,但是,`Service Worker`可以访问`navigator`对象,也可以通过消息传递的方式([postMessage](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage))与`JavaScript`主线程进行通信。 * `Service Worker`是一个网络代理,它可以控制`Web`页面的所有网络请求。 * `Service Worker`具有自身的生命周期,使用好`Service Worker`的关键是灵活控制其生命周期。 ## `Service Worker`的作用 * 用于浏览器缓存 * 实现离线`Web APP` * 消息推送 ## `Service Worker`兼容性...

JavaScript

之前阅读过一篇文章[《Async/Await替代Promise的6个理由》](https://blog.fundebug.com/2017/04/04/nodejs-async-await/),现在[async / await](https://tc39.github.io/ecma262/#sec-ecmascript-language-functions-and-classes)语法已经处于**Stage3阶段**。 ## 兼容性 * 服务端方面,在`Node.js 7.6`版本后,`async / await`语法已经被`Node.js`支持,如`Koa2`已经抛弃[generator/yield语法](https://tc39.github.io/ecma262/#sec-generator-function-definitions),拥抱`async / await`语法。 * 客户端方面,也可以通过`Babel`让我们随心所欲地使用最新的`Ecmascript`语法。 ## 从业务说起 单从我个人来讲,是不太喜欢使用这样的最新语法的。一直以来写代码还是拥抱`Promise`为主。但自从用上了`async / await`语法后好像就会对这种语法产生依赖感(看起来就像是同步阻塞的代码一样,还不用像`generator`语法那样手动释放,或使用`co`那样的流程控制库) **看下面这些常见的业务场景:** 1. 假设我们在编写一个刷题的程序,这个程序是智能的(对,它懂你),你每次做完一道题并提交,服务端会根据你提交的结果来判断你有没有掌握当前知识点,如果没有掌握,服务端会再次给你推送下一道题。 2. 假设我们在编写一个用户手动对图像进行鉴别的软件,服务端给了两个接口,**接口submit**用于提交上一张图像的鉴别结果,只有当**接口submit**提交成功,才能去请求**接口next**,用于请求下一张图片的链接。 ```javascript const requestSubmit = () =>...

JavaScript

服务端推送是现今`Web`开发过程中最常见的需求。例如: * 即时聊天工具 * H5网络游戏 * 消息通知 一般的服务器推送包括: * 最简单的是客户端轮询的方式,在客户端创建一个定时器,每隔一定的时间去请求服务端,每次请求检查状态变化以判断服务端是否有新数据更新。 * 基于 AJAX 的长轮询(`long-polling`)方式,服务器在一段时间后再返回信息; * `HTTP Streaming`,通过`iframe`和``标签完成数据的传输; * `TCP`长连接/`WebSocket`,可以实现服务器主动发送数据至网页端,它和`HTTP`一样,是一个基于`HTTP`的应用层协议,跑的是`TCP`,所以本质上还是个长连接,双向通信,意味着服务器端和客户端可以同时发送并响应请求,而不再像`HTTP`的请求和响应 * `SSE: Server-Sent Events`,这是通过`http`协议变通实现的,通过服务端向客户端声明,接下来是要发送的是流信息,本质上就是完成一次耗时长的下载。

JavaScript
编程/思考
Node.js

对`JavaScript`程序员来说,`Node.js`确实是我们作为服务端开发的首选语言。`Node.js`的性能优势源于其使用`Google`的`V8引擎`,使用非阻塞式的`I / O模型`,依靠事件驱动。但涉及密集型计算的场景时,`Node.js`不一定能够有很优秀的表现。还好有[C++ Addons](https://nodejs.org/dist/latest-v10.x/docs/api/addons.html)的机制,能够使得我们编写原生的`C++`模块,并且能够在`Node.js`中调用它。 ## 为何要使用`C++`模块 * `C++`社区庞大,我想在我们现成的`Node.js`应用中使用某个`C++`模块。 * 密集型计算场景,并且对性能有极大要求。 ### 举个例子:`Fabonacci` 斐波那契数列通常解法是以递归地方式来完成,在这里,为了体现`Node.js`中调用`C++`模块的优势,我们并不在`Fabonacci`中使用缓存的机制。 在`Node.js`中,根据`Fabonacci`定义,我们编写了如下代码,`fabonacci.js`: ```javascript // fabonacci.js function fabonacciNodeJS(n) { if (n === 0) { return 0; } if (n...

JavaScript
Node.js

```javascript /** * Create by https://github.com/xingbofeng at 2018-04-27 * 支持自定义事件顺序的eventHub */ class EventHub { constructor() { this.listeners = {}; } /** * _isValidListener:判断listener事件监听器是否合法 * @param {Function} listener 事件监听器 * @return...

JavaScript

问题:不用`Vuex`怎么让兄弟组件便捷通信?甚至让业务组件和内部组件通信? 答案:使用`eventHub` 如果不使用`EventHub`,我们想让父组件的两个子组件,甚至两个孙子组件之间进行通信,怎么办? ### 方案一:`Vue`自带的原生的`emit`和`on`的观察者模式 此处`demo`可见[官方文档](https://cn.vuejs.org/v2/guide/components.html#%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BA%8B%E4%BB%B6%E7%9A%84%E8%A1%A8%E5%8D%95%E8%BE%93%E5%85%A5%E7%BB%84%E4%BB%B6) > 弊端:必须经过父组件,并且必须为此给父组件增加一个状态。如果组件层级过深,不可维护! ### 方案二:自己实现一个`broadcast`和`dispatch` 虽然`broadcast`和`dispatch`方法已经被`Vue`官方所废弃,但是我们仍然可以自己实现一个`broadcast`和`dispatch`方法。原理是`componentName`参数传递需要被通知的组件,然后在组件树中用递归的方式找到正确的组件名称,之后通过`apply`调用对应组件的`$emit`方法: ```javascript function broadcast(componentName, eventName, params) { this.$children.forEach(child => { const name = child.$options.name; if (name === componentName) { child.$emit.apply(child,...

JavaScript
Vue

`select`、`poll`、`epoll`都是`I / O`复用的机制,在`《UNIX网络编程》`里重点讲了`select`、`poll`的机制,但`select`、`poll`并不是现代高性能服务器的最佳选择。包括现在的`Node.js`中的`事件循环机制(event loop)`也是基于`epoll`实现的。 ## select和poll的缺点 按照`《UNIX网络编程》`中所述,`poll`与`select`类似,没有解决以下的问题: * 每次调用`select`,都需要把`fd`集合从用户态拷贝到内核态,这个开销在`fd`很多时会很大 * 同时每次调用`select`都需要在内核遍历传递进来的所有`fd`,这个开销在`fd`很多时也很大 * `select`支持的文件描述符数量太小了,默认是`1024` ## epoll对于上述缺点的改进 `epoll`既然是对`select`和`poll`的改进,就应该能避免上述的三个缺点。那`epoll`都是怎么解决的呢?在此之前,我们先看一下`epoll`和`select`和`poll`的调用接口上的不同,`select`和`poll`都只提供了一个函数——`select`或者`poll`函数。而`epoll`提供了三个函数,`epoll_create`,`epoll_ctl`和`epoll_wait`,`epoll_create`是创建一个`epoll`句柄;`epoll_ctl`是注册要监听的事件类型;`epoll_wait`则是等待事件的产生。   对于第一个缺点,`epoll`的解决方案在`epoll_ctl`函数中。每次注册新的事件到`epoll`句柄中时(在`epoll_ctl`中指定`EPOLL_CTL_ADD`),会把所有的`fd`拷贝进内核,而不是在`epoll_wait`的时候重复拷贝。`epoll`保证了每个`fd`在整个过程中只会拷贝一次。   对于第二个缺点,`epoll`的解决方案不像`select`或`poll`一样每次都把`current`轮流加入`fd`对应的设备等待队列中,而只在`epoll_ctl`时把`current`挂一遍(这一遍必不可少)并为每个`fd`指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。`epoll_wait`的工作实际上就是在这个就绪链表中查看有没有就绪的`fd`(利用`schedule_timeout()`实现睡一会,判断一会的效果,和`select`实现中的第7步是类似的)。   对于第三个缺点,`epoll`没有这个限制,它所支持的`FD`上限是最大可以打开文件的数目,这个数字一般远大于`2048`,举个例子,在`1GB`内存的机器上大约是`10万`左右,一般来说这个数目和系统内存关系很大。 ## epoll接口 epoll操作过程需要三个接口,分别如下: ```c #include int epoll_create(int size); int epoll_ctl(int epfd,...

Node.js
后台开发
读书笔记

`fs`提供文件`I/O`,是标准`POSIX`函数的简单封装,提供文件和目录相关操作,所有的方法都有异步和同步的形式。对于异步方法,其返回的实例也继承自`EventEmitter`,可以组合回调和`EventEmmiter`的方法结合使用。 ## 读取文件 ### 同步读取 ```javascript const fs = require('fs'); // 直接同步读取文件的方式 try { const data = fs.readFileSync(__dirname + '/hello.txt', 'utf-8'); console.log(data); } catch(err) { console.error('readFileSync error: ' + err.message);...

JavaScript
Node.js

一般情况下`Node.js`使用`zlib`模块的使用`gzip()`压缩,但有一个坏处是,大文件会使`V8`缓冲区爆掉,原因是由于`gzip()`使用缓存,而`V8`的缓存区最大不超过`0x3FFFFFFF`字节(约为1GB),一般不使用缓存的方式压缩与解压缩数据,而使用`Stream`,原因可见[Coding with Streams](https://github.com/xingbofeng/Node.js-Design-Patterns-Second-Edition/blob/master/Chapter5-Coding%20with%20Streams.md): ```javascript const zlib = require('zlib'); const fs = require('fs'); fs.readFile(__dirname + '/hello.txt', 'utf-8', (readFileErr, readFileData) => { if (readFileErr) { return console.error('readFileErr error:' + readFileErr.message); } zlib.gzip(readFileData,...

JavaScript
Node.js