坑爹的游戏

今天下午玩了ensemble的作品黙って私のムコになれ(中文翻译:千金逼我嫁),玩了佑里恵的那条线,玩到最后我的表情是这样的:

黑人问号

表示对SB男主和游戏中后期的剧情感到很蛋疼

决定再也不玩这家公司的游戏了。

阅读全文>>

关于Promise的学习

最近在做创业学院的LowB高效历web端项目,前端样式做好了,然后拿到后端提供的接口文档,然后就是很高兴地测试了,然后就发现了一堆问题(主要是异步使得请求不能按照设想的样子进行),于是学习了promise,学习的资料是promise迷你书,目前这本书大概看了70-80%左右,下面是学习promise的笔记(非总结,总结应该是我能够在理论和实战上得心应手的情况下才写的):

0X01: Promise初步了解

严格来讲,我学习的是Javascript promise,因为promise是一种规范,或者说,是一种异步调用的规范,各种语言平台都可以实现,而我学习的是Javascript的实现方式。一般所说的promise有两种,一种是promise规范,一种是promise对象,我们实际上实现promise的,就是用的promise对象。

promise有很多种规范,比如Promise/A, Promise/B, Promise/D,Promise/A+,就跟麦当劳套餐差不多。。。

按Promise/A+规范的说法,Promise是分为三种状态的:

Fulfilled         //当resolve(成功)时,此时Promise的状态
Rejected      //当reject(失败)时,此时Promise的状态
Pending       //既不是resolve也不是reject时的状态

简单地说,对于一个promise对象(注意这个说法),fulfilled和rejected是终态,达到这两个状态之一就不能变化了,而在pending的时候,是可以转换为fulfilled或者rejected状态的。

由于我常用的框架是AngularJS,AngularJS实现promise的关键是$q库和$http这些,但是下面学到的都是基于原生Javascript的Promise:

0x02: Promise的基本使用

基于原生Javascript的六个Promise的方法:

Promise.resolve()
Promise.reject()
promise.then()
promise.catch()
Promise.all()
Promise.race()

产生promise对象的方式:

var promise = new Promise(function(resolve, reject) {
     setTimeout(function() {
    if(Math.random() > 0.5) {
       resolve(2);
    } else {
       reject(3);
    }
     }, 2000);
});

promise.then(function(value) {
   console.log(value);
}, function(error) {
   console.log(error) 
});

通过Promise构造函数产生了对应的promise对象,当产生随机数大于0.5时,promise达到fulfilled状态,否则promise达到rejected状态,promise.then(onfulfilled, onrejected)分别对应两个状态的处理函数,参数值分别为对应传入的数值。

Promise的六个方法中,#then和#catch是对象实例拥有的方法,而resolve,reject,all,race则为静态方法:

Promise.resolve也是产生一个promise对象,相当于下面代码的语法糖:

Promise.resolve(value) === new Promise(function(resolve) {
    resolve(value);
});

对应的Promise.reject:

Promise.reject(value) === new Promise(function(undefined, reject) {
    reject(value);
});

Promise.resolve(value)的特点是可以转换thenable对象为promise对象,thenable对象简单说就是拥有then方法的对象,比如JQuery的$.ajax()方法那样,可以将thenable对象转成promise对象,并且调用thenable对象的then方法进行promise的初始化。

Promise.reject(value)也是一样的道理;

promise.then和promise.catch就是promise chain重要的组成部分,其中promise.catch其实就是promise.then抽象出来的方法:then(undefined, onRejected);

所以下面主要还是promise.then: promise.then返回的是promise对象,比如下面的一个调用:

var promise = Promise.resolve(1);
promise.then(function(value1) {
    return value1;
}).then(function(value2) {
    return value2 * 2;
}).then(function(value3) {
    return value3 + 1;
}).then(function(value4) {
    console.log(value4);    //value4 ==> 3
}).catch(function(error) {
    console.log('what the fuck???');
});

到return value的时候如果没有发生错误,那么将返回一个promise对象,并且这个对象跟之前的promise对象是不同的,并且,value会作为 新promise对象的resolve方法的参数,当然有个例外就是value本身就是个promise对象的话,那么就返回这个promise对象,调用链的下一个then就是这个promise对象达到fulfilled状态或者rejected状态时调用的方法(then(onFulfilled,onRejected);),以AngularJS作为例子:

var deferred = $q.defer();
var promise = deferred.promise;
$http({
    method: 'GET',
    url: 'https://www.aonosora.com/site1'
}).then(function(result) {
    if(result.msg === 'success') {
    deferred.resolve('成功!');
    } else {
    deferred.reject('失败!');     
    }
}).catch(function(error) {
    deferred.reject('失败!');
});

return promise.then(function(result) {
     //TODO
     //返回promise对象,下一个then就是这个promise
     //resolve或者reject状态调用的函数
     return $http({
       method: 'GET',
       url: 'https://www.aonosora.com/site2'
     });
}, function(error) {
     console.log('what???');
}).then(function(result) {
     //TODO
}, function(error) {
     console.log('what???');    
});

