Promise的使用

总结

一、JS中的错误处理 try…catch

语法固定 try…catch try 尝试的意思 catch 捕获
1. try catch捕获到错误之后, 后续代码可以继续执行
2. catch 可以将错误信息捕获到. error参数是一个错误对象, 有message(错误信息)和stack(错误跟踪,精准到行和列)两个属性,使用console.dir(error)打印输出查看
3. 抛出错误之后, 在 try 里面的报错的后续代码就不再执行
4. try 不能捕获语法错误(syntaxError). 其他三种类型错误可以捕获(typeError类型错误、RangeError范围错误、以及throw抛出错误).
5. 允许使用 throw 手动的抛出错误
6. throw可以抛出任意类型的数据

try {
   try中存入有可能会出现错误的代码(文件操作...、连接数据库....、操作数据库方法....、ajax请求...1、TypeError错误:
     let a = 10.4656;
     a = {}
     // 在try中如果有哪一句话发生了错误,则后面的语句将不再执行
     console.log(a.toFixed(2));
     //前面的语句发生了错误,则这句123是不会在控制台中输出
     // console.log(123);

     2、RangeError:范围错误
     //Array构造函数中的参数表示数组的预计长度,起始为0,不能为负数
     // let arr = new Array(-1);
     // console.log(arr);

     3、SyntaxError语法错误,catch是无法捕捉的!!!
     // if () {

     4throw抛出的错误,catch也是可以捕捉的,可以抛出任意类型错误

     // throw new Error('错误消息');
     // throw new TypeError('错误消息');
     //throw后面可以抛出任意的数据类型,只要抛出了catch中的错误对象都可以捕捉
     // throw 100;
     // throw "我是错误字符串";
     // throw true;
     // throw [1, 2, 3];

 } catch (e) {
     //catch方法需要传入一个参数,这个参数表示错误对象
     //错误对象也是对象,那么可以通过console.dir方法查看对象的结构
     //错误对象中包含了两个属性,一个是message(错误消息)另一个是stack(错误跟踪,精准到行和列)
     console.dir(e);
 }
 //try...catch后面的语句是可以正常运行的
        console.log('hello');

在这里插入图片描述

二、promise基本使用

Promise的用途主要是为了实现一些异步任务,当这些异步任务的结果还没有得出的时候,此时Promise对象的状态仍然为pending

  • 创建promise对象(pending状态)
    const p = new Promise(executor)

    1、Promise本质是一个构造函数(产生一个实例化对象)
    2、Promise这个构造函数中需要传入一个参数,语法规定,必须要传入的,需要传入一个回调函数(executor 执行器函数)
    3、Promise构造函数中的实际参数的回调函数中还需要传递两个参数,且这两个参数仍然为回调函数
    这两个回调函数名基本不会改变:resolve(当前的状态是成功的)、reject(当前的状态是失败的)
    4、Promise主要为了实现异步编程(定时器、fs模块(文件写入、读取、删除…)、ajax、数据库操作方法)中提供成功/失败的结果
    5、Promise实例化对象有三个状态:pending(等待中...)、fulfilled(成功的状态)、rejected(失败的状态)
    6、Promise是通过其实例化对象的三个不同的状态来控制异步编程功能
    7、executor执行器函数中的两个形式参数也是可选参数,可加可不加,
    什么情况会添加?当如果想要改变Promise实例化对象的状态的时候是需要添加的,默认情况下Promise实例化对象的状态为pending

执行器回调函数中的两个回调函数作用:(resolve,reject)=>{}

  • reject的作用就是把Promise的状态从pending置为rejected,将实参设置到这个属性PromiseResult中,这样在then中就能捕捉到reject的回调函数
  • resolve的作用就是把Promise的状态从pending置为resolved,将实参设置到这个属性PromiseResult中,这样在then中就能捕捉到resolve的回调函数
const p = new Promise((resolve,reject)=>{
	//在回调函数中启动异步任务
    setTimeout(()=>{
        if(成功){
            resolve(实参);
        }else{
            reject(实参);
        }
    },2000)
})
  • 实例对象调用Promise原型中的then方法来完成对结果的处理
p.then((value)=>{
	//成功
},(reason)=>{
	//失败
})

三、Promise的状态改变

  • pending变为fulfilled
  • pending变为rejected

说明:只有这2种,且一个promise对象只能改变一次状态,状态一经改变,不可逆转

​ 无论变为成功还是失败,都会有一个结果数据

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

四、Promise实例对象的两个属性

  • PromiseState

    此属性为promise对象的状态属性。

    • fulfilled:成功的状态
    • rejected:失败的状态
    • pending:初始化的状态

    【注】状态只能由pending->fulfilled 或者是 pending->rejected

  • PromiseResult

    此属性为promise对象的结果值(resolve以及reject函数的形参值)
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q8uod8Ow-1686052789729)(null)]

