Promise入门到自定义
一. 准备
1.什么是回调函数?
回调只是使用JavaScript函数的惯例的名称。 JavaScript语言中没有特别的东西叫做“回调”,它只是一个约定。「不像大多数函数那样立即返回一些结果」,「使用回调函数需要一些时间来产生结果」。 “异步”这个词,”,意思是“需要一些时间”或“将来会发生,而不是现在”。通常回调仅在进行I / O时使用,例如下载东西,阅读文件,与数据库交互等
2.回调函数的分类
- 同步回调
- 理解: 立即执行, 全部执行完了才结束, 不会放入回调队列中
- 例子: 数组遍历相关的回调函数 / Promise的 executor 函数
- 异步回调
- 理解: 不会立即执行, 会放入回调队列中来执行
- 例子: 定时器回调 / ajax回调 / Promise的成功|失败的回调
- 简单来理解就是:同步按你的代码顺序执行,异步不按照代码顺序执行,异步的执行效果更高
3.JS中的error处理
错误的类型
Error
: 所有错误的父类型ReferenceError
: 引用的变量不存在TypeError
: 数据类型不正确的错误RangeError
: 数据值不在其所允许的范围内SyntaxError
: 语法错误
错误处理
- 捕获错误:
try...catch(error){}
- 抛出错误:
throw error
- 捕获错误:
error对象属性
message
属性: 错误的相关信息stack
属性: 函数调用栈记录信息
二. Promise理解和使用
1.Promise是什么
❝
Promise
是异步编程的一种解决方案, 解决「回调地狱」, 主通常用来标识一个异步操作的最终完成 (或失败)从语法上来说:
promise
是一个对象, 用它可以获取异步操作的消息从功能上来说:
❞promise
对象用来封装一个异步操作, 并可以获取成功/失败的结果
function asyncFunction() {
return new Promise((resolve, reject) => { /* executor */
setTimeout(() => {
resolve('Async Hello world')
}, 16);
})
}
asyncFunction().then(value => {
console.log(value) // Async Hello world
})
.catch(err => {
console.log(err)
})
2.Promise的状态
- 用
new Promise
实例化的promise对象有以下三个状态pending
(进行中)- 等待状态, 比如正在进行网络请求, 或者定时器没有到时间
resolved
(已成功)又名fulilled
- 成功状态, 当我们主动回调了resolve 时, 就处于该状态并且会回调.then()
rejected
(已失败)- 失败状态, 当我们主动回调了 reject 时, 就处于该状态并且会回调.catch()
- 「promise的状态改变」
- 1.从
pending
变化resolved
- 2.从
pending
变化rejected
- 说明: 「只有可能这两种状态」, 「且状态状态改变后, 就不会在再发生任何变化」
- 1.从

