不管用什么工具写,反正得用到手,所以这个标题似乎并没有什么不妥。
下面进入正题。

Promise是个用于异步执行的方法类,他的显著特点是支持链式调用,避免了之前异步执行嵌套回调那种写法的弊病,毕竟代码是给人看的,回调地狱的写法看起来就费劲。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

function MyPromise(callback) {
var self = this;
self.status = 'pending';
self.data = null;
self.onResolvedCbs = [];
self.onRejectedCbs = [];

try {
callback(resolve, reject);
} catch (err) {
reject(err);
}

function resolve(data) {
self.status = "fullfiled";
self.data = data;
self.onResolvedCbs.map((item) => {
item(self.data);
})
}


function reject(error) {
self.status = 'rejected';
self.data = error;
self.onRejectedCbs.map((item)=>{
item(self.data);
})
}
}


MyPromise.prototype.then = function (onResolve, onReject) {
const self = this;

const p = new MyPromise((resolve, reject)=>{

if (self.status === 'fulfilled') {
onResolve(self.data);
}

if (self.status === 'rejected') {
onResolve(self.data);
}

if (self.status === 'pending') {
self.onResolvedCallback.push(onResolve);
self.onRejectedCallback.push(onReject);
}

});

return p;
};


var p = new MyPromise((resolve, reject)=>{
setTimeout(()=>{
console.log('hi');
resolve('success');
},10);
})


p.then((data)=>{
console.log(data);
})

关于then链式调用的详细实现后面再说吧


实现一个 curry function

1
2
3
4
5
6
7
8
9
10
11
12
13
14

function curry(fn){
var len = fun.length;

return function exect(...args){
if(args.length>=len){
return fn.apply(null, args);
}

return function(...args2){
return exect.apply(null, args.concat(args2));
}
}
}

实现一个compose函数

1
2
3
4
5
6
7
8

function compose(...fn){
return fn.reduce(function(preFn, nextFn){
return function(...args){
return preFn(nextFn(...args))
}
})
}

模拟reduxcombineReducers
网上combineReducers的用处说是将多个reducer进行合并。我开始看到这里一想reducer不就是那些switch case之类的判断吗。那他所谓的合并莫不是叠加case?我当时就想那不干脆用字符拼接嘛,然后用eval执行?哈哈哈哈~我这直观的脑路啊!

combineReducers(state)里面的参数实际就是你全局的state的数据格式,他可以让你一个key对应一个reduce方法。他们所谓的好吧实际就是遍历这个state对象的所有的key,并且执行对应的reduce方法,以改变其value。那这就很简单了嘛!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function combineReducers(reduceObj={}){
var newState = {};
return function(state, action){
var keys = Object.keys(reduceObj);
var hashChange = false;

for(var i=0; i<keys.length; i++){
var key = keys[i];
var value = typeof reduceObj[key] === 'function' ? reduceObj[key](state[key], action) : reduceObj[key];

hashChange = hashChange || value!=state[key];

newState[key] = value;
}

return hashChange ? newState : state;
}
}

实现数组扁平化

1
2
3
4
5
6

function flatten(array){
return array.reduce(function(pre, next){
return pre.concat(Array.isArray(next) ? flatten(next) : next )
}, [])
}

js的instance of方法主要是判断一个对象是不是某个指定构造函数的实例,其判断的来源于该对象的__proto__属性是不是指定构造函数的原型,并且这种判断是可以顺着原型链往上追溯的,所以方法的实现核心就是判断构造函数的prototype跟实例的__proto__是不是一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function instanceOf(instance, constructor){
var pro = instance.__proto__;
while(true){
if(pro===null){
return false;
}

if(pro===constructor.prototype){
return true;
}

pro = pro.__proto__;
}
}

reduce方法实现

1
2
3
4
5
6
7
8
9
10
11
12

Array.prototype.reduce = function(fn, initialVal){
var arr = this;
var pre = initialVal ? initialVal : arr[0];
var index = initialVal ? 0 : 1;

for(var i=index; i<arr.length; i++){
pre = fn(pre, arr[i], i, arr);
}

return pre;
}

debounce方法实现

1
2
3
4
5
6
7
8
9
10
11
12
function debounce(fn, time){
var timer = null;
return function(){
var that = this;
var args = arguments
clearTimeout(timer);
timer = seTimeout(function(){
fn.apply(that, args)
}, time);
}

}

throttle方法实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function throttle(fn, time){
var freeze = false;
return function(){
if(freeze) return;

var that = this;
var args = arguments;

freeze = true;

setTimeout(function(){
fn.apply(that, args);
freeze = false;
}, time)
}
}


冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var list = [1,2,3,4,5,6,4,3,2,1];


function bubbleSort(list){

var len = list;

for(var i=0; i<list.length; i++){

for(var j=i; j<list.length; j++){
var l = list[i];
var r = list[j];
var temp = l;

if(r<l){
list[i] = r;
list[j] = temp;
}
}
}

return list;
}

bubbleSort(list)


快速排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function quickSort(arr){
if(arr.length <= 1){ return arr; };
var middleIndex = Math.floor(arr.length/2);
var item = arr.splice(middleIndex, 1)[0];
var leftArr = [];
var rightArr = [];
for(var i=0; i<arr.length; i++){
var obj = arr[i];
if(obj<item){
leftArr.push(obj);
}else{
rightArr.push(obj);
}
}

return quickSort(leftArr).concat(item, quickSort(rightArr));
}


实现一个请求可以控制最大并行请求数量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class GlobalRequest {
constructor(maxConcurrency) {
this.max = maxConcurrency;
}

requestList = [];

runNextTask() {
for (let i = 0; i < this.requestList.length; i++) {
const request = this.requestList[i];
if (request.wait) {
//找到下一个待执行任务
request.wait = false;
request.fn();
break;
}
}
}

get(url) {
return new Promise((resolve, reject) => {
const p = {
wait: true,
fn: () => {
window.fetch(url).then((data) => {
const i = this.requestList.indexOf(p);
//找到当前执行完的任务,将其从队列删除;
this.requestList.splice(i, 1);
//再执行下一个待执行任务
this.runNextTask();
resolve(data);
});
}
};

this.requestList.push(p);

if (this.requestList.length <= this.max) {
p.wait = false;
p.fn();
}
});
}
}

const r = new GlobalRequest(2);


实现一个 Events 模块,可以实现自定义事件的订阅、触发、移除功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class EEvent {
events = {}

once(eventName, fn){
if(!this.events[eventName]){
this.events[eventName] = [];
}

this.events[eventName].push({func: fn, isOnce: true});
}

fire(eventName){//触发事件
if(!this.events[eventName]) return;

this.events[eventName] = this.events[eventName].filter((item)=>{
item.func && item.func();
return !item.isOnce;
})
}
on(eventName, fn){//注册事件
if(!this.events[eventName]){
this.events[eventName] = [];
}

this.events[eventName].push({func: fn, isOnce: false});
}
off(eventName, fn){//移除事件
if(this.events[eventName] && !fn){
delete this.events[eventName]
}

if(this.events[eventName] && fn){
this.events[eventName] = this.events[eventName].filter((f)=>{
return f.func!=fn;
})
}
}
}