"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简体实现结构大概是:

  1. //Promise构造函数实现的大概结构
  2. function Promise(resolver) {
  3. //promise 的初始状态
  4. this._PromiseStatus = 'pending';
  5. //promise 的value 值(不同实现这个属性名字不一样)
  6. this._PromiseValue = undefined
  7. //......接下来要实现的此处省略
  8. }
  9.  
  10. //给Promise添加方法
  11. Promise.all = all;
  12. Promise.race = race;
  13. Promise.resolve = resolve;
  14. Promise.reject = reject;
  15.  
  16. //重写Promise构造函数原型
  17. Promise.prototype = {
  18. constructor: Promise,
  19. then: then,
  20. catch: catch
  21. };
  22.  
  23. //方法具体实现
  24. function all( /***/ ) {
  25.  
  26. }
  27. // ......方法实现省略

使用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对象需要状态?

  1. var testPromiseStatus = new Promise(function(resolve, reject) {
  2. //异步操作......成功后执行了resolve(1)
  3. getdata((data) => {
  4. resolve(data);
  5. })
  6. })
  7.  
  8. setTimeout(() => {
  9. //从创建了testPromiseStatus,在到执行testPromiseStatus.then中间的时间间隔不确定
  10. testPromiseStatus.then(function onFulfilled(value) {
  11. console.log("我到底应该什么时候执行呀?");
  12. })
  13. },一个不确定的时间)

需要一个状态位去标志,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对象?

  1. var aPromise = new promise(function(resolve, reject) {
  2. resolve("test chain");
  3. });
  4. aPromise.then(function taskA(value) {
  5. // task A
  6. }).then(function taskB(vaue) {
  7. // task B
  8. })

返回新的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对象。可以在控制台执行下图代码。

  1. var thenable = {
  2. then: function(resolve, reject) {
  3. console.log("thenable");
  4. reject("thenable");
  5. }
  6. };
  7. var testPromiseThenable = new Promise(function(resolve, reject) {
  8. resolve('haha');
  9. }).then(function onFulfilled() {
  10. //返回一个thenable对象
  11. return (thenable);
  12. })

总结: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 干什么?

  1. var testPromiseMistake = new Promise(function(resolve, reject) {
  2. reject("testPromiseMistake")
  3. });
  4. //使用catch 处理错误
  5. var rejectPromiseCatch = testPromiseMistake.catch(function onRejected(value) {
  6. console.log("rejectPromiseCatch:", value)
  7. })
  8. //使用then处理错误
  9. var rejectPromiseThen = testPromiseMistake.then(null, function onRejected (value) {
  10. console.log("rejectPromiseThen:", value)
  11. })

上面用catch和then是等价的。catch就是处理之前的promise抛出的异常。

有的文章中说testMistake.catch是不会执行的,因为前面没有错误抛出,会跳过.catch方法。但testMistake.catch它是执行了的,下图代码中 testMistake  和 testMistakecatch 是不相等的promise对象,可以在控制台输出判断。Promise.prototype.catch 与 promise.prototype.then(undefined, onRejected)方法等价,没有错误时就像执行了then但它的回调函数onFulfilled为null而已。

  1. var testMistake = new Promise(function(resolve, reject) {
  2. resolve("1")
  3. })
  4. var testMistakecatch = testMistake.catch(function(value) {
  5. console.log("Catch:", value)
  6. })

 ⑵.catch调用后也会产生新的promise

如图catch之后还是可以调用catch或者then方法的。在then函数中怎么显示抛出异常或者在catch中怎么显示抛出异常,让错误可以一直传递下去?(妈蛋,有错误就处理了,还传递个毛线呀)这就是后文中提起的Promise.reject();

对了catch的err来源于上一个Preomise的[[PromiseValue]]值看下图代码。

  1. var haha = {
  2. 'xiaobu': 2017,
  3. 'data': '6/13'
  4. }
  5.  
  6. var testC = new Promise(function(resolve, reject) {
  7. reject(haha);
  8. })
  9. // 此处判定
  10. testC.catch(e => {
  11. console.log(e === haha)
  12. })