五、node中的promisify

  • promisify (只能在 NodeJS 环境中使用)
  • promisify 是 util 模块中的一个方法 util 是 nodeJS 的内置模块
  • 作用: 返回一个新的函数, 函数的是 promise 风格的.
const util = require('util');
const fs = require('fs');
//promisify这个方法中需要传入一个以回调函数中是错误对象为优先的方法名
const mineReadFile = util.promisify(fs.readFile);

mineReadFile('./resource/2.html').then(value => {
    console.log(value.toString());
}, reason => {
    console.log(reason);
});

六、then 方法

then:指定用于得到成功value的成功回调和用于得到失败reason的失败回调,Promise的实例化对象调用Promise原型属性身上的then方法也是有返回值的,返回一个新的Promise对象

  • 成功的状态:执行第一个回调函数
  • 失败的状态:执行第二个回调函数

then方法返回一个Promise对象,它的的返回状态值的判断:

1、如果返回的是非promise的任意值, 新promise变为fulfilled, PromiseResult返回的值 ,如果没有retuen 返回值 PromiseResultundefined
2、如果返回的是另一个新promise, 此promise的结果就会成为新promise的结果
(当下这个新的Promise对象的状态将决定于then方法返回的Promise对象的状态,结果值亦然)
3、如果抛出异常, 新promise变为rejected, reason为抛出的异常

const p = new Promise((resolve,reject)=>{
     resolve('ok');
});

let result = p.then(value=>{
	1throw '错误信息';// 1抛出异常 错误
	2return 100;  // 值可以是字符串、数字、boolean、null、undefined、数组、对象都变为PromiseResult的结果
	3return new Promise((resolve,reject) => {
         // resolve();
         // reject();
         // throw 404;
        result的结果 取决于  此时设置的不同的状态 ,不设置的话result为pending
      })
},reason=>{
	console.log(reason);
});

console.log(result);
1、抛出异常的结果: PromiseState为rejected   PromiseResult为抛出的错误信息
2、 非promise的任意值  结果 :PromiseState为fulfilled   PromiseResult为return返回的值
3、result的结果 取决于  此时设置的不同的状态 ,不设置的话result为pending

当then方法没有传递成功/失败的回调函数的时候,那么p2的这个对象的状态和结果值???
如果then在书写的时候没有明确体现出成功/失败的时候,程序将默认补全
如果p1的状态为fulfilled的时候,then方法将补全成功回调函数为:value=>value 状态为fulfilled p1的结果值就是p2的结果值

   let p1 = new Promise((resolve, reject) => {
        resolve('ok');
    })
  //  let p2 = p1.then();  会转变为以下形式
    let p2 = p1.then(value => value);
    console.log(p2);

如果p1的状态为rejected的时候,then方法将补全失败回调函数为:reason=>{throw reason} p1的状态和结果值和p2是一致的

    let p1 = new Promise((resolve, reject) => {
        reject('error');
    })
 //  let p2 = p1.then();  会转变为以下形式
    let p2 = p1.then(() => { }, reason => {
        throw reason;
    });
    console.log(p2);

