为什么要使用Promise?
大家在做前端开发时,对于异步任务的处理是比较头痛的,假如现在有这么一个异步任务的小例子:
function start(){
setTimeout(function(){
return "这里是我返回的结果";
},3000)
}
console.log(start());//undefined
结果我们打印出来undefined,至于为什么是undefined,我想大家都知道。所以我们通常的做法就是利用回调函数来获取到异步任务返回的值
function start(fn) {
setTimeout(function () {
fn("这里是我返回的结果")
}, 3000)
}
start(function (data) {
console.log("这里对数据一次处理");
a(data);
function a(data) {
console.log("这里对数据二次处理");
b(data);
function b(data) {
console.log("这里对数据三次次处理");
}
}
})
这样我们代码的层次就一层一层嵌套,层数少了还好,但是层数一多,代码的可读性就太差了,不利于开发人员的后期维护。在这种场景下就出现Promise;
实现Promise的构造函数;
对于Promise的使用,我们这里就不讲了,大家可以看文档es6.ruanyifeng.com/#docs/promi… 我们实现我们自己的Promise构造函数。
function MyPromise(excutor){
this.status="pending";//当前的状态,初始状态就是pending
this.data=undefined;//回调的值
this.callBack=[];//当前的回调函数
function resolve(value){//成功的回调
//判断Promise当前是否是pending状态,因为promise只会从等待变为成功或者从等待变为失败
if(this.status!='pending'){
return;
}
this.status="resolve";
this.data=value;
//这里我们使用一个宏任务来实现我们的异步执行回调函数,确保我们可以拿到回调的值,再去执行回调函数
setTimeout(()=>{
this.callBack.forEach(item=>{
console.log("这里执行我们的回调函数");//后面我们继续补全这里
})
})
}
function reject(reason){//失败的回调
if(this.status!='pending'){
return;
}
this.status="reject";
this.data=value;
setTimeout(()=>{
this.callBack.forEach(item=>{
console.log("这里执行我们的回调函数");//后面我们继续补全这里
})
})
}
try{
//执行构造函数,同时我们还需要监听构造函数在执行时,是否报错
excutor(resolve.bind(this),reject.bind(this));
}catch (err) {
//如果构造函数执行报错,那直接执行失败回调函数
reject.call(this,err);
}
}
实现.then方法
then方法可以传入两个回调函数,第一个是成功的回调函数,第二个是失败的回调函数
MyPromise.prototype.then=function(onResolve,onReject){
let that=this;
//如果没有传入成功回调函数,就默认返回回调的值,因为在Promise中有个值穿透的概念
let onResolve=typeof onResolve=="function"?onResolve:value=>value;
//如果没有传入失败的回调函数,就赋值一个抛出异常的函数
let onReject=typeof onReject=="function"?onReject:err=>{
throw err;
}
//then方法返回一个新的Promise对象
return new MyPromise((resolve,reject)=>{
function handler(on){
//获取回调函数返回的值
let a=on(that.data);
//判断返回值是否也是Promise对象,如果是就需要判断该Promise的状态来决定新返回的Promise的状态
if(a instanceof MyPromise){
a.then(data=>{
resolve(data);
},err=>{
reject(err);
})
}else{
resolve(a);
}
}
//如果当前状态是pending,那么就需要将回调函数存入callBack中,当状态改变了就执行响应的回调
if(that.status=="pending"){
that.callBack.push({
onresolve:function(){
handler(onResolve);
},
onreject:function(){
handler(onReject);
}
})
//如果状态已经是resolve,就执行成功回调函数
}else if(that.status=="resolve"){
setTimeout(()=>{
handler(onResolve);
})
//如果状态已经是reject,就执行失败回调函数
}else{
setTimeout(()=>{
handler(onReject)
})
}
})
}
即现可以把我们的Promise构造函数补充完整:
function MyPromise(excutor){
this.status="pending";//当前的状态,初始状态就是pending
this.data=undefined;//回调的值
this.callBack=[];//当前的回调函数
function resolve(value){//成功的回调
//判断Promise当前是否是pending状态,因为promise只会从等待变为成功或者从等待变为失败
if(this.status!='pending'){
return;
}
this.status="resolve";
this.data=value;
//这里我们使用一个宏任务来实现我们的异步执行回调函数,确保我们可以拿到回调的值,再去执行回调函数
setTimeout(()=>{
this.callBack.forEach(item=>{
item.onresolve(value);//++++++++++++++++++++++++
})
})
}
function reject(reason){//失败的回调
if(this.status!='pending'){
return;
}
this.status="reject";
this.data=value;
setTimeout(()=>{
this.callBack.forEach(item=>{
item.onreject(reason);//++++++++++++++++++++++++++
})
})
}
try{
//执行构造函数,同时我们还需要监听构造函数在执行时,是否报错
excutor(resolve.bind(this),reject.bind(this));
}catch (err) {
//如果构造函数执行报错,那直接执行失败回调函数
reject.call(this,err);
}
}
实现catch方法
有了then方法,catch方法就比较简单了,直接执行失败的回调函数即可
MyPromise.prototype.catch = function (onReject) {
return this.then(undefined, onReject);
}
实现resolve静态方法
MyPromise.resolve = function (value) {
return new MyPromise((resolve, reject) => {
//promise.resolve,传入值是promise类型,就需要判断传入promise的状态来决定返回promise的状态
if (value instanceof MyPromise) {
value.then(data => {
resolve(data);
}).catch(err => {
reject(err);
})
} else {
//promise.resolve,传入值是普通类型,就直接返回成功,
resolve(value);
}
})
}
实现reject静态方法
MyPromise.reject = function (value) {
//promise.reject是只能返回一个失败的promise
return new MyPromise((resolve, reject) => {
reject(value);
})
}
实现all静态方法
MyPromise.all = function (arr = []) {
//promise.all:只要传入的promise数组中有失败的,就直接返回失败的promise,全部成功则返回成功promise,值为成功值数组
return new MyPromise((resolve, reject) => {
var list = [];
var n = 0;
arr.forEach((item, index) => {
MyPromise.resolve(item).then(data => {
n++;
list.push(data);
if (n === arr.length) {
resolve(list)
}
}).catch(err => {
reject(err);
})
})
})
}
实现race静态方法
MyPromise.race = function (arr = []) {
return new MyPromise((resolve, reject) => {
arr.forEach(item => {
item.then(data => {
resolve(data)
}).catch(err => {
reject(err)
})
})
})
}
谢谢大家!...........