Giter VIP home page Giter VIP logo

blog's People

Watchers

 avatar

blog's Issues

Debounce & Throttle

Intro

Debounce and Throttle are two most used utilities when implementing UI interaction. They're both used to handle frequent UI events so that resources (network, memory, etc) are optimized and users are satisfied.

Debounce

  • enforces that a function not be called again until a certain amount of time has passed without it being called. As in "execute this function only if 100 milliseconds have passed without it being called."
  • we want to have a reference of every previous call, and if it was ongoing, we can cancel it and reset the timeout
const debounce = (cb, timeout) => {
  let timeoutCall;

  return (...args) => {
    clearTimeout(timeoutCall);

    timeoutCall = setTimeout(() => {
      cb(...args);
    }, timeout);
  }
};

Throttle

  • enforces a maximum number of times a function can be called over time. As in "execute this function at most once every 100 milliseconds."

开个头

看了amandakelake的blog发现medium已经落伍了... 还是在github上写起来方便 我要的功能全有还能评论...
最近准备Google面试要整理这三年来做React Native跟前端开发的经验, 所以顺便就都写下来吧... 暂时以"总结给自己看"为目的, 面完试之后有空再写写有用的东西吧
主要就是把自己在Bear里总结的东西搬运一下然后总结一下... 为了面试还建了个repo放刷题总结... 就先private了
本人中文太差, 技术的东西还是英文写起来方便

React Native 指纹验证

Intro

工作几年了有很多经验跟caveat虽然自己理解了, 但是觉得也可以在网上分享一下, 因为很多时候一个功能不会实现我就得Google这儿Google那儿, 为了有个更全面的理解还会经常去国内的各种论坛博客上做research. 更况且从经验上来看React Native更多是被用来做业余爱好的项目而没有很多公开的, 关于用RN做企业级App的心得, 所以决定从这个指纹加密系统的tutorial开始写一些文章.

想先说一下为什么要讲指纹加密… 一般在对用户进行身份验证的时候, 生物验证 (Biometric Authentication, 并不知道准确中文是什么) 的方法大概分为两类, 一种是用指纹去验证用户是否可以访问数据, 一般这类的库或者函数都会返回一个boolean来说明用户是否有权限. 另一种是在验证的同时对某数据进行加密. 对应这两种方法, 一般的代码会是这样:

// 1. 指纹验证
authenticateWithBiometrcs()
	.then((authenticated) => {
	  if (authenticated) {
	    // 允许用户进行某种操作
	  } else {
      // 给出指纹(生物)验证错误的信息
    }
	})
  .catch(/* 处理报错 */);


// 2. 指纹加密
authenticateWithBiometrics(secretData)
  .then((encrypted) => /* 处理已加密的数据 */)
  .catch(/* 处理报错 */);

Security

一般情况下, 大部分的usecase用第一种方法就可以解决. 但是在搭建企业级应用的时候, 往往会有更复杂的身份验证系统. 大部分身份验证系统都会以authentication token的形式验证用户身份, 而往往光用第一种方法在JavaScript层进行处理会有很多安全隐患, 而使用第二种方法利用原生的API直接在封装好的函数内对数据进行加密则要安全得多. 具体的原因不是这个文章重点就不多说了, 有兴趣可以参考Best Practices of Implementing Touch ID in Financial Apps.

iOS

所以大部分时候在构建安全系数比较高的应用的时候, 就有必要寻找能同时对数据进行加密的指纹验证方法. iOS在这方面提供了非常便利的界面, 我们在实现这个功能的时候先研究了所有现有的RN的touchID的库, 但是并没有找到可以让指纹验证进行数据加密的库. 最后我们选定了一个iOS跟一个Android的原生库然后自己开发RN的bridge把原生的swift跟Java的模块桥接到JavaScript离去. 具体怎么实现把原生代码桥接到JavaScript, 我应该会在下一篇里写.
首先是找到了一个非常合适用来做iOS指纹验证的库: GitHub - kishikawakatsumi/KeychainAccess: Simple Swift wrapper for Keychain that works on iOS, watchOS, tvOS and macOS. 这个库本身的api就已经包括了使用指纹验证在iOS的keychain上进行操作的方法. 然后用RN的bridge可以非常简单地把每个方法都map到一个JavaScript方法上就行了.

Android

然后Android系统本身对于指纹验证的要求就比较复杂一些了. 因为Android本身就是一个原生系统外面包一层第三方的皮, 所以往往在提供api的consistency上有很大难度. 在指纹加密这一方面, Android采用了非常底层的加密/解密方法. 由于跟iOS在本身系统性质上的不同, 对于秘密的处理方式也很不一样. iOS的keychain可以直接读写任意字符串, 而Android (虽然也有keychain但是跟iOS还是不大一样) 如果需要在你的app所拥有的存储空间存下app专属的用户的秘密的话 (一般是密码或者token之类的), 就需要使用Keystore.
Keystore的好处在于存储的数据是被sandbox掉的, 也就是不能被除了你的app以外任何app接触, 并且秘密并不是直接存储在app上, 而是被一个在硬件上生成的密钥加密过之后返回给开发者. 所以一般人也把Keystore跟SharedPreference合在一起用, 用SharedPreference把加密过后的数据存起来.
这里我大概研究了十个库, 把每个的代码都翻了个底朝天. 大部分都多多少少有些edge case没有处理. 比如说给用户数据加密过后如果用户在手机上又加了一个新的指纹, 那之前的密钥就作废了, 大部分的库都不会处理这种情况, 但是Android底层的确是给出了很详细的说明让开发者对这种情况进行处理的. 然后还有很多的库不去查手机上是否已经enroll了指纹. 最后我锁定了Square的Whorlwind. 虽然用了一个我完全不懂的RxJava, 但是至少所有可以预见的错误都已经有了相应的处理. 唯一不足的是大家都没有做相应的UI, 因为Android上指纹验证系统是没有提供原生UI的, 所以这时候一般需要用RN bridge在Java上提供的Promise类或者EventEmitter把相应的UI事件传回到JavaScript上, 然后就可以自己做一个自定义的RN component来渲染UI啦.