Promise.all方法是专门用于处理Promise数组的,适用与多个Promise同时调用的情况,一般的用法如下:

Promise.all([promise1,promise2,...]).then(function(result) {
    //TODO
}, function(error) {
    //TODO
});

Promise.all数组里面的promise是同时执行的,如果所有的promise都能达到fulfilled状态,那么调用onFulfilled处理函数,result的值为: [promise1->result, promise-result, ....],如果在这个过程中有一个先达到rejected状态,那么直接调用onRejected处理函数,参数值为对应的promise的reject的error值

Promise.race方法也是处理Promise数组的,不过不同的是,Promise.race方法只要数组中有一个promise达到fulfilled或者rejected状态时,便会触发onFulfilled或者onRejected处理函数:

Promise.race([promise1,promise2,....]).then(function(result) {
    //TODO
}, function(error) {
    //TODO
});

0x03: 关于Promise的一些要明白的地方

上面的Promise,按下面的代码来看,我们很可能认为输出是这样的:

var promise = new Promise(function(resolve, reject) {
     console.log('haha');   //1
     resolve();
});

promise.then(function() {
     console.log('hehe')';  //2
});

console.log('hihi');        //3

这样认为的理由是:产生promise对象的时候,是会调用回调函数的,相当于立即执行了resolve,那么就会立即调用了then,那么就会输出hehe,然后就是hihi了。

但是很遗憾,这个想法是错误的,实际上的结果是haha->hihi->hehe,把console.log('hihi')改为循环100次的console,console.log('hehe')也是最后输出的,因为Promise规范规定调用一定是异步的,即resolve和reject()都一定是异步的,因为同步的情况在实际应用中可能会产生很多问题,比如,如果是同步的,且同步的调用是基于dom加载完成进行的,那么就会有两种结果:

dom加载完成后调用,按顺序同步调用
dom加载未完成,调用顺序产生了问题

而基于异步的情况下则不会出现顺序不确定的问题了,所以第一点要记住的是promise一定是基于异步的。

Promise有很多中类库,比如Q库之类的,很多前端框架或者后端框架已经集成了Promise类库的服务,比如AngularJS的$q服务和$http,$resource服务等等,目前对应Promise的支持除了IE完全不支持之外,其他基本都没什么问题

0x04: Promise的进阶

如果我们要写一个promise对象的状态处理,那么可能是这样的:

