Promise (2) 基本方法
"I'm Captain Jack Sparrow"
加勒比海盗5上映,为了表示对杰克船长的喜爱,昨天闪现了几次模仿船长的走路姿势(哈哈哈,简直妖娆)。
为了周天能去看电影,要赶紧做完手上的活儿,比如总结Promise的方法。
2 Promise基本方法简介
Promise提供了哪些方法了?大招就是放图在控制台输出Promise。

从图中结构看,Promise构造函数上实现了all,race,reject,resolve。Promise构造函数的原型上实现了then,catch的方法。在构造函数原型上实现then,catch的方法是为了让Promise构造函数创建的 实例 共享then,catch方法。(此处提一下,实例和构造函数原型之间存在连接,并不是与构造函数存在连接。对构造函数原型和构造函数,实例之间的关系不理解可以看看《javascript高级程序设计》第六章)。 在Promise构造函数上实现的all,race,reject,resolve,不能在对象的实例中访问,属于Promise构造函数自己,这样做保证了对象的命名空间整洁。所以这几个函数的调用方式是Promise.all(),Promise.race(),Promise.reject(),Promise.resolve()。
Promise简体实现结构大概是:
//Promise构造函数实现的大概结构
function Promise(resolver) {
//promise 的初始状态
this._PromiseStatus = 'pending';
//promise 的value 值(不同实现这个属性名字不一样)
this._PromiseValue = undefined
//......接下来要实现的此处省略
} //给Promise添加方法
Promise.all = all;
Promise.race = race;
Promise.resolve = resolve;
Promise.reject = reject; //重写Promise构造函数原型
Promise.prototype = {
constructor: Promise,
then: then,
catch: catch
}; //方法具体实现
function all( /***/ ) { }
// ......方法实现省略
使用new 操作符创建 promise对象实际经历的步骤:(这个摘抄自《javascript高级程序设计》,好书值得多读几遍)
1.创建了一个新的对象。
2.将构造函数的作用域赋给新对象(因此this就指向了这个新的对象)。
3.执行构造函数代码(为这个新对象添加属性)。
4.返回新对象。
第三条加粗了可以解释为什么all,race,reject,resolve,不能在对象的实例中访问。all,race,reject,resolve并没有在构造函数中赋值给新对象的属性。
总结:then,catch方法是供Promise构造函数创建的 实例调用的,all,race,reject,resolve是Promise构造函数自己调用的。(这句描述不是很标准)
2.1 Promise.prototype.then
⑴.为什么promise对象需要状态?
var testPromiseStatus = new Promise(function(resolve, reject) {
//异步操作......成功后执行了resolve(1)
getdata((data) => {
resolve(data);
})
})
setTimeout(() => {
//从创建了testPromiseStatus,在到执行testPromiseStatus.then中间的时间间隔不确定
testPromiseStatus.then(function onFulfilled(value) {
console.log("我到底应该什么时候执行呀?");
})
},一个不确定的时间)
需要一个状态位去标志,testPromiseStatus 的状态,
如果在执行testPromiseStatus.then()时promise的状态是pedding,将 onFulfilled存起来 等到promise状态变成fulfilled的时候执行。
如果 testPromiseStatus.then()时promise的状态是fulfilled,直接执行onFulfilled函数。
参考es6-promise的源码,会发现它的实现是将回调函数放进一个数组队列(意味着队列里面不一定只有一个函数等待被执行),然后如果promise对象状态不为pending状态,就按顺序执行这个 数组队列里面的回调函数,如果promise对象为pending状态,就是等待promise对象状态迁移后再执行这个数组队列。
- 如果promise对象状态不为pending状态

- 如果promise对象为pending状态,就是等待promise对象状态迁移后再执行这个数组队列

⑵.为什么Promise.prototype.then执行它会返回一个新的promise对象?
var aPromise = new promise(function(resolve, reject) {
resolve("test chain");
});
aPromise.then(function taskA(value) {
// task A
}).then(function taskB(vaue) {
// task B
})
返回新的promise对象的原因是为了链式操作,使得能以taskA → task B 这种流程进行逻辑处理。即aPromise.then()执行完,返回一个新promise b对象,接着执行新promise b对象的then方法,为什么是新的promise对象?因为promise对象需要自己的状态[[PromiseStatus]]值(记录自己的状态)(用来判定是执行then传递的函数,还是等待promise状态迁移后,再执行then里面的函数),每一个还需要自己的 [[PromiseValue]] 值(记录自己的值,当promise状态迁移后,.then的函数每一次调用得到的参数data一致)。所以需要返回一个新的promise对象。
⑶.thenable对象是个啥?
类Promise对象,thenable对象拥有名为then方法的对象。所拥有的 then 方法应该和Promise所拥有的 then 方法具有同样的功能和处理过程。then 调用的回调函数 retuen 一个普通的thenable对象,会先执行thenable对象的then方法,根据then方法内部执行resolve或reject确定[[PromiseValue]]和[[PromiseStatus]],然后将值赋给新的promise对象。可以在控制台执行下图代码。
var thenable = {
then: function(resolve, reject) {
console.log("thenable");
reject("thenable");
}
};
var testPromiseThenable = new Promise(function(resolve, reject) {
resolve('haha');
}).then(function onFulfilled() {
//返回一个thenable对象
return (thenable);
})