七、Promise的链式调用

通过then方法来实现链式调用

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

p.then(value=>{
	console.log(value);
},reason=>{
	console.log(reason);//error 失败状态,进入失败的函数
}).then(value=>{
	console.log(value);//undefined  此时的值取决于上一个Promise对象的状态
},reason=>{
	console.log(reason);
})

将 then 方法 的Promise对象的返回状态值的判断弄通这个链式调用中的值就懂了

八、终止Promise链条

通过 return new Promise((resolve, reject) => {}); 返回一个pending状态的promise对象 这样后续的链式调用就不再执行

new Promise((resolve, reject) => {
    resolve(111);
}).then(value=>{
    console.log(value);
    console.log(222);
    //
    // return false;
    // throw '出错啦';
    //有且只有一种方式 返回一个pending状态的promise对象
    return new Promise((resolve, reject) => {});
}).then(value => {
    console.log(333);
}).then(value => {
    console.log(444);
}).catch(reason => {
    console.log(reason);
});

九、Promise对象下的API方法

9.1.catch方法

功能是可以单独用来指定失败的回调函数

	let p1 = new Promise((resolve, reject) => {
      reject('error')
    })
    p1.catch(reason => {
      console.log(reason); //error
    })

catch方法也可以和then方法连用
当如果then方法可以catch方法连用的时候,并且then里面也有失败的回调函数的时候,具体是否还会向下执行catch
取决于then方法返回的那个新的Promise实例化对象的状态是否是失败的,因为catch方法是专门用于指定失败状态的这么一个方法
如果是失败的,会执行catch,反之不会

	let p1 = new Promise((resolve, reject) => {
      reject('error')
    })
    p1.then(value => {
      console.log(value)
    }, reason => {//进入到失败的回调
      // console.log(reason)
      return new Promise((resolve, reject) => {
        reject('错误...')
      })
    }).catch(reason => {//通过返回值进入到catch
      console.log(reason); //错误...
    })

异常(错误)穿透
当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用catch
当如果promise对象的状态为reject的话,会一直向下穿透直到catch方法

let p1 = new Promise((resolve, reject) => {
    reject('error')
 })
p.then(value=>{
    console.log(value);
}).then(value=>{
    console.log(value);
}).catch(reason=>{
    console.log(reason);//error
})

catch的返回值的用法和then是一样的 catch方法返回一个Promise对象,它的的返回状态值和then()方法是一样的

	let p1 = new Promise((resolve, reject) => {
      reject('error')
    })
    let p2 = p1.catch(reason => {
      console.log(reason); //error
    })
    console.log(p2) //Promise对象

9.2 resolve方法

创建一个成功状态的Promise实例化对象

  • 情况1:当如果resolve方法传递的为非Promise实例化对象的时候,
    则p1这个对象的状态为fullfilled,结果值为resolve方法的实际参数值
   let p1 = Promise.resolve(100);
     console.log(p1);
  • 情况2:当resolve方法传递的是promise实例化对象的时候,
    p2的状态和结果值完全取决于resolve方法的参数中的promise对象的状态和结果值
   let p2 = Promise.resolve(new Promise((resolve, reject) => {
       resolve('success');
   }))
   console.log(p2) //fulfllted 状态  值为success

9.3reject方法

返回的结果始终为失败的Promise对象
Promise.reject(值) 无论值是什么类型 都将已错误的值返回

 let p1 = Promise.reject(100);
console.log(p1); //  Promise对象 失败状态  值为100

  //reject的结果值仍然是reject这个方法的实际参数值
  let p1 = Promise.reject(new Promise((resolve, reject) => {
    resolve('success');
  }));
  console.log(p1);//  Promise对象 失败状态  值为传递的参数这个新的promise  看下图输出

在这里插入图片描述

9.4 all方法

作用:针对于多个Promise的异步任务进行处理