var promise = new Promise(function(resolve, reject) {
     if(Math.random() > 0.5) {
    resolve();
     } else {
    reject();
     }
}

promise.then(function(value) {
     //TODO
}).catch(function(error) {
     //TODO
});

又或者是这样的:

promise.then(function(value) {
     //TODO
}, function(error) {
     //TODO
});

这两种方法一般都能用,但是有一些特殊的情况需要说明,下面是一种情况的代码示例:

function failTest() {
    throw new Error('tend to be failed');
}

function badPro() {
    console.log('bad');
}

function goodPro() {
    console.log('good');
}

var promise1 = Promise.resolve(1);
var promise2 = Promise.resolve(2);
promise1.then(failTest, badPro);
promise2.then(failTest).catch(goodPro);

上面的代码只会输出good而不是bad,原因在于,then(onFulfilled,onRejected)中的onFulfilled产生错误,onRejected是不会捕获到的,它只会捕获上一个promise的错误,而catch是方法链的调用,当前的和之前的promise产生的错误都可以被捕获到。

所以,在实际应用中,如果要让onRejected捕获到onFulfilled产生的错误,那么就要用then->catch的方式而不是then(onFulfilled,onRejected)的方式。

但是,在Promise测试中,then(onFulfilled,onRejected)反而才是好的方法,因为如果用then->catch的方式,那么onFulfilled产生的错误将会由onRejected捕获,如果onRejected没出错误,那么测试将会是成功的,这与我们想要的不同,采用then(onFulfilled,onRejected)的方式,当onFulfilled失败时测试就是失败,符合我们的要求。

关于Deferred和Promise

Deferred这个东西是由对应的Library或者Framework按照自己的喜好实现的,并没有像Promise/A+那样统一的规范,Deferred应该说是包含了Promise这个东西。

对于Deferred是个怎么养的东西,可以看下面的代码:

function Deferred() {
   this.promise = new Promise(function(resovle, reject) {
    this._resolve = resolve;
    this._reject = reject;
   });
}

Deferred.prototype.resolve = function(value) {
   this._resolve.call(this.promise, value);
}

Deferred.prototype.reject = function(value) {
   this._reject.call(this.promise, value);
}

function getURL(url) {
    var deferred = new Deferred();
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onload = function() {
    if(xhr.status == 200) {
        deferred.resolve(xhr.responseText);
    } else {
        deferred.reject(new Error(xhr.statusText));
    }
    }
    xhr.onerror = function() {
    deferred.reject(new Error(xhr.statusText));
    }
    xhr.send()

    return deferred.promise;
}

var URL = "http://httpbin.org/get";
getURL(URL).then(function onFulfilled(value){
    console.log(value);
}).catch(console.error.bind(console));

如果是一般声明Promise对象,那么resolve和reject只能在其构造函数里面写,这就很局限性了,并且,如果这个逻辑复杂冗余,那么在代码上也不简洁,Deferred的出现,使得我们能够自己设置调用resolve或者reject的时机,异步调用变得更加灵活。

暂时就写这么多了,我写不了太长,后续如果有就添加新的笔记,附带promise迷你书地址(戳我进入)

阅读全文>>

踏入黄油圈?

好的,这几天基本都在玩黄油,具体玩了什么黄油?玩了柚子社的千恋万花,天色幻想岛,DRACU RIOTS!,漩涡社的那个什么真红之瞳,还有一个叫1/2summer的,漩涡社的游戏嘛,呵呵,柚子社的画风很喜欢,千恋万花的音乐,画风,画质和剧情都很不错,所以推了三条线,而天色幻想岛嘛,呵呵,玩了一条线就不想再玩下去了,果断封存,DRACU RIOTS!?,剧情是说是挺不错的,以吸血鬼为题材,人设也还可以,可惜我对吸血鬼很反感,所以只玩了美羽线,而且这条线只玩了一半就这个游戏封存到硬盘了233333,总之,虽然玩了四五个游戏,但是算真正玩下去的就只有千恋万花了,挺喜欢里面出现的SD图的,感觉好嗨萌,然后从清明开始颓废到现在了QAQ

虽然颓,但是还是想玩,好在柚子社的其他几个游戏我连想玩的欲望都没有,所以近期应该是不怎么玩了吧233333

2

4

阅读全文>>

给博客进行加速

中午去深圳同学家,早上没什么事做,就稍微给这个博客进行加速,我尝试删除Chrome的所有历史数据,然后访问博客的时候,开启开发者工具进行监听,DOMContentLoaded的时间大概在3s左右,而Load的时间则是4s出头,对此进行的解决方法有:

采用CDN加速

这里我直接将我引用的静态图片等资源全部放到了腾讯云的Bucket上面,然后在Bucket上面开启了500+的CDN节点加速,将引用地址全部替换为了对应的CDN地址。采用了这个方法之后,第一次访问网站速度不变,但是以后访问就很快了

采用gzip进行压缩

由于我的网站是采用nginx进行部署的,所以要用到gzip,只需要在nginx.conf里面添加如下代码即可:

    server {
          gzip on;
          gzip_types  text/plain  application/javascript application/x-javascript text/javascript text/xml text/css;
    }

然后测试的结果是,原本boostrap.min.js的大小是119KB左右,做了gzip后只有24.9KB(原谅我没有截图,用心感受就好QWQ),然后重新删除Chrome的所有历史数据,重新进行博客的访问(首次访问),加载情况如下所示:

最终结果

可以看到DOMContentLoaded是799ms,Load是1.53s,Finish那个不用管,会叠加的,总的来说速度比之前快了1倍多,感觉还不错QWQ

背景

阅读全文>>

某高校app的post漏洞

这学期有一门课叫软件工程,选的人才21人,然而老师在上课说要推广一个签到app来考勤,一个班才21人选还玩这些。。,这倒是给原本无趣的软件工程添加了点好玩的东西,就玩一下这个app咯,废话不多说,这个app叫Signer,就是下面这家伙:

Signer

进入,注册账号,然后退出,登录界面如下图:

Signer登录

账号:15521117213  
密码:123456 

既然是优秀校友做的app,那么就从意想不到的地方搞一下它吧。

开启亲爱的Charles,准备抓包,然后进入修改密码界面:

Signer修改密码

原密码:123456  
新密码:426153  

修改完密码后就直接跳到登录界面了,不急,先查看抓包情况:

Charles抓包1

从上图可以很明显看出,通过Get /api/publicey,得到一个公钥,然后利用这个公钥对新密码进行加密,然后将加密的结果post到对应的账号中post /api/users/15521117213,很明显后面是手机号;具体如下:

Get /api/publickey

{
    "code": "200",
    "data": "-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIeiKZeAhYhsNgMrCNEonJA+YdbWsAC9\nDGz0WsU/zKSPVqggI9G+P//Ip4W9U9zZNiwL22E+ZK5Py/fCxzbvk6sCAwEAAQ==\n-----END PUBLIC KEY-----",
    "msg": "操作成功"
}

//---------------分割线------------------

Post /api/users/15521117213

password: RrF1OPfdschY/pziZF2RaFjrqmPnSnEHRFv3uJbh5RaYyW5VDK0HoTABmp0ZvunusvoYWJWu3bHsPeuWX+91TA==
阅读全文>>
...

这里是萌萌哒咪西西

如果您看到下面这段文字,说明您的浏览器不支持canvas(或者您的浏览器采用了兼容模式,请换用新浏览器或者快速模式QAQ