Cryptography For Android Biometrics

在Android上加密的时候, 大部分人会选择用AES, 也就是对称的加密, 但是AES需要在生成密钥的时候也进行指纹验证. 在这里为了保证跟iOS的parity, 我们希望能够不用验证来生成密钥, 这时候可以使用RSA加密来保证可以直接使用一个Certificate来绕过加密时的验证. 这个方法可以在Whorlwind里找到相应的例子.

Conclusion

这篇文章其实是在一年前刚做完这个feature的时候写的, 用的很多reference也已经out-of-date了. 但是这可能是我工作这几年来做的最多research的一次了, 看遍了所有相关的Documentation, Github Repos, Stack Overflow, Blog, 甚至有很多这方面的research, 来保证安全性跟可行性. 而且因为要顾及到React Native的Cross-Platform的特性需要尽量把iOS跟Android的API做的一样, 并且符合当时的产品需求以及安全需求, 这些都带来了各方各面的restriction. 虽然磕磕碰碰最后做完了整个bridge, 但是在看遍了各种资料之后对整个RN的开源社区都挺失望... 不过至于对RN的总结, 之后再写了

Reference

作为Reference, 当时研究了所有的库:

Implementation of Redux

Intro

In Egghead.io's vid series about Redux, Dan Abramov had a brief walk-through of an over-simplified Redux store. And that's what I'll be using to demonstrate the core philosophy of Redux.
When I'm writing this, I'm basically "reverse-engineering" the redux store, based on the knowledge I obtained from day-to-day work that heavily involves the React-Redux stack.

createStore

The kernel (at least from my understanding) of Redux is the createStore function, which dictates the unidirectional data flow philosophy. By setting up event listeners and explicitly creating a new state on every action, redux is able to keep applications stateful and everything in sync.

The key principles of Redux mandates the store to follow certain rules to make sure the state is in-sync all the time. Based on that, Redux store needs to have the following functions defined: (not the exact API, just concepts)

  • getState always returns the current state tree of the application
  • subscribe allows attaching event/action-listeners to handle events/actions
    • In this implementation, it will also return a function to unsubscribe for convenience
  • dispatch triggers events (actions) for the store to handle

First, we know that createStore needs to create a store that is stateful, so we can just maintain state in memory.

const createStore = () => {
  let state = {};

  return {
    getState: () => state,
    subscribe: () => {},
    dispatch: () => {},
  }
}

Also, we know createStore takes a combined reducer, and every action dispatched will be used to invoke the reducer to create a new state. From usage of dispatch, we know that it takes an action, passes it to reducer, and allow reducer to create new state. Assuming there are listeners subscribing to the store, we should also invoke all the listeners.

const createStore = (reducer) => {
  let state = {};
  const listeners = [];

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach((listener) => listener());
  };

  return {
    getState: () => state,
    subscribe: () => {},
    dispatch,
  };
};

Last but not least, the subscribe method is crucial for the observable pattern to work. The listeners we use to subscribe to store usually have handlers to update UI, so that all actions triggered will lead to UI changes.

const createStore = (reducer) => {
  let state = {};
  const listeners = [];

  const dispatch = (action) => {
    state = reducer(state, action);
    listeners.forEach((listener) => listener());
  };

  const subscribe = (listener) => {
    listeners.push(listener);
    return () => {
      // this is to make sure we have a way to unsubscribe 
      listeners = listeners.filter(exisitingListener => existingListener !== listener);
    };
  };

  return {
    getState: () => state,
    subscribe: () => {},
    dispatch,
  };
};

Communication Between Browser Tabs

  1. WebSocket
    pros: real-time update
    cons: requires specific architecture
  2. SharedWorker
    pros: allows an event emitter interface across tabs
    cons: local, might lead to edge cases between tab comms and client-server comms
  3. Local Storage
    pros: easy to implement (by adding event listeners on local storage changes)
    cons: error-prone and non-idiomatic

Cookie, Session Storage, and Local Storage

Cookies are small pieces of data stored in the browser used to remember state of web applications (and usually encrypted or encoded).
Session storage and local storage are similar but used for different purposes.

h2. Transfer
Cookies are sent over the network between client and server.
Data in Session Storage and Local Storage are kept in the browser all the time.

h2. Storage Size
Cookies are less than 4kb.
Session Storage and Local Storage can be much larger, and can be as big as 5Mb or more.

h2. Expiration
Cookies are valid before their expiration dates. And they can survive when a browser window closes.
Session Storage is cleared when the browser window closes. And they can survive over page reloads and restores.
Local Storage never gets cleared unless specifically instructed so. (no expiration, no auto-deletion)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.