总结:Promise的状态是为了解决then方法传递的回调是等待被执行(函数队列),还是立即执行(函数队列)。Promise的链式操作的需求和每一个promise对象都需要自己的状态,让then方法返回的总是一个新的promise对象。
then方法执行的回调函数执行return 值(参考至Promises/A+。这篇是翻译,个人觉得很棒【翻译】Promises/A+规范,建议文章很简短值得一看)
①var aPromise = new Promise(function(){ resolve(1)}); var testPromise = aPromise.then(null,null)//没有回调函数,新创建的testPromise 对象的[[PromiseStatus]]和[[PromiseValue]]与之前的aPromise 的一样。
②then方法执行的回调函数执行return 值只为普通对象或者原始类型,即将值赋给新创建的promise对象[[PromiseValue]],新创建的promise对象的[[PromiseStatus]]就等于调用then的那个promise对象的[[PromiseStatus]]。
③then方法执行的回调函数执行return值为promise对象,即将promise对象的[[PromiseValue]]和[[PromiseStatus]]赋值给新创建的promise对象对应属性值。
④then方法执行的回调函数执行return值为thenable对象,即执行对象的then方法,根据then方法内部执行resolve或reject确定[[PromiseValue]]和[[PromiseStatus]],赋值给新创建的promise对象对应属性值。

2.2 Promise.prototype.catch
Promise.prototype.catch 只是 promise.prototype.then(undefined, onRejected)方法的一个别名而已。 也就是说,这个方法用来注册当promise对象状态变为Rejected时的回调函数。摘抄至--《javascript Promise迷离书》
promise.prototype.then(onFulfilled, onRejected)中的onRejected是不会处理同级的onFulfilled的函数的错误的,他处理的是前一个promise对象的。传递给Promise.prototype.catch 的参数是一个函数,这个函数主要的作用是处理之前的错误。
⑴.调用catch 干什么?
var testPromiseMistake = new Promise(function(resolve, reject) {
reject("testPromiseMistake")
});
//使用catch 处理错误
var rejectPromiseCatch = testPromiseMistake.catch(function onRejected(value) {
console.log("rejectPromiseCatch:", value)
})
//使用then处理错误
var rejectPromiseThen = testPromiseMistake.then(null, function onRejected (value) {
console.log("rejectPromiseThen:", value)
})
上面用catch和then是等价的。catch就是处理之前的promise抛出的异常。
有的文章中说testMistake.catch是不会执行的,因为前面没有错误抛出,会跳过.catch方法。但testMistake.catch它是执行了的,下图代码中 testMistake 和 testMistakecatch 是不相等的promise对象,可以在控制台输出判断。Promise.prototype.catch 与 promise.prototype.then(undefined, onRejected)方法等价,没有错误时就像执行了then但它的回调函数onFulfilled为null而已。
var testMistake = new Promise(function(resolve, reject) {
resolve("1")
})
var testMistakecatch = testMistake.catch(function(value) {
console.log("Catch:", value)
})
⑵.catch调用后也会产生新的promise

如图catch之后还是可以调用catch或者then方法的。在then函数中怎么显示抛出异常或者在catch中怎么显示抛出异常,让错误可以一直传递下去?(妈蛋,有错误就处理了,还传递个毛线呀)这就是后文中提起的Promise.reject();
对了catch的err来源于上一个Preomise的[[PromiseValue]]值看下图代码。
var haha = {
'xiaobu': 2017,
'data': '6/13'
}
var testC = new Promise(function(resolve, reject) {
reject(haha);
})
// 此处判定
testC.catch(e => {
console.log(e === haha)
})

