javascript Promise简单学习使用方法小结


Posted in Javascript onMay 17, 2016

解决回调函数嵌套太深,并行逻辑必须串行执行,一个Promise代表一个异步操作的最终结果,跟Promise交互的主要方式是通过他的then()方法来注册回调函数,去接收Promise的最终结果值

Promise相关的协议有PromiseA和PromiseA+

定义一个类Promise

定义属性队列queue,初始化空数组[]

定义属性值value,初始化null

定义属性状态status,初始化“pending”(默认值)

定义成员方法getQueue(),返回属性queue

定义成员方法getStatus(),返回属性status

定义成员方法setStatus(),设置状态,传递参数:status,value

判断status为fulfilled或者rejected,

设置status属性this.status=status

设置value属性this.value=value || null ,如果不传value就是null

定义冻结变量freezeObject

定义成员方法isFulfilled(),判断当前状态是否是(完成)

定义成员方法isRejected(),判断当前状态是否是(失败)

定义成员方法isPending(),判断当前状态师傅是(等待)

定义成员方法then(),传递参数:onFulfilled成功的回调,onRejected失败的回调

定义对象handler对象,属性fulfilled,rejected两个回调函数

定义handler对象的deferred属性,Deferred对象

判断当前状态是否等待,如果是等待 把handler对象塞入queue队列数组

如果不是等待状态,调用Utils对象的procedure()方法,参数:status,

返回 handler.deferred.promise对象

定义一个类Deferred

定义属性promise,初始化Promise对象

定义成员方法resolve(),传递参数:result结果

判断Promise对象的状态是 等待,直接返回

调用Promise对象的getQueue()方法,获取queue数组

循环数组

//todo调用工具类Utils. procedure()方法,参数:“fulfilled”,元素,err信息

调用Promise对象的setStatus()方法,设置状态,参数:'fulfilled',result

定义成员方法reject,传递参数:err错误信息

判断Promise对象的状态是 等待,直接返回

调用Promise对象的getQueue()方法,获取queue数组

循环数组

//todo,调用工具类Utils. procedure()方法,参数:“rejected”,元素,err信息

调用Promise对象的setStatus()方法,设置状态,参数:'fulfilled',result

定义工具类Utils,使用匿名函数立即执行,得到一个对象
 
返回对象,对象中有一个方法procedure()

定义procedure()方法,传递参数:type状态类型,handler处理器数组,result结果

获取到处理函数func,在handler[type]

到这里我看晕了。。。
 

使用方法:

定义一个函数ajax,传递参数:url路径
 

获取Deferred对象,new出来

ajax请求数据的代码,在返回数据的回调方法中

如果成功了调用Deferred对象的resolve()方法,参数:返回的数据

如果失败了调用Deferred对象的reject()方法,参数:返回的数据

返回Deferred.promise对象

调用ajax()方法,得到promise对象,参数:url,

调用promise对象的then()方法,参数:匿名函数

调用ajax()方法,获取到promise对象,返回这个对象

形成链式调用
 

js部分:

<script>
//Promise代码部分(我选择狗带)
Promise = function() {
  this.queue = [];
  this.value = null;
  this.status = 'pending';// pending fulfilled rejected
};

Promise.prototype.getQueue = function() {
  return this.queue;
};
Promise.prototype.getStatus = function() {
  return this.status;
};
Promise.prototype.setStatus = function(s, value) {
  if (s === 'fulfilled' || s === 'rejected') {
    this.status = s;
    this.value = value || null;
    this.queue = [];
    var freezeObject = Object.freeze || function(){};
    freezeObject(this);// promise的状态是不可逆的
  } else {
    throw new Error({
      message: "doesn't support status: " + s
    });
  }
};
Promise.prototype.isFulfilled = function() {
  return this.status === 'fulfilled';
};
Promise.prototype.isRejected = function() {
  return this.status === 'rejected';
}
Promise.prototype.isPending = function() {
  return this.status === 'pending';
}
Promise.prototype.then = function(onFulfilled, onRejected) {
  var handler = {
    'fulfilled': onFulfilled,
    'rejected': onRejected
  };
  handler.deferred = new Deferred();

  if (!this.isPending()) {//这里允许先改变promise状态后添加回调
    utils.procedure(this.status, handler, this.value);
  } else {
    this.queue.push(handler);//then may be called multiple times on the same promise;规范2.2.6
  }
  return handler.deferred.promise;//then must return a promise;规范2.2.7
};

