对Promise的新的理解

前言

每一次的学习都能感受到新的东西,很开心

初步总结

  1. promise是一个对象,从他可以获取异步操作的消息

  2. promise有两个特点

    1. 对象的状态不受外界影响 有三个状态 pending fullfilled rejected 只有异步操作的结果可以决定当前是哪个状态,任何其他操作都无法改变这个状态
    2. 一旦状态发生改变就不会再次改变 状态的改变只有从pending -> fullfilled pending -> rejected
  3. 它解决了一些回调存在的问题,可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。

  4. 存在着一些缺点

    1. 如果不设置回调函数,外部无法捕捉到内部出现的错误,一般在Promise链的最后添加一个catch函数。

      为什么在最后加呢?

      因为对于一个没有错误处理函数的Promise链,任何错误都会在链中被传播下去,直到注册了错误处理函数

    2. **无法取消 promise ** 一旦新建它就会立即执行,无法取消

    3. 无法得知pending状态 当处于pending状态时,我们无法得知究竟是进行到了哪一步,是刚刚开始还是即将完成。

API

Promise.prototype.catch()

用于指定发生错误时的回调函数

抛出错误的写法有三种

//写法一
			var promise = new Promise((resolve, reject) => {
				throw new Error('test')
			})
			promise.catch(function (error) {
				console.log(error)
			})

//写法二
			var promise = new Promise((resolve, reject) => {
				try {
					throw new Error('test')
				} catch (e) {
					reject(e)
				}
			})
			promise.catch(function (error) {
				console.log(error)
			})

//写法三
			var promise = new Promise((resolve, reject) => {
				reject(new Error('test'))
			})
			promise.catch(function (error) {
				console.log(error)
			})
  • 如果promise的状态已经变成了Resolved,再抛出错误是不会被捕捉的
			var promise = new Promise((resolve, reject) => {
				resolve('ok')
				throw new Error('test')
			})
			promise.then((value) => {
				console.log(value)
			}).catch((error) => {
				console.log(error)
			})

虽然promise在resolve后面抛出了错误,但是由于promise的状态一旦被改变,就会永久保持该状态,不会再改变了,所以错误不会被捕捉,等于没有抛出

  • promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获为止。
//伪代码
getJson('post.json').then(function (post) {
    return getJson(post.commentURL)
}).then(function (comments) {
    //some code
}).catch(function (error) {
    //处理错误
})
  • 如果没有使用catch方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应
			var someAsyncThing = function () {
				return new Promise(function (resolve, reject) {
                    // x没有声明,会报错
					resolve(x + 2)
				})
			}
			someAsyncThing().then(function () {
				console.log('everything is ok')//Uncaught (in promise) ReferenceError: x is not defined
			})


someAsyncThing函数产生的Promise对象会报错。但是由于没有指定catch方法,所以方法不会被捕获,也不会传递给外部代码

Promise.prototype.then()

为Promise实例添加状态改变时的回调函数。 函数形式是fn(value){} value是上一个任务的返回结果。

then中的函数一定要返回一个结果或者一个promise对象才可以让之后的then接收

Promise.race()
var p = Promise.race([p1, p2, p3])

promise.race()情况下,只有有一个实例p率先改变状态,p的状态就跟着改变, 率先改变的Promise实例的返回值就就传递给p的回调函数

如果Promise.race()的参数并不是Promise实例,就会先将其参数转化会Promise对象,再做下一步处理

Promise.all()

用于将多个Promise实例包装成一个新的Promise实例

var p = Promise.race([p1, p2, p3])

p的状态有两种情况

  1. 当p1,p2,p3的状态由pending -> fufilled ,p的状态才会变成fullfilled。此时,p1,p2,p3的返回值组成一个数组,传递给p的回调函数
  2. 当p1,p2,p3中有一个被Rejected,p的状态就会变成Rejected,此时第一个被Rejected的实例的返回值就会传递给p的回调函数
Promise.resolve()★★

根据传入的对象决定返回的是什么

  • 传入的是个promise实例,原封不动地返回这个实例
      function fn (resolve) {
        setTimeout(function () {
          resolve(123)
        }, 3000)
      }
      let p0 = new Promise(fn)
      let p1 = Promise.resolve(p0)
      console.log(p0 === p1) // true

Promise.resolve()传入的参数是promise实例时,Promise.resolve()将不做任何修改,原封不动地返回这个实例。所以p0 === p1

  • 参数是一个thenable对象
      
      let thenable = {
        then: function (resolve, reject) {
          resolve(42)
        }
      }
      let p2 = Promise.resolve(thenable)
      p2.then(function (value) {
        // 当pending -> fullfilled时
        console.log(value)
      })

当Promise.resolve()传入的参数thenable对象(thenable对象指的是具有then方法的对象),会将这个对象转化为promise对象,然后立即执行thenable方法

  • 参数不是具有then方法的对象或者根本不是对象
      let p3 = Promise.resolve('hello')
      p3.then(function(s){
        console.log(s)
      })

如上,参数是一个原始值,Promise.resolve()返回一个新的promise对象 (状态为resolved)

  • 不带有任何参数时
