Promise

82 阅读6分钟

一. Promise 是什么

1.1 Promise 理解

抽象表达

(1)Promise 是一门新的技术(ES6规范)

(2)Promise 是 JS 进行异步编程的新的解决方案(旧方案:使用回调函数)

具体表达 (1)语法上来讲 Promise 是一个构造函数 (2)功能上来说 Promise 对象可以封装一个异步操作,获取其结果值(成功/失败),并对结果进行处理

1.2 Promise 的状态改变

  1. pending 变成 resolved
  2. pending 变成 rejected

注:只有这两种,且一个 promise 对象只能改变一次,不论成功/失败,都会有一个结果数据

成功的结果一般称为 value,失败的结果一般称为 reason

Promise 的状态

实例对象中的一个属性 『PromiseState』

内置属性,不能直接对属性操作,结果值如下:

 pending  未决定
 resolved / fulfilled  成功
 Rejected  失败

Promise 对象的值 实例对象中的另外一个属性 『PromiseResult』保存对象,成功/失败 的结果 如下两函数

resolve
reject

注:只有上面两个函数可以对实例对象中 PromiseResult 的值进行修改

let p = new Promise((resolve, reject) => {
  // 成功的值
  resolve('success')
  // 失败的值
  // reject('error')
})

1.3 Promise 的基本流程

promise-基本流程.png

二.为什么要用 Promise

2.1 指定回调函数更加灵活

旧方案:必须在启动异步任务前指定

新方案:启动异步任务 => 返回 Promise 对象 => 给回 promise对象绑定回调函数(可在异步任务结束后指定or多个)

2.2 支持链式调用,可以解决回调地狱问题

回调地狱: 回调函数嵌套使用,外部回调函数异步执行的结果是嵌套的回调函数的条件

回调函数的缺点:不便于阅读,不便于异常处理

promise 链式调用,可以解决回调地狱

三.如何使用 Promise

3.1 API

3.1.1 Promise 构造函数

new 实例化对象, Promeise(excutor){} (1)executor函数:执行器 (resolve, reject) => {} (2)resolve函数:内部定义,成功时调用的函数 value => {} (3)reject函数:内部定义,失败时调用的函数 reason => {} 注:executor 会在 Promise 内部立即同步调用,异步操作会在执行器中执行

// new Promise() 函数的参数被称为执行器函数,内部同步调用
 let p = new Promise((resolve, reject) => {
 	console.log(1)
 })
 console.log(2)

3.1.2 Promise.prototype.then 方法

(onResolved, onRejected) => {} (1)onResolved 函数:成功的回调函数 (value) => {} (2)onRejected 函数:失败的回调函数 (reason) => {} 注:用于得到成功 value 的回调函数,用于得到失败 reason 的回调函数,都返回一个新的 promise 对象

3.1.3 Promise.prototype.catch 方法

(onRejected) => {} onRejected 函数:失败的回调函数 (reason) => {}

let p = new Promise((resolve, reject) => {
	// 执行器函数中 执行reject
  reject('error')
})

p.catch(reason => {
	console.log(reason)
})
// 单独封装 内部也有由 then 方法实现的

3.1.4 Promise.resolve 方法

Promise 的函数对象,不属于实例对象

(value) => {} value:成功的数据 promise 对象

返回一个 成功/失败 的 promise 对象

// 1.传入参数为 非promise类型的对象,返回 成功状态的 promise 对象
let p1 = Promise.resolve('哈哈')
console.log(p1)

// 2.传入参数为 promise对象,参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
  reject('error')
}))
console.log(p2)

3.1.5 Promise.reject

属于 Promise 函数对象,不属于实例对象

(reason) => {} reason:失败的原因,返回一个失败状态的 promise 对象

作用:快速返回一个失败的 promise 对象,失败的值,就是传递进来的值

