1.什么是Promise?
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一。
2.对于几种常见异步编程方案?(暂不说generator函数和async函数)
1.回调函数;
2.事件监听
3.发布/订阅模式
4.Promise对象
3.方案对比
这里为了突出Promise在异步编程的优势,我主要使用了回调函数和Promise作出对比
1.回调函数
我们接触比较多的回调函数,我举个例子,我们们用Jquery的ajax获取数据时 都是以回调函数方式获取的数据
$.get(url, (data) => {
console.log(data)
)
如果说 当我们需要发送多个异步请求 并且每个请求之间需要相互依赖 那这时 我们只能 以嵌套方式来解决 形成 "回调地狱"
$.get(url, data1 => {
console.log(data1)
$.get(data1.url, data2 => {
console.log(data1)
$.get(data2.url, data3 => {
console.log(data2)
.....
})
})
})
这样一来,在处理越多的异步逻辑时,就需要越深的回调嵌套,导致代码书写顺序与执行顺序不一致,不利于阅读与维护,不利于bug的修复和新需求的加入等等。
2.Promise方案
这里我们使用Promise来解决这个callback-hell问题。
const asyncRequest = url => {
return new Promise((resolve,reject)=>{
$.get(url, data => {
resolve(data)
});
})
}
首先对Jq的请求函数进行Promise封装
// 请求data1
asyncRequest(url)
.then(data1 => {
return request(data1.url);
})
.then(data2 => {
return request(data2.url);
})
.then(data3 => {
console.log(data3);
})
.catch(err => throw new Error(`error of ${err} happen in asyncRequest function`));
经过Promise处理的Jq请求函数,在处理上述中回调地狱情形是如此优势巨大,整个请求下来,逻辑非常清晰和有利于代码的维护。
接下来为了更加深入地了解Promise,我们不如造一个属于自己的Promise吧,不过这个Promise不会完全实现和PromiseA+规范的Promise,这里我们只需要实现我们平时使用的Promise中的静态resolve,reject函数,原型对象的then函数,catch函数,实现链式调用,而race和all函数这些附加性质的函数,我们有时间再去实现,我们先简单实现上述目标!
等等,实现一个Promise之前,我们先了解Promise的特性,不然你不知道需求,写什么代码啊!!
3.Promise特性
1.Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject
const promise = new Promise((resolve, reject) => {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
2.Promise是一个状态机,有三种不同的状态。
- pending
- fulfilled
- rejected
(1) promise 对象初始化状态为 pending
(2) 当调用resolve(成功),会由pending => fulfilled
(3) 当调用reject(失败),会由pending => rejected
注意promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变
3.promise对象方法
(1) then方法注册 当resolve(成功)/reject(失败)的回调函数
// onFulfilled 是用来接收promise成功的值
// onRejected 是用来接收promise失败的原因
promise.then(onFulfilled, onRejected);
(2) resolve(成功) onFulfilled会被调用
const promise = new Promise((resolve, reject) => {
resolve('fulfilled'); // 状态由 pending => fulfilled
});
promise.then(result => { // onFulfilled
console.log(result); // 'fulfilled'
}, reason => { // onRejected 不会被调用
})
(3) reject(失败) onRejected会被调用
const promise = new Promise((resolve, reject) => {
reject('rejected'); // 状态由 pending => rejected
});
promise.then(result => { // onFulfilled 不会被调用
}, reason => { // onRejected
console.log(reason); // 'rejected'
})
(4) promise.catch
在链式写法中可以捕获前面then中发送的异常
promise.catch(onRejected)
相当于
promise.then(null, onRrejected);
// 注意
// onRejected 不能捕获当前onFulfilled中的异常
promise.then(onFulfilled, onRrejected);
// 可以写成:
promise.then(onFulfilled)
.catch(onRrejected);
(5)链式调用
promise.then方法每次调用都返回一个新的promise对象所以可以链式写法
function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected) // 捕获前面then方法中的异常
(6)Promise的静态方法
- Promise.resolve 返回一个fulfilled状态的promise对象
Promise.resolve('hello').then(function(value){
console.log(value);
});
Promise.resolve('hello');
// 相当于
const promise = new Promise(resolve => {
resolve('hello');
});
(2) Promise.reject 返回一个rejected状态的promise对象
Promise.reject(24);
new Promise((resolve, reject) => {
reject(24);
});
(3) Promise.all 接收一个promise对象数组为参数
只有全部为resolve才会调用 通常会用来处理 多个并行异步操作
const p1 = new Promise((resolve, reject) => {
resolve(1);
});
const p2 = new Promise((resolve, reject) => {
setTimeout(()=>{
resolve(2);
},1000)
});
const p3 = new Promise((resolve, reject) => {
reject(3);
});
Promise.all([p1, p2, p3]).then(data => {
console.log(data); // [1, 2, 3] 结果顺序和promise实例数组顺序是一致的
}, err => {
console.log(err);
});
(4) Promise.race 接收一个promise对象数组为参数
Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
function timerPromisefy(delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
Promise.race([
timerPromisefy(10),
timerPromisefy(20),
timerPromisefy(30)
]).then(function (values) {
console.log(values); // 10
});
Promise特征总结
1.Promise是一个构造函数,接受一个函数作为参数,而该函数两个函数类型形参resolve reject,这两函数是构造函数内部提供。
2.Promise有三种状态pending,fulfilled,rejected且状态不能逆转
3.Promise对象有三个方法then,resolve,reject,catch
4.Promise能够进行链式调用
5.Promise静态方法resolve,reject,all,rece。
需求准备好,开始早一个Promise!(all,race暂不实现,另外不对thenable对象,和内部可能存在的其他Promise的情形作处理,先通过数字,字符串,对象等情况)
go on
首先我们要将下面这个回调函数做做处理变成Promise形式
function doSomething(cb) {
cb();
}
biubiubiu
function doSomething(){
return {
then(cb) {
cb()
}
}
}
好得到这段毫无意义的代码,不过看上去好像有点样式...!我们目前还没有触及 Promise 背后的核心概念,但这也是个小小的开始。
好继续改造
上面代码:
function MyPromise(){
return {
then(cb) {
cb()
}
}
}
改造代码:
function MyPromise(excutor){
let callback = null;
this.then = function(cb) {
callback = cb
}
function resolve(val) {
callback(val)
}
try{
excutor(resolve)
}catch(error){
throw new Error(error)
}
}
这里改造后的代码,好像有模有样了,但是这里就遇到一个问题:如果你逐行执行代码,就会发现resolve() 函数在then() 函数之前被调用,这就意味着resolve() 被调用的时候,callback 还是 null。让我们用一个 hack 来干掉这个问题,引入setTimeout处理一下,代码如下所示:
function MyPromise(excutor){
let callback = null;
this.then = function(cb) {
callback = cb
}
function resolve(val) {
setTimeout(()=>{
callback(val)
},0)
}
try{
excutor(resolve)
}catch(error){
throw new Error(error)
}
}
测试代码:
console.log(0)
var a = new MyPromise((resolve,reject)=>{
console.log(1);
resolve(2);
})
a.then(val=>{
console.log(val)
})
console.log(3)
结果:0,1,3,2
做到这里,程序的执行顺序和我们平常的Promise顺序一致唉!不过还存在非常多的问题!
- 没有链式调用
- 没有Promise状态
- 没有reject函数作错误返回,catch函数做错误捕捉等等...
好继续改造
// promise 三个状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
//这里用用es6的语法
class MyPromise {
constructor(excutor) {
if(typeof excutor !== 'function') {
throw new Error(`${excutor} is not a function`);
}
let that = this;
this.state = PENDING//fulfilled reject
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];//纪录成功的回调,就是then的第一个参数
this.onRejectedCallbacks = [];//纪录成功的回调,就是then的第二个参数
function resolve(value) {
setTimeout(()=>{
that.state = FULFILLED;
that.value =value;
that.onFulfilledCallbacks.forEach((cb,idx)=>{
cb.call(this,that.value);
})
})
}
function reject(reason) {
setTimeout(()=>{
that.state = REJECTED;
that.reason = reason;
that.onRejectedCallbacks.forEach((cb,idx)=>{
cb.call(this,that.reason);
})
},0)
}
try {
excutor(resolve,reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason=>{
throw new Error(reason)
}
return new MyPromise((resolve,reject)=>{
/*
*这里是箭头函数,所以这里this.onFulfilledCallbacks和*this.onRejectedCallbacks是指向外层的成功和失败回调数据,
*假如是function的形式,就需要提前定义这个**参数函数**然后通过*bind()函数绑定this的指向
*/
this.onFulfilledCallbacks.push(value)=>{
try {
let newValue = onFulfilled(value);
resolve(newValue);
} catch (error) {
reject(error)
}
}
this.onRejectedCallbacks.push(value=>{
try {
let reason = onRejected(value);
reject(reason)
} catch (error) {
reject(error)
}
})
})
}
}
测试代码:
console.log(0)
var a = new SuperPromise((resolve,reject)=>{
console.log(1)
resolve(2)
})
a.then((val)=>{
console.log(val)
return (3)
}).then(val=>{
console.log(val)
})
console.log(4)
结果//0,1,4,2,3
好,这里我们实现了then的链式调用,这一看,我们只实现了原型上一个then函数,接下来我们继续实现catch,和静态resolve,静态reject
go on
上面我们提到catch函数:
promise.catch(onRejected)
相当于
promise.then(null, onRrejected);
但是有一点不同的是,onRrejected不是不能捕捉到onFulfilled中的异常。
class MyPromise {
constructor(excutor) {
if(typeof excutor !== 'function') {
throw new Error(`${excutor} is not a function`);
}
let that = this;
this.state = PENDING//fulfilled reject
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];//纪录成功的回调,就是then的第一个参数
this.onRejectedCallbacks = [];//纪录成功的回调,就是then的第二个参数
function resolve(value) {
setTimeout(()=>{
that.state = FULFILLED;
that.value =value;
that.onFulfilledCallbacks.forEach((cb,idx)=>{
cb.call(this,that.value);
})
})
}
function reject(reason) {
setTimeout(()=>{
that.state = REJECTED;
that.reason = reason;
that.onRejectedCallbacks.forEach((cb,idx)=>{
cb.call(this,that.reason);
})
},0)
}
try {
excutor(resolve,reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason=>{
throw new Error(reason)
}
if(this.state === PENDING) {
return new MyPromise((resolve,reject)=>{
this.onFulfilledCallbacks.push(value=>{
try {
let newValue = onFulfilled(value);
resolve(newValue);
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(value=>{
try {
let newValue = onRejected(value);
reject(newValue)
} catch (error) {
reject(error)
}
})
})
}
}
catch(onRejected) {
return this.then(null,onRejected)
}
}
测试代码:
var b = new MyPromise((resolve,reject)=>{
reject('error happen in SuperPromise')
})
b.then((val)=>{
console.log(val,'val')
return val;
})
.catch(err=>{
console.log(err)
})
-------
var c = new MyPromise((resolve,reject)=>{
resolve(2)
})
c.then((val)=>{
console.log(val,'val')
throw new Error('some error in then')
})
.catch(err=>{
console.log(err)
})
接下黎啊继续实现静态resolve和reject
class MyPromise {
constructor(excutor) {
if(typeof excutor !== 'function') {
throw new Error(`${excutor} is not a function`);
}
let that = this;
this.state = PENDING//fulfilled reject
this.value = undefined;
this.reason = undefined;
this.onFulfilledCallbacks = [];//纪录成功的回调,就是then的第一个参数
this.onRejectedCallbacks = [];//纪录成功的回调,就是then的第二个参数
function resolve(value) {
setTimeout(()=>{
that.state = FULFILLED;
that.value =value;
that.onFulfilledCallbacks.forEach((cb,idx)=>{
cb.call(this,that.value);
})
})
}
function reject(reason) {
setTimeout(()=>{
that.state = REJECTED;
that.reason = reason;
that.onRejectedCallbacks.forEach((cb,idx)=>{
cb.call(this,that.reason);
})
},0)
}
try {
excutor(resolve,reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled,onRejected) {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason=>{
throw new Error(reason)
}
if(this.state === PENDING) {
return new MyPromise((resolve,reject)=>{
this.onFulfilledCallbacks.push(value=>{
try {
let newValue = onFulfilled(value);
resolve(newValue);
} catch (error) {
reject(error)
}
})
this.onRejectedCallbacks.push(value=>{
try {
let newValue = onRejected(value);
reject(newValue)
} catch (error) {
reject(error)
}
})
})
}
}
catch(onRejected) {
return this.then(null,onRejected)
}
//这两个就比较简单,我们回忆一下,当我们Promise.resolve(),就会马上进入成功回调,相反Promise.reject(),就马上进入失败回调
static resolve(val){
return new MyPromise((resolve,reject)=>{
resolve(val)
})
}
static reject(reason){
return new MyPromise((resolve,reject)=>{
reject(reason)
})
}
}
测试代码:
MyPromise.resolve(2).then(val=>{
console.log(val)
return 3
}).then(val=>{
console.log(val)
})
---
MyPromise.reject('some error happen in static reject')
.catch(err => console.log(err))
以上两段代码测试通过,完美!!!
好,我们再看看我们的需求
(all,race暂不实现,另外不对thenable对象,和内部可能存在的其他Promise的情形作处理,先通过数字,字符串,对象等情况)
OK这里已经实现的Promise已经实现了我们上述的请求,如果看客跟着我一起去实现一个Promise,是不是会有一些成就感呢?说笑,这节说到这里。good night