此处可以在控制台输出true 和 testC,发现testC[[PromiseValue]]值与haha相等。
总结:清楚Promise.prototype.catch 只是 promise.prototype.then(undefined, onRejected)方法的一个别名,懂then的调用那么catch也不是什么新方法了。
2.3 总结
"I'm Captain Jack Sparrow"
看完加勒比海盗好几天,这篇学习笔记还是没写完。愧疚一把,为了结束,就总结为原型上的方法篇吧。
Promise.prototype.catch和promise.prototype.then 是需要认真理解的方法。理解Promise的状态,理解then方法调用会返回新的promise对象等等。
ps. node从7.6版本开始就支持async/await。async/await是一种编写异步的新方法,可以让代码看起来,表现起来更像同步代码……优点一堆值得体验。(当然理解Promise,对理解async/await 是有帮助的)
Promise (2) 基本方法的更多相关文章
- promise(3) '静态'方法
要是人没有梦想,跟咸鱼又有什么两样了?一直恐惧读源码,哪怕是一个简单的库也是读百来行遇到难点就放弃了.对于新的东西也仅仅是知道它拿来干什么,社区资源在哪里,要用时就突击文档资源使用即可.未有过深入之心 ...
- 微信小程序:封装全局的promise异步调用方法
微信小程序:封装全局的promise异步调用方法 一:封装 function POST(url, params) { let promise = new Promise(function (resol ...
- 为Promise添加finally方法支持,把小程序函数变成promise函数
// 为Promise添加finally方法支持 Promise.prototype.finally = function (callback) { let P = this.constructo ...
- 掌握 Promise 的逻辑方法
Promise 是 ES2015 新增的对象 Promise 对象有几个组合方法,可以将多个承诺合并成一个进行处理 分别是 Promise.all, Promise.race, Promise.all ...
- 手写Promise中then方法返回的结果或者规律
1. Promise中then()方法返回来的结果或者规律 我们知道 promise 的 then 方法返回来的结果值[result]是由: 它指定的回调函数的结果决定的 2.比如说下面这一段代码 l ...
- 聊一聊看似简单的Promise.prototype.then()方法
Promise.prototype.then() Proise实例的then方法是定义在原型对象Promise.prototype上的,它的作用是为Promise实例添加状态改变时的回调函数. 该方法 ...
- [Es6]原生Promise的使用方法
参考:https://www.cnblogs.com/imwtr/p/5916793.html 1.new Promise(func) 通过实例化构造函数成一个promise对象,构造函数中有个函数参 ...
- es6语法中promise的使用方法
Promise是一个构造函数,它有resolve,reject,race等静态方法;它的原型(prototype)上有then,catch方法,因此只要作为Promise的实例,都可以共享并调用Pro ...
- 网页视频不能自动播放?HTML5 video报错Uncaught (in promise) DOMException解决方法
话说发哥四年前写了一个网页,如上图效果,实际网址http://pano.z01.com ,话说做好时是正常的,突然某一天,客户说你这个网站动画不见了,这是什么原因? 结果检查脚本一切正常. 其实也不是 ...
随机推荐
- php生成器使用总结
一般我们在迭代一组数据的时候,需要创建一个数据,如果数组很大,则会消耗很大性能,甚至造成内存不足抛出error比如: //Fatal error: Allowed memory size of 134 ...
- druid查询
查询是发送HTTP请求到,Broker, Historical或者Realtime节点.查询的JSON表达和每种节点类型公开相同的查询接口. Queries are made using an HTT ...
- Sql server DATEADD日期函数的使用
DATEADD日期函数 DATEADD() 函数在日期中添加或减去指定的时间间隔. 日:在当前日期上加两天 , ,'2014-12-30') 月:在当前日期上加两个月 , , 年:在当前日期上加两年 ...
- webpack 打包成功,但是css不起作用
问题: webpack 打包成功,但是css不起作用 问题分析/解决: 原因有以下几种 使用了webpack2的语法规则不正确; webpack2要求必须写-loader; 可能是只写了css-loa ...
- AngularJS学习笔记5
11.AngularJS HTML DOM ng-disabled 指令直接绑定应用程序数据到 HTML 的 disabled 属性. <button ng-disabled="my ...
- angular apply
<div ng-controller="firstController"> {{date}} </div> <script> var first ...
- 快速认识HTML及一般标签
HTML(Hype Text Language,超文本标记语言) <html >--开始标签 <head> 网页控制信息 <title>网页标题</title ...
- STM32学习笔记(四)——串口控制LED(中断方式)
目录: 一.时钟使能,包括GPIO的时钟和串口的时钟使能 二.设置引脚复用映射 三.GPIO的初始化配置,注意要设置为复用模式 四.串口参数初始化配置 五.中断分组和中断优先级配置 六.设置串口中断类 ...
- mui开发app之cropper裁剪后上传头像的实现
在大多数app项目中,都需要对用户头像的上传,之前做web开发的时候,我主要是通过input type=file的标签实现的,上传后,使用php对图片进行裁剪,这种方式比较传统简单. 此次app开发中 ...
- 04(2) 基于上下文相关的GMM-HMM声学模型2之参数共享
1.三音素建模存在的问题 问题一:很多三音素在训练数据中没有出现(尤其跨词三音素) 问题二:在训练数据中出现过的三音素有相当一部分出现的频次较少 因此,三音素模型训练时存在较严重的数据不足问题 2.参 ...