接收的参数:参数类型是一个数组,数组里面放的是promise的实例化对象

返回值:promise对象,状态由promise数组中的对象状态决定

  • 若每个对象状态都为成功,则返回的promise对象状态为成功,

​ 成功的结果值为每个promise对象成功结过值组成的数组

  • 不论有几个失败状态的对象 若任意一个对象状态为失败,则返回的promise对象状态为失败,

​ 失败的结果值为发现的第一个失败的promise对象的结果值 (以最快返回的第一个失败)

最终的请求时间是所有请求中耗时最长的请求所用的时间

let p1 = new Promise((resolve, reject) => {
            resolve('ok');
})
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('okk');
let result = Promise.all([p1, p2, p3])
console.log(result);

在这里插入图片描述

10.5 race方法

Promise.race() race 赛跑的意思

参数: promise 数组

返回结果: promise 对象

状态由『最先改变状态的 promise对象』决定

结果值由 『最先改变状态的 promise对象』决定

race方法是需要看哪一个Promise对象的状态已经不再是pending了,
不管是fulfilled还是rejected,只要修改了则修改的这个对象的状态和结果值直接就是arr的状态和结果值(最先出现结果的值就会输出)

let p1 = new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve('ok');
            }, 2000)
});
let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh hou');
let result = Promise.race([p1, p2, p3]);
console.log(result);// 成功状态的  success  p1 有定时器所有慢 p2 先输出

10.6 Promise.allSettled()

allSettled方法
参数仍然为promise 数组数组
返回的也是一个Promise实例化对象,其中包括两个状态,一个是fulfilled,一个是rejected

Promise.allSettled()方法,用来确定要一组异步操作是否都结束了(不管成功或失败)。
状态是fulfillesd ,值是以对象的形式返回每一项的状态和值 组成的数组

所以,它的名字叫"Settled",包含了"fufilled"和"rejected"两种情况.

最终的请求时间是所有请求中耗时最长的请求所用的时间
在这里插入图片描述

<script>
    function ajax(url) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest();
        xhr.open('get', url, true);
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText);
                } else {
                    reject(xhr.responseText);
                }
            }
        }
    })

}
//类比Promise下的all方法和allSettled
// Promise.all([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
// ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
// ]).then(value => {
//     console.log(value)
// }).catch(error => {
//     console.log(error);
// })

Promise.allSettled([ajax('http://www.xiongmaoyouxuan.com/api/tabs'),
                    ajax('https://m.maizuo.com/gateway?cityId=110100&k=4770248')
                   ]).then(value => {
    // console.log(value)
    let successList = value.filter(item => item.status === 'fulfilled');
    console.log(successList)

    let errorList = value.filter(item => item.status === 'rejected');
    console.log(errorList)
}).catch(error => {
    console.log(error);
})
</script>

10.7 Promise.any()

参数还是数组,数组中的内容是Promise实例化对象
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfiilled状态;

如果所有参数实例都变成rejected,包装实例就会变成rejected状态。

Promise.any()跟Promise.race()方法很像,但是有一点不同,
就是Promise.any()不会因为某个Promise变成rejected状态而结束,
必须等到所有参数Promise变成rejected状态才会结束。

10.8 Promise.finally()

finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象变成fufilled还是rejected状态,最终都会被执行。

finally方法中的回调函数是不接受参数的,因为无论前面是fulfilled状态还是rejected状态, 它都是执行。

const p = new Promise((resolve, reject) => {
    // resolve('ok');
    reject('error');
});
p.then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
}).finally(() => {
    console.log('finally')
})

十、async和await

async/await 是ES7提出的基于Promise的解决异步的最终方案。

10.1 async函数

async是一个加在函数前的修饰符,被async定义的函数会默认返回一个Promise对象resolve的值。

因此对async函数可以直接then,返回值就是then方法传入的函数。