此处可以在控制台输出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) 原型上的方法的更多相关文章

  1. JavaScript数组方法总结,本文是根据数组原型上的方法进行总结,由于方法太多将会分篇章发布

    通过浏览器控制台 console 可查看到 Array 数组上原型的所有方法(如下图).对于原型问题此文章暂不过多叙述,单针对对象中的方法进行自我看法的总结:细心的同学可以发现对象原型上所携带的方法基 ...

  2. call()和原型继承的方法

    1.call() call()方法接受两个参数,obj和arg 比如functionA.call(obj,arg)   就是说现在运行(执行)functionA这个方法,但是functionA里面的方 ...

  3. 基于原生JS封装数组原型上的sort方法

    基于原生JS封装数组原型上的sort方法 最近学习了数组的原型上内置方法的封装,加强了用原生JS封装方法的能力,也进一步理解数组方法封装的过程,实现的功能.虽然没有深入底层,了解源码.以下解法都是基于 ...

  4. 3分钟教会你把封装的js公共方法挂载在vue实例原型上

    第一步:首先在src文件夹里面创建一个通用js文件夹,然后在创建的文件夹里面创建一个js文件 第二步:const 一个方法,然后通过export暴露出来(在同一个页面可以写多个方法,和暴露多个方法,在 ...

  5. JavaScript利用数组原型,添加方法实现遍历多维数组每一个元素

    原型就是提供给我们为了让我们扩展更多功能的. 今天学习了用js模拟底层代码,实现数组多维的遍历.思想是在数组原型上添加一个方法. // js中的数组forEach方法,传入回掉函数 能够帮助我们遍历数 ...

  6. jq源码解析之绑在$,jQuery上面的方法

    1.当我们用$符号直接调用的方法.在jQuery内部是如何封装的呢?有没有好奇心? // jQuery.extend 的方法 是绑定在 $ 上面的. jQuery.extend( { //expand ...

  7. 六.jQuery源码分析之jQuery原型属性和方法

    97 jQuery.fn = jQuery.prototype = { 98 constructor: jQuery, 99 init: function( selector, context, ro ...

  8. react-native-pg-utils(对react-native全局进行配置,对内置对象原型链增加方法,增加常用全局方法.)

    react-native-pg-utils 对react-native全局进行配置,对内置对象原型链增加方法,增加常用全局方法. 每次新建react-native项目之后都会发现有一些很常用的方法在这 ...

  9. ES6 class 语法糖不能直接定义原型上的属性

    今天注意到两个东西: 1.为了模拟面向对象,JavaScript的class语法糖屏蔽了原型的概念 class A{ a = 1   // 注意!!这里定义的不是在prototype上的属性,而是给实 ...

随机推荐

  1. vue入门知识点

    最近入坑vue 做一点小的记录 有不对的 辛苦指出 会第一时间更改上新 0.利用vue-cli构建项目新建一个目标文件夹 ,全局安装vue-cli脚手架工具 (全局安装一次即可) npm instal ...

  2. Kubernetes国内镜像、下载安装包和拉取gcr.io镜像

    参考:  https://blog.csdn.net/nklinsirui/article/details/80581286

  3. 一个div实现白眼效果

    巧妙利用border和background-clip   <div class="eye"></div> .eye{ width:150px; height ...

  4. mfc简单框架的分析和原理记录

    由于最近在准备考试,可能博客的更新有点慢(呵,我又为自己的懒惰和拖延找借口,总之有时间就更新) 一.菜单 1.在windows中,菜单资源的识别通过HMENU句柄识别 ,但是这个开发过程比较繁琐 2. ...

  5. day14_dom操作

    1.input的类型typy=(text/password/button/submit/checkbox/radioreset/file) 一.参考:http://www.imdsx.cn/index ...

  6. __x__(34)0908第五天__ 定位 position

    position 定位 指将原始摆放到页面的任意位置. 继承性:no 默认值:static        没有定位,原始出现在正常的文档流中 可选值: static :    默认值,元素没有开启定位 ...

  7. [LeetCode] Similar RGB Color 相似的红绿蓝颜色

    In the following, every capital letter represents some hexadecimal digit from 0 to f. The red-green- ...

  8. Git 经常用到的命令

    1.克隆master分支之外的分支: 首先克隆项目 1>Git clone git@192.168.0.201:frontend/mn.git 然后转换到克隆下来的文件夹 2>cd 文件名 ...

  9. [Codeforces Round #438][Codeforces 868C. Qualification Rounds]

    题目链接:868C - Qualification Rounds 题目大意:有\(n\)个题目,\(k\)个人,每个人可能做过这\(n\)个题里的若干道,出题方要在这\(n\)个题目里选若干个出来作为 ...

  10. Git飞行规则

    原文链接 Git飞行规则(Flight Rules)