let p4 = Promise.resolve()

当Promise.resolve()不传入任何参数时,会返回一个状态为resolved的promise对象


题目(1)

      function a () {
        setTimeout(() => {
          console.log("1")
        }, 1000);
      }
      function b () {
        setTimeout(() => {
          console.log("2")
        }, 2000);
      }

设计一个promise让先执行b函数,再执行a函数

      function a () {
        setTimeout(() => {
          console.log("1")
        }, 1000);
      }
      function b () {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
          console.log("2")
          resolve()
        }, 2000);
        })

      }
      Promise.resolve().then(function () {
        return b()
      }).then(function () {
         a()
      })

上面那个写的一点都不好,于是重新学了一下promise,不断反思,不断进步

      function a (resolve, reject) {
        setTimeout(() => {
          resolve(console.log("1"))
        }, 1000);
      }
      function b (resolve, reject) {
        setTimeout(() => {
          resolve(console.log("2"))
        }, 2000);
      }
      new Promise(b).then((value) => {
        return new Promise(a)
      })

这样的话其实就是一个很漂亮的方式了, 不足的是我这样子做,要同时更改a,b函数。不知道有没有什么方法可以在不更改a,b函数的情况下,实现呢?

题目(2)

题目一是同学问我的,当时一瞬间的感觉就是,对promise不熟悉 + 其实具体的思路啊什么的都不是很了解,痛定思痛!! 于是通过一个dalao的文章,逐步实现了一下这个方法~~

参考

面试精选之Promise

实现 通知保姆完成以下事情

  1. 去超市购买饭和菜
  2. 用超市买来的菜做饭
  3. 将饭送到媳妇在的公司,媳妇收到后给我发了个么么哒
  4. 保姆给我打电话,我给保姆奖励
  • 定义买饭,做饭,送饭,给保姆奖励函数
      function buyVegetable(resolve, reject) {
        setTimeout(() => {
          resolve(['西红柿', '鸡蛋', '酱油'])
        }, 3000);
      }

      // 定义做饭函数
      function doRice (resolve, reject) {
        setTimeout(() => {
          resolve({
            '主食': '米饭',
            '菜': '西红柿炒蛋'
          })
        }, 3000);
      }

      // 定义送饭到老婆单位
      function sendRice (resolve, reject) {
        setTimeout(() => {
          // 对送完饭的结果做下一步处理
          resolve("老婆的么么哒")
        }, 3000);
      }

      // 给保姆奖钱
      function callme() {
        console.log("给保姆发奖金")
      }
  • 对保姆发布命令,让他一步一步实现
new Promise(buyVegetable)
.then((value) => {
    return new Promise(doRice)
}).then((value) => {
    return new Promise(sendRice)
}).then((value) => {
    return new Promise(callme)
})

题目(3)

题目:红灯三秒亮一次,绿灯一秒亮一次,黄灯2秒亮一次;如何让三个灯不断交替重复亮灯?(用 Promse 实现)

// html
<div id = "box"></div>

// css
      #box{
        width: 50px;
        height: 50px;
        border-radius: 50%;
        background: black;
      }
      var box = document.getElementById("box");
      // 定义三个亮灯函数
      function red () {
        box.style.backgroundColor = 'red'
      }
      function yellow () {
        box.style.backgroundColor = 'yellow'
      }
      function green () {
        box.style.backgroundColor = 'green'
      }
      var light = function(timer, callback) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            callback()
            resolve()
          }, timer);
        })

      }
      var step = function() {
        Promise.resolve().then(function () {
          return light(3000, red)
        }).then(function () {
          return light(2000, yellow)
        }).then(function () {
          return light(1000, green)
        })
      }
  • 插播一个很低级的错误 太久没写了
    <div class="ccircle"></div>
     var ccircle = document.getElementsByClassName("ccircle")
     ccircle.style.backgroundColor = 'red'

这样写的时候一直报错,把我气死了…

[外链图片转存失败(img-Z1MTwzhZ-1569304825279)(D:\2019.5月秋招准备\面试题\promise\1.png)]

但是都不知道凭什么报错, 就把ccircle这个对象输出了一下

[外链图片转存失败(img-UDJUM3oz-1569304825280)(D:\2019.5月秋招准备\面试题\promise\2.png)]

才反应过来!!!可以有无数个元素取ccircle这个类名。所以 他获取完是一个数组对象啊!!! 所以咱们后面要加上[0]

     var ccircle = document.getElementsByClassName("ccircle")[0]

Dom和Bom的概念

这里插播一个面试题, 用友面试的时候被问到了,但是太久没看 记不清了

  • Dom(Document Object Model) 文档对象模型

HTML DOM定义了访问和操作HTML 文档的标准方法

自己的理解就是,

<div id="box"></div>
var box = document.getElementById("#box")
box.innerHTML = "..."

获取这个dom对象,对其进行一个操作

  • Bom(Browser Object Model) 浏览器对象模型

作用:弹出新的浏览器窗口、移动、关闭浏览器窗口及调整浏览器窗口大小

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值