Promise学习笔记
参考视频教程
知识铺垫
函数对象和实例对象
- 函数对象:将函数作为对象使用
- 实例对象:new 函数产生的对象(执行构造函数)
只有在new出实例对象之后,函数才能叫做构造函数
function Person() {
}
var p = new Person();
console.log(Person.prototype)
在这段代码中p是实例对象,Person是构造函数,打印Person原型时,Person是函数对象
回调函数
同步回调:立即执行,完全执行完了才结束,不会放入回调队列
异步回调:不会立即执行,放入回调队列中将来执行
const arr = [1, 2, 3];
arr.forEach(item => {
console.log(item);
});
console.log('foreach之后');
setTimeout(() => {
console.log('callback');
}, 0);
console.log('setTime之后');
上面一段是同步回调,按照顺序执行;下面一段是异步函数,放到队列中执行,主线程执行完毕之后才执行
错误处理
错误的类型
- Error: 所有错误的父类型
- ReferenceError: 引用的变量不存在
- TypeError: 数据类型不正确的错误
- RangeError: 数据值不在其所允许的范围内
- SyntaxError: 语法错误
错误处理
- 捕获错误: try … catch
- 抛出错误: throw error
错误对象
- message属性: 错误相关信息
- stack属性: 函数调用栈记录信息
Promise理解和使用
什么是Promise
抽象表达:
- Promise是JS中进行异步编程的新的解决方案(旧的是谁?纯回调callback)
具体表达:
- 从语法上来说: Promise是一个构造函数
- 从功能上来说: promise对象用来封装一个异步操作并可以获取其结果
promise的状态改变(只有2种结果,,只能改变一次)
- pending变为resolved
- pending变为rejected
- 无论成功还是失败都会有一个 结果,成功的称为value,失败的称为reason
promise的基本流程(pending,图里面写错了)
为什么使用Promise
- 指定回调函数的方式更加灵活:可以在请求发出甚至结束后指定回调函数
- 支持链式调用,可以解决回调地狱问题
怎么使用Promise
简单的示例
const p = new Promise((resolve, reject) => {
const d = Date.now();
if (d % 2 === 1) {
resolve('success')
} else {
reject('faild')
}
})
p.then(value => console.log(value), reason => console.log(reason))
.then()接收两个函数,第一个是成功的回调(onResolved),第二个是失败的回调(onRejected)
主要API
- Promise构造函数: Promise (excutor) {}
- Promise.prototype.then方法: (onResolved, onRejected) => {}
- Promise.prototype.catch方法: (onRejected) => {},拦截失败操作,返回promise对象,如果catch之前有reject,直接跳到reject,中间所有的.then都不执行
- Promise.resolve方法: (value) => {},修改状态为成功
- Promise.reject方法: (reason) => {},修改状态为失败
- Promise.all方法: (promises) => {},参数为一个可迭代对象,等所有的promise对象都完成之后状态变为resolved,返回结果可迭代对象;如果过有失败结果,状态变为rejected,失败原因是第一个失败的promise对象的结果
- Promise.race方法: (promises) => {},参数为一个可迭代对象,如果有任何一个promise解决或者拒绝,返回的promise就会解决或者拒绝
存在的问题
- 改变状态不一定是resolve和reject,也可以发生错误或者抛出异常
- 同一个promise对象添加多个.then都会执行
- 改变promise状态和指定回调函数谁先谁后
- 正常情况下是先指定回调函数再改变状态
- 先改变状态再指定回调:①在执行器中直接调用resolve()/reject()②延迟更长时间才调用then()
- 什么时候得到数据
- 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
- 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
- 不论成功失败,回调函数永远是异步执行
- .then返回promise的状态——由指定的回调函数执行的结果决定
- 抛出异常,新的promise变为rejected,reason为抛出的异常
- 返回的是非promise任意值,状态改为resolved,value是返回值
- 返回值是一个新的promise,这个promise的结果就会成为新的promise的结果
自定义Promise
整体结构
由于ES6和CommenJS都需要编译才能使用,所以自定义Promise需要使用ES5模块语法(自调用函数)
(function (window) {
/*
Promise:构造函数
excutor: 执行器
*/
function Promise(excutor) {
}
/*
Promise 原型对象.then
指定成功和失败的回调函数
返回一个新的Promise
*/
Promise.prototype.then = function (onResolved, onRejected) {
}
/*
Promise 原型对象.catch
指定失败的回调函数
返回一个新的Promise
*/
Promise.prototype.catch = function (onRejected) {
}
/*
Promise 原型对象.resolve
返回一个指定value的Promise
*/
Promise.resolve = function (value) {
}
/*
Promise 原型对象.reject
返回一个指定reason的Promise
*/
Promise.reject = function (reason) {
}
/*
Promise 原型对象.all
返回一个Promise,所有promise都成功才成功,一个失败就失败
*/
Promise.all = function (promises) {
}
/*
Promise 原型对象.race
返回一个Promise,由第一个完成的promise决定
*/
Promise.race = function (promises) {
}
// 暴露Promise
window.Promise = Promise;
})(window)
构造函数
/*
Promise:构造函数
excutor: 执行器
*/
function Promise(excutor) {
this.status = 'pending'; // 状态
this.data = undefined; // 数据
this.callbacks = []; // 保存回调函数,结构:{onResolved() {}, onReject() {}}
function resolve(value) {
// 当前状态不是pending结束
if (this.status !== 'pending') {
return
}
// 修改状态
this.status = 'resolved';
// 保存数据
this.data = value;
// 立即执行callback
if (this.callbacks.length > 0) {
this.callbacks.forEach(callbacksObj => {
setTimeout(() => { // 异步执行回调
callbacksObj.onResolved(value)
}, 0)
});
}
}
function reject(reason) {
// 当前状态不是pending结束
if (this.status !== 'pending') {
return
}
// 修改状态
this.status = 'rejected';
// 保存数据
this.data = value;
// 立即执行callback
if (this.callbacks.length > 0) {
this.callbacks.forEach(callbacksObj => {
setTimeout(() => { // 异步执行回调
callbacksObj.onRejected(reason)
}, 0)
});
}
}
// 立即执行excutor
try {
excutor(resolve, reject);
} catch (error) { // 抛出异常变为rejected
reject(error);
}
}
Promise.then()/.catch()
先来看一下这个例子,将fn赋值给f,两种方法,第二种比第一种简洁,在.then内部返回数据时会用到
function fn() {
}
var f = function fn() {
}
var f = fn;
正片开始
/*
Promise 原型对象.then
指定成功和失败的回调函数
返回一个新的Promise
*/
Promise.prototype.then = function (onResolved, onRejected) {
onResolved = typeof onResolved === 'function' ? onResolved : value => value
onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason}
const _this = this;
// 返回一个新的promise
return new Promise((resolve, reject) => {
// 指定调用回调函数
function handle(callback) {
try {
const result = callback(_this.data);
if (result instanceof Promise) { // 类型为promise,结果是这个promise的结果
// result.then(
// value => resolve(value),
// reason => reject(reason)
// )
result.then(resolve, reject);
} else {
resolve(result); // 非promise返回结果
}
} catch (error) { // 抛出异常,失败
reject(error);
}
}
if (_this.status === PENDING) {
_this.callbacks.push({
onResolved(value) {
handle(onResolved)
},
onRejected(reason) {
handle(onRejected)
}
})
} else if (_this.status === RESOLVED) {
setTimeout(() => {
handle(onResolved)
})
} else {
setTimeout(() => {
handle(onRejected)
})
}
})
}
/*
Promise 原型对象.catch
指定失败的回调函数
返回一个新的Promise
*/
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
Promise.resolve()/reject()
/*
Promise 原型对象.resolve
返回一个指定value的Promise
*/
Promise.resolve = function (value) {
// 返回一个成功/失败的promise
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject)
} else {
resolve(value)
}
})
}
/*
Promise 原型对象.reject
返回一个指定reason的Promise
*/
Promise.reject = function (reason) {
// 返回一个失败的promise
return new Promise((resolve, reject) => {
reject(reason);
})
}
Promise.all()/race()
/*
Promise 原型对象.all
返回一个Promise,所有promise都成功才成功,一个失败就失败
*/
Promise.all = function (promises) {
const values = new Array(promises.length); // 保存所有成功的value
let resolveCount = 0; // 计数器,计算成功的数量
return new Promise((resolve, reject) => {
// 获取每个promise的结果
promises.forEach((p, index) => {
p.then(
value => {
resolveCount++;
values[index] = value;
if (resolveCount === promises.length) { // 所有都完成才会resolve
resolve(values)
}
}, reason => {
reject(reason)
}
)
})
})
}
/*
Promise 原型对象.race
返回一个Promise,由第一个完成的promise决定
*/
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
promises.forEach((p) => {
p.then(
value => {
resolve(value)
}, reason => {
reject(reason)
}
)
})
})
}
代码
代码已经上传码云