Promise对象特点
- 「对象的状态不受外界影响」, 只有异步操作的结果, 可以决定当前是哪一种状态, 任何其他操作都无法改变这个状态
- 「一旦状态改变, 就不会再变, 任何时候都可以得到这个结果」
3.Promise的优点和缺点
优点
- 有了
Promise
对象, 就可以将异步操作以同步的流程表达出来, 避免了层层嵌套的回调函数 Promise
对象提供统一的接口, 使控制异步操作更加容易
- 有了
缺点
- 首先, 无法取消
Promise
, 一旦新建它就会立即执行, 无法中途取消 - 其次, 如果不设置回调函数,
Promise
内部会抛出错误, 不会反映到外部 - 当处于
pending
状态时, 无法得知目前进展到哪一个阶段 (刚刚开始还是即将完成)
- 首先, 无法取消
4.Promise API
实例方法
❝
Promise
构造函数:Promise (excutor)
❞
excute
函数: 同步执行器(resolve, reject) => { }
resolve
函数: 将异步操作成功的value
传递并调用reject
函数: 将异步操作失败的reason
传递并调用
❝Promise.prototype.
then(onResolved, onRejected)
❞
onResolve
函数: 成功时的回调函数(value) => { }
onRejected
函数: 失败的回调函数(reason) => {}
- 说明: 得到成功 value 的回调和得到失败 reason 的回调, 会返回一个新的promise对象
❝Promise.prototype.
catch(onRejected)
❞
onRejected
函数: 失败的回调函数- 说明: .then()的语法糖, 相当于: then(undefined, onRejected)
静态方法/函数对象方法
❝
Promise.resolve(value)
value
: 成功的数据或promise对象- 说明: 返回一个成功/失败的 promise 对象
Promise.reject(reason)
❞
reason
: 失败的原因- 说明: 返回一个状态失败的 Promise 对象, 并将给定的失败信息传递给对应的处理方法
❝
Promise.all([promise,..])
- 参数: 数组中传递promise对象
- 数组中promise对象状态
- 只要「数组传递中」的promise对象状态全部成功才返回成功状态的promise对象, 并将成功的 values 以数组传递
- 只要有一个失败了就回返回失败状态的promise对象, 并将数组其中具体失败promise对象的 reason 信息传递
- 返回值: 返回新的 promise 对象
- 注意: 返回数据的顺序以 promise 数组顺序一致
Promise.race([promise,..])
❞
- 参数: 数组中传递promise对象
- 数组中promise对象状态
- 以数组传递的 promise 对象, 第一个完成 promise 的结果状态就是最终的结果状态
- 「返回的结果」就是数组中Promise对象第一个状态的 value 或 reason
- 返回值: 返回新的 promise 对象
- 注意: 以数组中最先返回结果状态的promise对象为最终结果
5.Promise 几个关键问题
1.如何改变promise的状态
- resolve(value) : 如果当前是 pending 就会变为 resolved
- reject(reason) : 如果当前是 pending 就会变为 rejected
- 抛出异常: 如果当前是 pending 就会变为 rejected
2.一个promise指定多个成功/失败回调, 会调用吗?
- 当 promise 改变对应的状态时, 对应状态的回调都会调用
3.改变promise状态和指定回调函数谁先谁后?
- 都有可能, 正常情况下是先指定回调函数再改变状态, 但也可以先改变状态再指定回调函数
- 如何先该状态再指定回调?
- 在指定器中直接调用 resolve()/reject()
- 延迟更长时间才调用 then()
- 什么时候才得到数据?
- 如果先指定的回调, 那当状态发生改变时, 回调函数就会放入队列中调用, 得到数据
- 如果改变的状态, 当指定回到函数时, 回调函数就会放入列中中调用, 得到数据
4.promise.then()返回新的promise对象结果状态由什么决定?
- 简单说明: 由then()里指定的回调函数, 执行结果决定
- 详细说明:
- ①如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
- ②如果返回的是非promise 的任意值, 新 promise 变为 resolve, value 为返回的值
- ③如果返回的是另一个新 promise , 此 promise 的结果就会成为新 promise 的结果
5.promise如何串连多个操作任务?
- promise 的 then() 返回一个新的 promise, 可以看成 then() 的链式调用
- 通过 then 的链式调用串连多个同步/异步任务
6.promise异常穿透?
- 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调
- 前面任何操作出了异常, 都会传到最后失败的回调中处理
- reason是以此进行传递的, 你没有指定 reason 回调, 默认是将 reason throw 抛出了
7.如何中断promise链?
- 当使用 promise 的 then 链式调用时, 在中间中断promise链, 后续的回调函数不会再调用
- 方法: 在回调函数中「返回一个 pending 状态的 promise 对象」
6.Promise基本流程

三. 自定义Promise
1.整体结构思路