let p = Promise.reject('666')
let p1 = Promise.reject(666)
let p2 = Promise.reject(new Promise((resolve, reject) => {
    resolve('
	resolve('success')
}))
// 始终返回一个失败的 promise 对象,失败的值,是传递进来的值
console.log(p, p1, p2)

3.1.6 Promise.all

属于 Promise 函数对象 (promise) => {} promises:包含 n个 promise 对象

注:返回一个新的 promise,只有所有的 promise 都成功才成功,有一个失败就失败

let p1 = new Promise((resolve, reject) => {
    resolve('success')
})
let p2 = Promise.resolve('ok1')
let p3 = Promise.resolve('ok2')

// 三个都成功,是三个成功的结果值  数组
let result1 = Promise.all([p1, p2, p3])
console.log(result1)

let p4 = Promise.reject('失败1')
let p5= Promise.reject('失败2')

// 返回失败的 promise 对象值,且是第一个失败的值
 const result2 = Promise.all([p1, p4 p5])
 console.log(result2)

3.1.7 Promise.race

属于 Promise 函数对象 (promise) => {} promises:包含 n个 promise 对象 注:返回一个新的 promise,第一个完成的 promise 的结果状态就是最终结果的状态

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
            resolve('success')
    }, 100)
})
let p2 = Promise.resolve('ok')
let p3 = Promise.resolve('成功')

// 第一个完成的 promise 的结果状态就是最终的结果状态
const result = Promise.race([p1, p2, p3])
console.log(result)

3.2 promise 关键问题

3.2.1 promise 如何修改状态

(1)resolve(value) 如果当前是 pending,会变成 resolved

(2)reject(value) 如果当前是 pending,会变成 rejected

(3)抛出异常 如果当前是 pending,会变成 rejected

3.2.2 能否执行多个回调

当 promise 状态改变时,指定的多个成功/失败的回调函数,都会调用

let p = new Promise((resolve, reject) => {
    // 状态改变,都会调用
    resolve('success')
})
// 回调 1
p.then(value => { console.log(111) })
// 回调 2
p.then(value => { console.log(222) })

3.2.3 改变 Promise 状态、指定回调函数谁先执行

都有可能

情况一:先执行 resolve 改变状态,后执行回调函数

// 执行器函是任务是同步任务
let p = new Promise((resolve, reject) => {
    resolve('success')
})
p.then(value => {
    console.log(value)
}, reason => {})

情况二:then() 方法先执行,改变状态后执行(实际居多)

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('success')
    }, 1000);
});
p.then(value => {
    console.log(value)
}, reason => {});

1. 如何先改变状态,再指定回调函数

(1)执行器函数直接调用 resolve() / reject()

(2)延长更长时间再调用 then()

2. 什么时候得到数据(回调函数什么时候执行)

(1)先指定回调,状态发生改变时,回调函数就会调用,得到数据

(2)先改变状态,指定回调时,回调函数就会调用,得到数据

3.2.4 then() 方法返回的新的 promise 结果状态由什么决定

简单描述:由 thn() 指定的回调函数执行结果决定

详细描述:

(1)抛出异常,新 promise 状态变成 rejected

let p = new Promise((resolve, reject) => {
    resolve('ok');
});
p.then(value => {
    throw '404
}, reason => {})

(2)返回的是promise 的任意值,状态为 resolved,value 为返回值

(3)返回新 promise,此 promise的结果为新的 promise 结果

3.2.5 promise 如何串联多个操作任务

promise 的 then() 返回一个新的 promise(链式调用),可以实现

// 状态改变后,执行回调函数,在执行回调函数...
let p = new Promise((resolve, reject) => {
  setTimeout(() => {
      resolve('OK');
  }, 1000)
})

p.then(value => {
  return new Promise((resolve, reject) => {
      resolve('success')
  }).then(value => {
  	// success
      console.log('1 =>', value)
  }).then(value => {
  // undefind
  // 状态由指定的回调函数返回值决定,状态没写,所以结果是undfind
  	console.log('2 =>', value)
  })
})

3.2.6 promise 异常穿透

(1)使用 romise 的 then 链式调用时,可以在最后指定失败的回调

(2)前面任何操作出现异常,都会传递到最后失败的回调中处理

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('ok')
        // reject('error')
    }, 1000)
});

p.then(value => {
    // console.log(111)
    throw '失败了'
}).then(value => {
    console.log(222)
}).then(value => {
    console.log(333)
}).catch(reason => {
    console.warn(reason)
})

3.2.7 中断 promise 链

有且只有一种方式:return 一个 pending 状态的 promise 对象

let p = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('ok')
        // reject('error')
    }, 1000)
});

p.then(value => {
    console.log(111)
    // 返回 pending 状态 promise
    return new Promise(() => {})
}).then(value => {
    console.log(222)
}).then(value => {
    console.log(333)
}).catch(reason => {
    console.warn(reason)
})