async函数的返回值是一个Promise对象,这个Promise对象的状态到底是成功还是失败,取决于return后面值的类型
如果值类型为基本数据类型/引用数据类型, 则返回的Promise对象的状态为成功
如果值类型为promise实例化对象的话,则状态和返回的这个对象的状态有关联,状态值也是一样的

// async基础语法
async function fun0(){
    console.log(1);
    return 1;
}
fun0().then(val=>{
    console.log(val) // 1,1
})

async function fun1(){
    console.log('Promise');
    return new Promise(function(resolve,reject){
        resolve('Promise')
    })
}
fun1().then(val => {
    console.log(val); // Promise Promise
}
//声明一个async函数
async function main() {
    console.log('async function');
    //情况1:返回非promise对象数据
    return 'hahaha';
    //情况2:返回是promise对象数据
    /* return new Promise((resolve, reject) => {
		// resolve('ok');
		reject('error');
	}) */
    //情况3:抛出异常
    // throw new Error('出错啦!!!');
}
let result = main().then(value => {
    console.log(value);
});
console.log(result);

10.2 await表达式

await 也是一个修饰符,只能放在async定义的函数内。可以理解为等待

await 修饰的如果是Promise对象,可以获取Promise成功状态的结果值,且取到值后语句才会往下执行;
如果不是Promise对象:把这个非promise的东西当做await表达式的结果。
await后面是Promise成功状态的结果值
await后面如果是一个失败的Promise对象,则结果值需要通过使用try…catch来捕获得到
注意事项

  • await必须写在async函数中,但是async函数中可以没有await
  • 如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async function fun(){
    let a = await 1;
    let b = await new Promise((resolve,reject)=>{
        setTimeout(function(){
            resolve('setTimeout')
        },3000)
    })
    let c = await function(){
        return 'function'
    }()
    console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"
function log(time){
    setTimeout(function(){
        console.log(time);
        return 1;
    },time)
}
async function fun(){
    let a = await log(1000);
    let b = await log(3000);
    let c = log(2000);
    console.log(a);
    console.log(1)
}
fun(); 
// 立即输出 undefined 1
// 1秒后输出 1000
// 2秒后输出 2000
// 3秒后输出 3000
async function main() {
    //1、如果await右侧为非promise类型数据
    var rs = await 10;
    var rs = await 1 + 1;
    var rs = await "非常6+7";

    //2、如果await右侧为promise成功类型数据
    var rs = await new Promise((resolve, reject) => {
        resolve('success');
    })

    //3、如果await右侧为promise失败类型数据,需要借助于try...catch捕获
    try {
        var rs = await new Promise((resolve, reject) => {
            reject('error');
        })
        } catch (e) {
            console.log(e);
        }
}
main();
// 使用async/await获取成功的结果

// 定义一个异步函数,3秒后才能获取到值(类似操作数据库)
function getSomeThing(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('获取成功')
        },3000)
    })
}

async function test(){
    let a = await getSomeThing();
    console.log(a)
}
test(); // 3秒后输出:获取成功

async 用来修饰函数
   async 修饰过的函数,函数的返回值变成了 promise,这个promise我们叫做【async函数的promis】
问: 【async函数的promis】 成功失败由什么来决定? — 由函数的return来决定
1. return 一个非promise值得时候,【async函数的promis】一定是成功的,promise的值是 return值
2. return 一个promise值,【async函数的promis】由这个return的promise来决定
    return的promise是成功的,【async函数的promis】也是成功的
    return的promise是失败的,【async函数的promis】也是失败的
3. 函数如果抛出错误,那么【async函数的promis】也是失败的

await
await等待的意思,await必须放在async函数中
1. await 跟一个非promise值,直接得到这个结果
2. await 跟一个成功的promise,等待这个promsie执行完毕,拿到成功的值
3. await 无法跟一个失败的promise,跟一个失败的promsie,此时这行代码会立即抛错(后续代码不会执行了)
4. await 跟一个pendding状态的promsie,会一直等待这个promise出结果

