解决回调函数嵌套太深,并行逻辑必须串行执行,一个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简单学习使用方法小结就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。
本文向大家介绍简单学习5种处理Vue.js异常的方法,包括了简单学习5种处理Vue.js异常的方法的使用技巧和注意事项,需要的朋友参考一下 错误大全 为了测试各种异常处理技巧,我故意触发三种类型的错误。 第一种:引用一个不能存在的变量: 上述代码运行后不会抛出错误,但是在控制台会有[Vue warn]消息。 你可以在Codepen查看例子完整代码。 第二种:将变量绑定到一个被计算出来的属性,计算的
本文向大家介绍Android学习之介绍Binder的简单使用,包括了Android学习之介绍Binder的简单使用的使用技巧和注意事项,需要的朋友参考一下 前言 最近因为公司项目需求,需要远程调度启动客户端输入法输入内容。 这就是大致的需求流程,这篇首先讲远程与服务控制端通讯。首先控制服务端定义好一个Service,且在ServiceManager注册添加服务。 在这里我讲解远程端与服务控制端通讯
本文向大家介绍学习thinkphp5.0验证类使用方法,包括了学习thinkphp5.0验证类使用方法的使用技巧和注意事项,需要的朋友参考一下 通过一个实例,给大家讲解一下如果通过thinkphp5.0验证类的方法。 自定义验证类,需继承Validate类 比如在home模块新建validate文件夹,再新建Test.php验证类,内容如下: 在Index控制器test方法使用 以上就是我们给出的
Scikit-learn 套件的安装 目前Scikit-learn同时支持Python 2及 3,安装的方式也非常多种。对于初学者,最建议的方式是直接下载 Anaconda Python (https://www.continuum.io/downloads)。同时支持 Windows / OSX/ Linux 等作业系统。相关数据分析套件如Scipy, Numpy, 及图形绘制库 matplot
本文向大家介绍简单学习Python多进程Multiprocessing,包括了简单学习Python多进程Multiprocessing的使用技巧和注意事项,需要的朋友参考一下 1.1 什么是 Multiprocessing 多线程在同一时间只能处理一个任务。 可把任务平均分配给每个核,而每个核具有自己的运算空间。 1.2 添加进程 Process 与线程类似,如下所示,但是该程序直接运行无结果,因
本文向大家介绍.NET分页控件简单学习,包括了.NET分页控件简单学习的使用技巧和注意事项,需要的朋友参考一下 这几天无意间看到一个关于分页的帖子,觉得写得挺好的。关于这些东西,自己一直都是只知道原理,却没有真正动手做过,于是研究了一下分页的原理自己动手写了一个十分特别非常简单的分页程序,在这里与大家分享一下。 这个程序取数据使用的ado.net,首先先新建一个取数据的类PageDAl 然后记