var utils = (function(){
  var makeSignaler = function(deferred, type) {
    return function(result) {
      transition(deferred, type, result);
    }
  };

  var procedure = function(type, handler, result) {
    var func = handler[type];
    var def = handler.deferred;

    if (func) {
      try {
        var newResult = func(result);
        if (newResult && typeof newResult.then === 'function') {//thenable
          // 此种写法存在闭包容易造成内存泄露,我们通过高阶函数解决
          // newResult.then(function(data) {
          //   def.resolve(data);
          // }, function(err) {
          //   def.reject(err);
          // });
          //PromiseA+规范,x代表newResult,promise代表def.promise
          //If x is a promise, adopt its state [3.4]:
          //If x is pending, promise must remain pending until x is fulfilled or rejected.
          //If/when x is fulfilled, fulfill promise with the same value.
          //If/when x is rejected, reject promise with the same reason.
          newResult.then(makeSignaler(def, 'fulfilled'), makeSignaler(def, 'rejected'));//此处的本质是利用了异步闭包
        } else {
          transition(def, type, newResult);
        }
      } catch(err) {
        transition(def, 'rejected', err);
      }
    } else {
      transition(def, type, result);
    }
  };

  var transition = function(deferred, type, result) {
    if (type === 'fulfilled') {
      deferred.resolve(result);
    } else if (type === 'rejected') {
      deferred.reject(result);
    } else if (type !== 'pending') {
      throw new Error({
        'message': "doesn't support type: " + type
      });
    }
  };

  return {
    'procedure': procedure
  }
})();

Deferred = function() {
  this.promise = new Promise();
};

Deferred.prototype.resolve = function(result) {
  if (!this.promise.isPending()) {
    return;
  }

  var queue = this.promise.getQueue();
  for (var i = 0, len = queue.length; i < len; i++) {
    utils.procedure('fulfilled', queue[i], result);
  }
  this.promise.setStatus('fulfilled', result);
};

Deferred.prototype.reject = function(err) {
  if (!this.promise.isPending()) {
    return;
  }

  var queue = this.promise.getQueue();
  for (var i = 0, len = queue.length; i < len; i++) {
    utils.procedure('rejected', queue[i], err);
  }
  this.promise.setStatus('rejected', err);
}
/*****************************上面看不懂,分割线************************************/
//测试部分
ajax = function(url) {
  var def = new Deferred();

  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      if ((xhr.status >=200 && xhr.status < 300) || xhr.status === 304) {
        def.resolve(xhr.responseText)
      } else {//简化ajax,没有提供错误回调
        def.reject(new Error({
          message: xhr.status
        }));
      }
    }
  };
  xhr.open('get', url, true);
  xhr.send(null);

  return def.promise;
}

ajax('test.php?act=1').then(function(data1) {
  console.log(data1);//处理data1
  return ajax('test.php?act=2');
}).then(function(data2) {
  console.log(data2);//处理data2
  return ajax('test.php?act=3');
}, function(err) {
  console.error(err);
}).then(function(data3) {
  console.log(data3);
  alert('success');
}, function(err) {
  console.error(err);
});
</script>

php:

<?php
if($_GET['act']==1){
  echo json_encode(array("code"=>200));
}else if($_GET['act']==2){
  echo json_encode(array("code"=>300));
}else if($_GET['act']==3){
  echo json_encode(array("code"=>400));
}

javascript Promise简单学习使用方法小结