十一、代码

ES5写法

(function (window) {
    // executor是执行器函数
    function Promise(executor) {
        //构造函数中的this一定是指向其实例化对象的
        // 定义实例属性state,初始值为pending
        this.PromiseState = 'pending';
        // 定义实例属性result,初始值为undefined
        this.PromiseResult = undefined;
        // 定义实例属性callbackFun,起始值为一个数组
        this.callbackFun = [];
        /* [
            {onResolved:function(){},onRejected:function(){}},
            {onResolved:function(){},onRejected:function(){}},
            {onResolved:function(){},onRejected:function(){}}
        ] */

        // 定义resolve函数
        const _resolve = value => {
            // 当状态已经被更改过,不允许再次更改
            if (this.PromiseState !== 'pending') return;
            //在修改状态之前需要考虑一件事,Promise实例化对象的状态是否仍然是pending 
            //如果不是pending了,不管是fulfilled还是rejected,就不会执行后面的代码
            // 将状态更改为成功(fulfilled)
            this.PromiseState = 'fulfilled';
            // 成功值为value
            this.PromiseResult = value;
            //运行执行器函数内部的异步代码
            // console.log(this.callbackFun)
            this.callbackFun.forEach(item => {
                item.onResolved();
            })
        }
        // 定义reject函数
        const _reject = reason => {
            // 当状态已经被更改过,不允许再次更改
            if (this.PromiseState !== 'pending') return;
            // 将状态更改为失败
            this.PromiseState = 'rejected';
            // 将result设置为reason
            this.PromiseResult = reason;
            this.callbackFun.forEach(item => {
                item.onRejected();
            })
        }
        try {
            executor(_resolve, _reject);
        } catch (err) {
            _reject(err);// 状态更改为失败,值为异常信息
        }



    }

    // Promise.prototype.then = function () { }


    //对象间的合并
    //第二个参数(源对象)向第一个参数(目标对象)合并
    //合并的时候,如果两个对象中有相同的属性,则后者会覆盖前者
    Object.assign(Promise.prototype, {
        // onResolved:成功回调
        // onRejected:失败回调

        then(onResolved, onRejected) {

            //判断当then方法里面没有传递两个实际参数的回调函数的时候,需要添加默认值
            //instanceof是判断一个值是否所属于某一个构造函数的实例化对象
            //补充成功回调函数
            if (!(onResolved instanceof Function)) {
                onResolved = value => value; // value=>{return value}
            }

            //补充失败回调函数
            if (!(onRejected instanceof Function)) {
                onRejected = reason => {
                    throw reason;
                };
            }

            return new Promise((resolve, reject) => {

                const _common = function (callback) {
                    setTimeout(() => {
                        try {
                            // value是成功回调的返回值
                            const value = callback(this.PromiseResult);
                            // 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
                            if (value instanceof Promise) {
                                value.then(v => {
                                    resolve(v);
                                }, r => {
                                    reject(r);
                                });
                            }
                            else {
                                // 不是Promise实例,将返回的Promise状态设置为成功,值为value
                                resolve(value);
                            }
                        } catch (err) {
                            // 有异常,将返回Promise的状态更改为失败,值为err
                            reject(err);
                        }

                    })
                }
                // 状态成功调用onResolved

                //这两种状态的改变相当于是同步代码的直接改变
                // p1的状态为成功
                if (this.PromiseState === 'fulfilled') {
                    _common.call(this, onResolved);
                } else if (this.PromiseState === 'rejected') {
                    _common.call(this, onRejected);
                } else {
                    //当异步任务没有执行完毕的时候,此时Promise实例化对象的状态为pending
                    //但是在pending的期间最终结果到底是fulfilled还是rejected,都有可能
                    //可以在当前Promise实例化对象身上添加一个回调函数的属性,用来存储两个回调(成功的回调,失败的回调)
                    this.callbackFun.push({
                        onResolved: _common.bind(this, onResolved),
                        onRejected: _common.bind(this, onRejected)
                    })
                }
            })
        },
        catch(onRejected) {
            //既然catch方法和then方法做的功能是一致的,那么我们没必要将代码在复制粘贴一份,而选择直接调用then方法
            // console.log(onRejected);
            return this.then(undefined, onRejected);
        }
    })

    //Promise对象下的方法添加
    // console.dir(Promise);

    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
            //判断value的类型到底是不是一个Promise对象
            if (value instanceof Promise) {
                // console.log('实例化对象', value);
                // value.then(v => {
                //     resolve(v);
                // }, r => {
                //     reject(r);
                // })

                //简写的形式
                value.then(resolve, reject);
            } else {
                resolve(value);
            }
        })
    }

    Promise.reject = function (value) {
        return new Promise((resolve, reject) => {
            //直接将Promise实例化对象状态更改成rejected
            reject(value);
        })
    }

    Promise.all = function (value) {
        // 定义一个变量,用来计数(计成功的Promise的数量,到时候和数组的数量做对比)
        let index = 0;
        //定义一个数组,数组用来装如果all方法里面都是成功的Promise对象的结果值
        //new Array(数字):表示预设数组长度
        let arr = new Array(value.length); // [??]

        return new Promise((resolve, reject) => {
            value.forEach((item, i) => {
                // console.log('数组的每一项:', item);
                // console.log('数组的下标:', i)
                item.then(v => {
                    //只要有一个成功的Promise实例化对象,就让计数器+1
                    index++;
                    arr[i] = v;
                    if (index === value.length) {
                        //只要计数器数值和all方法中的长度一致,则证明数组中每一个元素都是成功的Promise对象
                        resolve(arr);
                    }
                }, r => {
                    //只要有失败,状态将立即更改
                    reject(r);
                })
            })
        })

    }

    Promise.race = function (value) {
        return new Promise((resolve, reject) => {
            value.forEach(item => {
                //从数组中的第一个Promise对象开始循环,只要能够进入到then的回调函数之中,不管是哪一个回调函数
                //说明此时Promise对象的状态一定不为pending,所以不管是成功还是失败,直接修改状态
                item.then(v => {
                    resolve(v);
                }, reason => {
                    reject(reason)
                })
            })
        })
    }

    window.Promise = Promise;
})(window);