2.自定义Promise_class版本
/*
自定义Promise模块
class版本
*/
(function (window) {
const PENDING = 'pending' // 初始化未确认的状态
const RESOLVED = 'resolved' // 成功状态
const REJECTED = 'rejected' // 失败状态
class Promise {
/**
* 通常执行异步任务 usual execute async task
* @param {function} execute 同步执行器函数
*/
constructor(execute) {
// 初始化属性
const self = this // Promise的实例对象
self.status = PENDING // 状态属性,初始状态为pending
self.data = undefined // 用来存储结果数据的属性,初始值为undefined
self.callbacks = [] // 保存then()传递的回调函数
/**
* 将promise状态改为成功,指定成功的value
* @param {any} value
*/
function resolve(value) {
// 如果当前不是pending状态直接结束
if (self.status !== PENDING) return
self.status = RESOLVED // 改变为成功状态
self.data = value // 数据存储
// 异步调用所有缓存的待执成功的回调函数
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value)
})
})
}
}
/**
* 将promise状态改为失败,指定失败的reason
* @param {any} reason 失败的reason
*/
function reject(reason) {
// 如果当前不是pending状态直接结束
if (self.status !== PENDING) return
self.status = REJECTED
self.data = reason
// 异步调用所有缓存的待执失败的回调函数
if (self.callbacks.length > 0) {
setTimeout(() => {
self.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason)
})
})
}
}
// 调用execute来启动异步任务
try {
// 如果同步执行器函数抛异常
execute(resolve, reject)
} catch (error) {
// 改变失败状态,并将失败信息传递
reject(error)
}
}
/* then()主要功能执行传递的回调或保存回调
用来指定成功/失败的回调函数
1. 如果当前promise是resolved,异步执行成功的回调函数onResolved
2. 如果当前promise是rejected,异步执行失败的回调函数onRejected
3. 如果当前promise是pending,保存回调函数
返回一个新的promise对象
它的结果状态由onResolved或onRejected执行的结果决定
2.1 抛出error ==> 变为rejected,结果值为error
2.2 返回值不是promise ==> resolved,结果值为返回值
2.3 返回值是promise ==> 由这个promise决定新的promise的结果(成功/失败)
*/
then(onResolved, onRejected) {
const self = this
//onResolved的默认值
onResolved = typeof onResolved === 'function' ? onResolved : (value) => value
// onRejected的默认值,如果没有传递
onRejected = typeof onRejected === 'function' ? onRejected : (reason) => { throw reason } //将reason向下传递
// 返回新的promise对象,状态由onResolve或onRejected回调来决定
return new Promise((resolve, reject) => {
/**
* 调用指定的回调函数callback
* 根据callback执行结果来更新then()返回promise的状态
* @param {function} callback 要调用的回调函数
*/
function handle(callback) {
try {
// 执行成功的异步回调
const result = callback(self.data)
if (result instanceof Promise) {
result.then(
value => resolve(value),
reason => reject(reason)
)
// result.then(resolve, reject)
} else {
resolve(result)
}
} catch (error) {
reject(error)
}
}
// RESOLVED状态
if (self.status === RESOLVED) {
// 异步调用onResolved
setTimeout(() => {
handle(onResolved)
})
// REJECTED状态
} else if (self.status === REJECTED) {
setTimeout(() => {
handle(onRejected)
})
}
/* PENDING状态,保存传递自定义的的回调, 因为直接将then()传递的回调保存起来时, 后面
resolve或reject调用的时候 返回的promise状态 一直是PENDING状态, 后面链式调用
没有效果的 */
else {
self.callbacks.push({ // 不是直接成功/失败的回调,保存包含了回调函数调用的函数
onResolved(value) { // 在后面调用resolve()中执行
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
}
})
}
/**
* 用来指定失败的回调函数
* catch是then的语法糖
* @param {function} onRejected 失败的回调
*/
catch (onRejected) {
return this.then(undefined, onRejected)
}
/**
* value可能是一个一般的值,也可能是promise对象
* @param {any} value
*/
static resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
/**
* 用来返回一个指定reason的失败的promise
* @param {function} reason
*/
static reject = function (reason) {
return new Promise((resolve, reject) => {
reject(reason)
})
}
/**
* 返回一个promise对象,对象的状态由传递过来的promise数组来决定,只有全部成功才返回成功状态的promise
* @param {Array} promises
*/
static all = function (promises) {
let resolveCount = 0 // 已经成功的数量
let values = new Array(promises.length) // 用来保存成功promise的value值
return new Promise((resolve, reject) => {
// 遍历所有promise,取其对应的结果
promises.forEach((p, index) => {
p.then(
value => {
// 如果判断传递promise数组全部成功? 计数
resolveCount++
values[index] = value
if (resolveCount === promises.length) { // 全部成功了
resolve(values)
}
},
reason => {
reject(reason)
}
)
})
})
}
/**
* 返回一个promise,对象的状态由传递的promise数组来决定,第一个返回状态的promise就是最终结果
* @param {Array} promises
*/
static race = function (promises) {
return new Promise((resolve, reject) => {
// 遍历所有promise,取其对应的结果
promises.forEach(p => {
// 返回的promise由第一个完成p来决定其结果
p.then(resolve, reject)
})
})
}
/**
* 延迟指定的时间才执行成功(或失败的)的promise
* @param {function} value
* @param {number} time
*/
static resolveDelay = function (value, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
}, time);
})
}
/**
* 延迟指定的时间才执行失败的promise
* @param {function} value
* @param {number} time
*/
static rejectDelay = function (reason, time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason)
}, time);
})
}
}
window.Promise = Promise
})(window)