回顾promise

218 阅读3分钟

以前我们经常这么写异步回调:

step1(function(val1) {
	step2(function(val2) {
		step3(function(val3){
			// ...嵌套再嵌套
		})
	})
})

这种三角形代码缺陷显而易见:

  1. 代码不优雅,阅读费劲
  2. 难以维护,俗称回调地狱

然后我们应用es6中promise:

new Promise(step1())
.then(step2())
.then(step3())
// 。。。是不是很帅?

promise以同步的方式来写异步,不用担心错过某个事件或信号,它是等上一个异步操作有结果了再执行它所寄存的下一个操作

几个需要注意的点:

  1. promise有三种状态 等待(pending)、已完成(fulfilled)、已拒绝(rejected)
  2. promise的状态只能从“等待”转到“完成”或者“拒绝”,不能逆向转换,同时“完成”和“拒绝”也不能相互转换
  3. promise必须有一个then方法,并且要返回一个promise对象,供then的链式调用
  4. then接受两个回调(成功与拒绝),在相应的状态转变时触发,回调可返回promise,等待此promise被resolved后,继续触发then链

##基本用法

ES6的promise对象是一个构造函数,用来生成promise实例。

var promise =  new Promise((resolve, reject) => {
    if (/* 异步操作成功 */) {
      resolve(value)
    } else {
      reject(error)
    }
})
promise.then(onFulfilled,onRejected).then(onFulfilled,onRejected)

这是我们项目中常用的方法,大家并不陌生。但还是说一下大概原理,Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resovle和reject方法。异步操作成功时,则用resolve方法将promise对象的状态改为“成功”;异步操作失败时,则用reject方法将状态改为“失败”。 promise实例生成以后,then传入回调,这里 的函数并不会立即执行而是加入队列,等待未来resolve或reject时触发执行。

###Promise.prototype.then()

function getPromise(n) {
  return new Promise((resovle, reject) => {
    if(n <= 100) {
      resovle(n)
    } else {
      reject('请传入100以内的数值!')
    }
  })
}

首先我先实例化一个Promise,之后介绍的方法都调用此函数作为例子

getPromise(1).then((a) => {
  return a + 1
}).then((b) => {
  console.log(b)
})
// 结果:2 2
then方法依次指定了两个函数,第一个回调函数返回的值传递给下一个函数作为参数。这种设计使得嵌套的异步操作得以改写。

###Promise.prototype.catch()

Promise.prototype.catch方法是Promise.prototype.then(null, rejection)的别名,用于指定发生错误时的回调函数。

getPromise(101).then((value) => {
  console.log(value)
}).catch((error) => {
  console.log(error)
})
// 结果:请传入100以内的数值!

###Promise.all()

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

接受一个数组作为参数 p1,p2,p3都是Promise对象的实例 p的状态由p1,p2,p3决定 返回为一个新的promise实例 先个例子吧:

var p = [1, 2, 3].map((time) => {
  return getPromise(time)
})
Promise.all(p).then((arrs) => {
  console.log(arrs)
})
// 结果:[1,2,3]

###Promise.race()

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

race与all方法不同之处在于p1,p2,p3之中有一个实例率先改变状态,p的状态就跟着改变。率先改变的Promise实例的返回值,就传递给p的回调函数。这里例子就不写了,有兴趣的同学可以去试试。

###Promise.resolve()与Promise.reject()

这两个方法的特色之处是将其参数转换成一个新的Promise对象

###错误的观念

有一次我看到有个人的代码里这么用promise, 那一刻我怀疑自己的眼睛瞎了,虽然结果没有什么问题,但是思想没有转变,还是原来的传统回调思想,失去了使用promise的意义

来看一下错误的写法:

// 错误的写法
getPromise(1)
  .then((a) => {
    console.log(a)
    return getPromise(a+1)
      .then((b) => {
        console.log(b)
        return getPromise(b+1)
          .then((c) => {
            console.log(c)
          })
      })
})
//结果:1
//     2
//     3
// 正确的写法
getPromise(1)
  .then((a) => {
    console.log(a)
    return a+1
  })
  .then((b) => {
    console.log(b)
    return b+1
  })
  .then((c) => {
    console.log(c)
    return c+1
  })
//结果:1
//     2
//     3