class写法

(function (window) {
    //声明类
    class Promise {

        constructor(executor) {
            //this指向的是Promise这个类的实例化对象
            this.PromiseState = 'pending';
            this.PromiseResult = undefined;
            //当执行器函数内部的代码为异步代码的时候
            this.callbackFun = [];

            // 定义resolve函数
            const _resolve = value => {
                // 当状态已经被更改过,不允许再次更改
                if (this.PromiseState !== 'pending') return;
                //在修改状态之前需要考虑一件事,Promise实例化对象的状态是否仍然是pending 
                //如果不是pending了,不管是fulfilled还是rejected,就不会执行后面的代码
                // 将状态更改为成功(fulfilled)
                this.PromiseState = 'fulfilled';
                // 成功值为value
                this.PromiseResult = value;
                this.callbackFun.forEach(item => {
                    item.onResolved();
                })
            }

            // 定义reject函数
            const _reject = reason => {
                // 当状态已经被更改过,不允许再次更改
                if (this.PromiseState !== 'pending') return;
                // 将状态更改为失败
                this.PromiseState = 'rejected';
                // 将result设置为reason
                this.PromiseResult = reason;
                this.callbackFun.forEach(item => {
                    item.onRejected();
                })
            }

            try {
                executor(_resolve, _reject);
            } catch (err) {
                _reject(err);// 状态更改为失败,值为异常信息
            }
        }

        then(onResolved, onRejected) {

            //判断当then方法里面没有传递两个实际参数的回调函数的时候,需要添加默认值
            //instanceof是判断一个值是否所属于某一个构造函数的实例化对象
            //补充成功回调函数
            if (!(onResolved instanceof Function)) {
                onResolved = value => value; // value=>{return value}
            }

            //补充失败回调函数
            if (!(onRejected instanceof Function)) {
                onRejected = reason => {
                    throw reason;
                };
            }

            return new Promise((resolve, reject) => {

                const _common = function (callback) {
                    setTimeout(() => {
                        try {
                            // value是成功回调的返回值
                            const value = callback(this.PromiseResult);
                            // 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
                            if (value instanceof Promise) {
                                value.then(v => {
                                    resolve(v);
                                }, r => {
                                    reject(r);
                                });
                            }
                            else {
                                // 不是Promise实例,将返回的Promise状态设置为成功,值为value
                                resolve(value);
                            }
                        } catch (err) {
                            // 有异常,将返回Promise的状态更改为失败,值为err
                            reject(err);
                        }

                    })
                }
                // 状态成功调用onResolved

                //这两种状态的改变相当于是同步代码的直接改变
                // p1的状态为成功
                if (this.PromiseState === 'fulfilled') {
                    _common.call(this, onResolved);
                } else if (this.PromiseState === 'rejected') {
                    _common.call(this, onRejected);
                } else {
                    //当异步任务没有执行完毕的时候,此时Promise实例化对象的状态为pending
                    //但是在pending的期间最终结果到底是fulfilled还是rejected,都有可能
                    //可以在当前Promise实例化对象身上添加一个回调函数的属性,用来存储两个回调(成功的回调,失败的回调)
                    this.callbackFun.push({
                        onResolved: _common.bind(this, onResolved),
                        onRejected: _common.bind(this, onRejected)
                    })
                }
            })
        }

        catch(onRejected) {
            //既然catch方法和then方法做的功能是一致的,那么我们没必要将代码在复制粘贴一份,而选择直接调用then方法
            // console.log(onRejected);
            return this.then(undefined, onRejected);
        }

        static resolve = function (value) {
            return new Promise((resolve, reject) => {
                //判断value的类型到底是不是一个Promise对象
                if (value instanceof Promise) {
                    // console.log('实例化对象', value);
                    // value.then(v => {
                    //     resolve(v);
                    // }, r => {
                    //     reject(r);
                    // })

                    //简写的形式
                    value.then(resolve, reject);
                } else {
                    resolve(value);
                }
            })
        }

        static reject = function (value) {
            return new Promise((resolve, reject) => {
                //直接将Promise实例化对象状态更改成rejected
                reject(value);
            })
        }

        static all = function (value) {
            // 定义一个变量,用来计数(计成功的Promise的数量,到时候和数组的数量做对比)
            let index = 0;
            //定义一个数组,数组用来装如果all方法里面都是成功的Promise对象的结果值
            //new Array(数字):表示预设数组长度
            let arr = new Array(value.length); // [??]

            return new Promise((resolve, reject) => {
                value.forEach((item, i) => {
                    // console.log('数组的每一项:', item);
                    // console.log('数组的下标:', i)
                    item.then(v => {
                        //只要有一个成功的Promise实例化对象,就让计数器+1
                        index++;
                        arr[i] = v;
                        if (index === value.length) {
                            //只要计数器数值和all方法中的长度一致,则证明数组中每一个元素都是成功的Promise对象
                            resolve(arr);
                        }
                    }, r => {
                        //只要有失败,状态将立即更改
                        reject(r);
                    })
                })
            })

        }

        static race = function (value) {
            return new Promise((resolve, reject) => {
                value.forEach(item => {
                    //从数组中的第一个Promise对象开始循环,只要能够进入到then的回调函数之中,不管是哪一个回调函数
                    //说明此时Promise对象的状态一定不为pending,所以不管是成功还是失败,直接修改状态
                    item.then(v => {
                        resolve(v);
                    }, reason => {
                        reject(reason)
                    })
                })
            })
        }
    }
    window.Promise = Promise;
})(window)
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值