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常用的优化手段
由于工作码成狗,抽闲整理了下内容,以下是网上流传比较广泛的30种SQL查询语句优化方法: 1.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描. ...
- Asp .net core api+Entity Framework 实现数据的存取到数据库中
最近在学dotNetCore 所以尝试了一下api 这个功能 不多说了大致实现如下 1.用vs2017建立一个Asp.net Core Web 应用程序 在弹出的对话框中选择 Web API 项目名 ...
- cookie方法封装及cookie缺点分析
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Consolas; color: #4f5d66 } p.p2 { margin: 0.0px ...
- Virtualbox mac版centos7.2 安装共享文件夹
因为用的是mac本,在自己电脑上用virtualbox安装了centos7.2 虚拟机,为了实现与本机交换文件,需要用到贡享文件夹功能. 网上搜的时候多是windows版的,所以自己写一个mac版的. ...
- PHP 分支与循环
一.概述: 上面一章我们讲解了PHP当中的运算符和表达式,通过上面的知识点我们就可以完成一些基本的运算操作了.但是涉及到一些比较复杂的逻辑,分支与循环就必不可少了.通过分支和循环的结合使用可以使业务更 ...
- EverythingAboutJava
1 GC gabage collection 垃圾回收Java GC系列(1):Java垃圾回收简介 http://mp.weixin.qq.com/s?src=3×tamp=149 ...
- hibernate 使用 hibernate tool 生成配置文件和实体类
安装Hibernate插件 下载所需的Hibernatetools http://www.hibernate.org/6.html 将下载得到的文件解压得到的features和plugins文件夹, ...
- Python 基础 四 面向对象杂谈
Python 基础 四 面向对象杂谈 一.isinstance(obj,cls) 与issubcalss(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls ...
- PHP的学习记录
这是我的第一次写博客,是一个PHP的初学者,刚刚开始之前是一点儿的都不懂,现在开始通过买些书籍回来学习,废话少说,开始记录笔记吧. 函数:函数的英文名为function,也就是功能的意思,在自定义函数 ...
- swap与dd命令使用详解
处理交换文件和分区 交换分区是系统RAM 的补充 基本设置包括: 创建交换分区或者文件 使用mkswap 写入特殊签名 在/etc/fstab 文件中添加适当的条目 使用swapon -a 挂载交换分 ...