以上这篇javascript Promise简单学习使用方法小结就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery中删除元素的实现代码
Dec 29 Javascript
js事件冒泡实例分享(已测试)
Apr 23 Javascript
JS调用CS里的带参方法实例
Aug 01 Javascript
jQuery实现异步获取json数据的2种方式
Aug 29 Javascript
jQuery实现预加载图片的方法
Mar 17 Javascript
js实现的四级左侧网站分类菜单实例
May 06 Javascript
浅谈JavaScript中setInterval和setTimeout的使用问题
Aug 01 Javascript
解决jQuery上传插件Uploadify出现Http Error 302错误的方法
Dec 18 Javascript
jQuery中iframe的操作(点击按钮新增窗口)
Apr 20 Javascript
JS控制div跳转到指定的位置的几种解决方案总结
Nov 05 Javascript
React-Native之定时器Timer的实现代码
Oct 04 Javascript
vue异步axios获取的数据渲染到页面的方法
Aug 09 Javascript
关于安卓手机微信浏览器中使用XMLHttpRequest 2上传图片显示字节数为0的解决办法
May 17 #Javascript
Web前端新人笔记之jquery入门心得(新手必看)
May 17 #Javascript
Angularjs中的事件广播 —全面解析$broadcast,$emit,$on
May 17 #Javascript
iScroll.js 使用方法参考
May 16 #Javascript
BootStrap的JS插件之轮播效果案例详解
May 16 #Javascript
老司机带你解读jQuery插件开发流程
May 16 #Javascript
jQuery 获取多选框的值及多选框中文的函数
May 16 #Javascript
You might like
php提示undefined index的几种解决方法
2012/05/21 PHP
php中通过DirectoryIterator删除整个目录的方法
2015/03/13 PHP
thinkphp微信开发(消息加密解密)
2015/12/02 PHP
PHP记录和读取JSON格式日志文件
2016/07/07 PHP
用showModalDialog弹出页面后,提交表单总是弹出一个新窗口
2009/07/18 Javascript
根据当前时间在jsp页面上显示上午或下午
2014/08/18 Javascript
JavaScript几种数组去掉重复值的方法推荐
2016/04/12 Javascript
ionic js 复选框 与普通的 HTML 复选框到底有没区别
2016/06/06 Javascript
jQuery动态添加可拖动元素完整实例(附demo源码下载)
2016/06/21 Javascript
用JavaScript实现让浏览器停止载入页面的方法
2017/01/19 Javascript
js中的事件委托或是事件代理使用详解
2017/06/23 Javascript
解决vue axios的封装 请求状态的错误提示问题
2018/09/25 Javascript
详解Angular模板引用变量及其作用域
2018/11/23 Javascript
Vue Echarts实现可视化世界地图代码实例
2019/05/07 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
2019/05/14 jQuery
vue 使用element-ui中的Notification自定义按钮并实现关闭功能及如何处理多个通知
2019/08/17 Javascript
Vue+element-ui添加自定义右键菜单的方法示例
2020/12/08 Vue.js
[00:28]DOTA2北京网鱼队选拔赛
2015/04/08 DOTA
Python中使用tarfile压缩、解压tar归档文件示例
2015/04/05 Python
int在python中的含义以及用法
2019/06/27 Python
详解anaconda安装步骤
2020/11/23 Python
使用css3 属性如何丰富图片样式(圆角 阴影 渐变)
2012/11/22 HTML / CSS
挪威手表购物网站:Klokker
2016/09/19 全球购物
男女时尚与复古风格在线购物:RoseGal(全球免费送货)
2017/07/19 全球购物
德国香水、化妆品和护理产品网上商店:Parfumdreams
2018/09/26 全球购物
GE设备配件:GE Appliance Parts(家电零件、配件和滤水器)
2018/11/28 全球购物
我想声明一个指针并为它分配一些空间, 但却不行。这些代码有什么 问题?char *p; *p = malloc(10);
2016/10/06 面试题
what is the difference between ext2 and ext3
2013/11/03 面试题
不假外出检讨书
2014/01/27 职场文书
授权委托书(公民个人适用)
2014/09/19 职场文书
教师党的群众路线对照检查材料
2014/09/24 职场文书
入队仪式主持词
2015/07/04 职场文书
优秀团员主要事迹范文
2015/11/05 职场文书
大学生奖学金获奖感言(范文)
2019/08/15 职场文书
使用Bandicam录制鼠标指针并附带点击声音,还可以添加点击动画效果
2022/04/11 数码科技
使用python绘制横竖条形图
2022/04/21 Python