Javascript Promise 学习(上)
Promise 就是处理异步的一个规范方法
a();
b();
alert("a");
如果a() 里面有一个ajax 或者settimeout
那么alert("a") 会先跑
这就是异步了。
从前我们用一堆callBack函数来解决问题,但是这样写不好看。
promise 的写法美丽多了
依据上面的例子
a().then(b).then(function(){
alert("");
})
这样它会先跑完 a -> b - > alert("");
虽然很多类库都实现了这个功能,甚至游览器也有自带的,而且ecma6好像还会有更好更简单的方法来解决异步的操作 !
but ! 人生最鸡巴的就是这个 but!
当作学习,我还是自己写了一个版本。
这个版本不是 promise a 也不是promise a+ 也不是jQuery Defferd 规范
它是给我自己用的!
个人觉得重点思想就是在 then 的时候返回一个 next promise , 而next promise 记入在上一个promise中,这样就创建了一个promise 连环链
而一个回调函数返回的是promise 或者我们叫thenAble函数,那么我们就把原先的链连接去它的后面就可以了。
function Promise(fn) {
//如果有放fn进来,那么就调用它,把 pass & fail 做参数传进去
//这样fn 内就可以直接 publish了
if (G.isFunction(fn)) {
var promise = new Promise();
fn.apply(null, [promise.pass.bind(promise), promise.fail.bind(promise)]);
return promise;
}
this.status = "pending";
this.data;
this._nextPromise; //保存下一个的指针,这样才可以连环触发
this._passFn_list = [];
this._failFn_list = [];
this._isAllPassRequest = true; //all or any 用的
//注释
//要改要潜水
//这里只说简单的使用说明吧
/*
//方便的初始化调用法
new Promise(function (pass, fail) {
setTimeout(pass, 100, "zzz"); //第三para是传给方法的参数 = pass(zzz)
}).then(fnPass, fnFail);
//一般调用法
a().then(b).then(c);
function a() {
var promise = new Promise();
setTimeout(function () {
promise.pass("data");
}, 1000);
return promise;
}
//all 和 any 参数是array,它会并发处理
//等待全部处理完验证每个的返回
//unknow 算 true
//(note: 一个promise只保存all or any 1condition default是 all)
//如果要求是 all ,那么回来的全部都必须all 就调用nextPromise.pass else fail
//如果要求是 any ,那么回来的要有至少一个是pass 就调用nextPromise.pass else fail
a().all([b, c], [c, b]).then(b, c);
//.catch, .complete 都是语法糖罢了 //异步loop调用, 这个比较复杂,以后还可以有更多变化
var list = [a, a, a];
var promiseTemp;
for (var i = 0; i < list.length; i++) {
var promise = (promiseTemp == undefined) ? list[i]() : promiseTemp.then(list[i]);
promiseTemp = promise;
}
*/
//简单说明:
/*
两大关键方法
then : 把参数加入fn_list中, 然后new 新的promise, 当前的promise.next 指向新的promise(循环链就开始了) ,然后把新的promise 返回出去
pass/fail : 把fn_list中的方法全部拿出来,然后"并发处理", 检查每一个是不是返回promise, 是的话要记入和跟踪,跟踪其实就是为这个promise加一个then,然后把职责链放进去,交替的感觉。 调用then/all/any的时候如果promise的status不是pending会直接add and 发布data
在并发方法之后 fnList会被清除干净,也就是说一个promise的fnlist的每个方法只会被执行一次
*/
}
Promise.prototype._concatFnList = function (passFn_list, failFn_list) {
//all 和 any 用来concat fn list 的
if (passFn_list != undefined && Array.isArray(passFn_list)) {
this._passFn_list = this._passFn_list.concat(passFn_list);
}
if (failFn_list != undefined && Array.isArray(failFn_list)) {
this._failFn_list = this._failFn_list.concat(failFn_list);
}
}
Promise.prototype._getFinalDataByDataRecordList = function (dataRecord_list) {
//dataRecord_list 是array , 因为大部分时候我们是用一个data罢了,所以这边做一些小过滤
var finalValue;
if (dataRecord_list.length == 1) {
finalValue = dataRecord_list[0].data; //抽取data出来就够了
}
else {
dataRecord_list.orderBy("index");//排好位置(因为all/any是并发,不会按照顺序回来)
finalValue = dataRecord_list.map(function (obj) {
delete obj.index; //洗掉属性 index 排位之后就没用了
return obj;
});
}
return finalValue;
}
Promise.prototype._publish = function (fn_list, that) {
//pass 和 fail 的共用过程
if (fn_list.length > 0) {
var returnPromiseCountRecord = 0; //for all & any 多个并发,同时会有多个promise函数
var dataRecord_list = []; //收集全部函数回来的data {index,data,status}
for (var i = 0, l = fn_list.length; i < l; i++) {
var fn = fn_list[i];
var returnValue = fn.call(that, that.data); //挺关键的一句,这里会确定他返回的是不是promise
(function (i) {
function callBack(data) {
//这里是我们外面的promise链 publish触发的
var result = { index: i, status: this.status, data: data };
dataRecord_list.push(result) //record data
returnPromiseCountRecord--; //之前我们累加计算,这里publish了就要开始累减回去了
//一直到0就准备做ending然后继续外面的职责链了
if (returnPromiseCountRecord == 0) {
var is_allPass = dataRecord_list.every(function (v) {
return (v.status == "unknow" || v.status == "pass");
});
var is_anyPass = dataRecord_list.some(function (v) {
return (v.status == "unknow" || v.status == "pass");
});
var finalValue = that._getFinalDataByDataRecordList(dataRecord_list);
//这里会依据 all or any 做处理 觉得调用下一家的 pass or fail
if ((that._isAllPassRequest && is_allPass) || (!that._isAllPassRequest && is_anyPass)) {
that._nextPromise.pass(finalValue);
}
else {
that._nextPromise.fail(finalValue);
}
}
}
if (returnValue instanceof Promise) {
//是promise的话就要 +count,然后+then给他,把职责链给他,等待他触发
returnPromiseCountRecord++;
var otherPromise = returnValue;
otherPromise.complete(callBack);
}
else {
//不是的话就push data 就好,status : unknow 也算 pass
var result = { index: i, status: "unknow", data: returnValue };
dataRecord_list.push(result);
}
})(i)
}
fn_list.length = 0; //运行完就clear掉
//没有return任何thenable方法
if (returnPromiseCountRecord == 0) {
var finalValue = that._getFinalDataByDataRecordList(dataRecord_list);
that._nextPromise.pass(finalValue); //因为没有pass fail 参考所以一定是pass
}
}
else {
//如果没有效应就去找小一家promise效应
if (that._nextPromise) {
that._nextPromise[that.status](that.data);
}
}
}
Promise.prototype.all = function (passFn_list, failFn_list) {
this._concatFnList(passFn_list, failFn_list);
if (this.status != "pending") this._alreadyPublish();
return this._nextPromise || (this._nextPromise = new Promise());
}
Promise.prototype.any = function (passFn_list, failFn_list) {
this._concatFnList(passFn_list, failFn_list);
this._isAllPassRequest = false;
if (this.status != "pending") this._alreadyPublish();
return this._nextPromise || (this._nextPromise = new Promise());
}
Promise.prototype.then = function (passFn, failFn) {
if (passFn != undefined) this._passFn_list.push(passFn);
if (failFn != undefined) this._failFn_list.push(failFn);
if (this.status != "pending") this._alreadyPublish();
return this._nextPromise || (this._nextPromise = new Promise());
}
Promise.prototype._alreadyPublish = function () {
var that = this;
setTimeout(function () {
that[that.status](that.data);
}, 0);
}
Promise.prototype.pass = function (data) {
var that = this;
this.status = "pass";
this.data = data;
var passFn_list = this._passFn_list;
that._publish(passFn_list, that);
}
Promise.prototype.fail = function (data) {
var that = this;
this.status = "fail";
this.data = data;
var failFn_list = this._failFn_list;
that._publish(failFn_list, that);
}
Promise.prototype.complete = function (completeFn) {
return this.then(completeFn, completeFn);
}
Promise.prototype.catch = function (catchFn) {
return this.then(void 0, catchFn);
}
Promise.prototype.getLastPromise = function () {
var promise = this;
for (var i = 0; i < Number.MAX_VALUE; i++) {
if (promise._nextPromise === undefined) {
return promise;
}
else {
promise = promise._nextPromise;
}
}
}
G.s.Promise = Promise;
Javascript Promise 学习(上)的更多相关文章
- Javascript Promise 学习笔记
1. 定义:Promise是抽象异步处理对象以及对其进行各种操作的组件,它把异步处理对象和异步处理规则采用统一的接口进行规范化. 2. ES6 Promises 标准中定义的API: ...
- Javascript - Promise学习笔记
最近工作轻松了点,想起了以前总是看到的一个单词promise,于是耐心下来学习了一下. 一:Promise是什么?为什么会有这个东西? 首先说明,Promise是为了解决javascript异步编 ...
- Javascript Promise 学习 (中)
时隔多日,对promise有了多一点点的了解. 最近用angularjs 做开发,所以研究了一下它的 $q 功能不算很强大,算是简化版的 Q.js 参考了一下源码,不过我的等级还差很多... 作为学习 ...
- JavaScript之Promise学习笔记
一直想知道Promise到底是怎么实现的,网上一搜几十篇文章,看的一脸蒙蔽.最后算是找到几个讲的真心很详细明了的.看了一份源码看了很久很久……最后找大佬问了几处看不懂的地方,大佬只看了十几分钟就看懂了 ...
- Promise 学习笔记 - 时间支配者
本文同步自我的个人博客:http://www.52cik.com/2015/11/08/promise.html JavaScript 的 promises 事实标准称为 Promises/A+.ES ...
- javascript设计模式学习之十六——状态模式
一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...
- javascript设计模式学习之八_发布订阅(观察者)模式
一.发布订阅模式定义 jQuery中的callbacks,defered,promise本质上就是发布订阅模式的实现.ES6的promise内部实现未开源,不了解具体机制 发布订阅模式又叫做观察者模式 ...
- [Javascript] Promise
Promise 代表着一个异步操作,这个异步操作现在尚未完成,但在将来某刻会被完成. Promise 有三种状态 pending : 初始的状态,尚未知道结果 fulfilled : 代表操作成功 r ...
- 大量Javascript/JQuery学习教程电子书合集
[推荐分享]大量Javascript/JQuery学习教程电子书合集,送给有需要的人 不收藏是你的错^_^. 经证实,均可免费下载. 资源名称 资源大小 15天学会jQuery(完整版).pd ...
随机推荐
- 状压dp-poj-1170-Shopping Offers
题目链接: http://poj.org/problem?id=1170 题目意思: 购物车里有b种(0=<b<=5)物品,每种物品告诉物品代号c(1=<c<=999),数量为 ...
- SKPhysicsJointFixed类
继承自 NSObject 符合 NSCoding(SKPhysicsJoint)NSObject(NSObject) 框架 /System/Library/Frameworks/SpriteKit. ...
- CentOS 7 安装教程
参考资料: http://www.cnblogs.com/bobbylinux/articles/centos7.html
- 关于centos6.5系统安装FTP服务和配置的方法
一般在配置服务器的时候,涉及到代码上传,通常都要用到FTP方式. 1.先查看系统是否安装vsftpd: rpm -qa | grep vsftpd 如果出现vsftpd-2.2.2-14......字 ...
- #ifndef #define #endif 的用法
1.文件中的#ifndef 头件的中的#ifndef,这是一个很关键的东西.比如你有两个C文件,这两个C文件都include了同一个头文件.而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来 ...
- 一览css布局标准
回顾历史,CSS1于1996.12.17发正式版,它是为辅助HTML的展现效果而生的.1998.5.12,CSS2发正式版.随后发修订版CSS2.1,纠正了CSS2中的一些错误.注意从CSS2起,CS ...
- svg text文字居中
<text x="100" y="100" text-anchor="middle" dominant-baseline=" ...
- Nginx 反向代理配置实例(转)
user www www; worker_processes ; error_log logs/error.log notice; pid logs/nginx.pid; worker_rlimit_ ...
- jQuery mini ui 2
1.<a class="mini-button" iconCls="icon-add" onclick="addRow()" plai ...
- Nagios配置—添加linux主机监控
nagios安装请参看:Nginx平台安装Nagios监控服务 下面是我添加linux监控机的过程,如有错误或者不当的地方请指出: 测试环境: 监控主机:nagios+nagios插件+nrpe+网站 ...