Promise之API

1. Promise 构造函数:Promise(excutor){ }

executor函数:执行器  (resolve, reject) => { }
resolve函数:内部定义成功是我们调用的函数 value => { }
reject函数: 内部定义失败时我们调用的函数 reason => { }

🔉 executor 会在Promise 内部立即同步调用, 异步操作在执行器中执行

2. Promise.prototype.then()

then()  方法返回一个 Promise。它最多需要有两个参数:Promise 的成功和失败情况的回调函数.

onResolved函数:成功的回调函数(value) => { }
onRejected函数:  失败的回调函数  (reason) => { }

🔊 : 当Promise实例的状态改变之后,不管成功还是失败,都会触发then回调函数。它能链式调用,那必然是挂载在原型上的方法,它的两个参数也都是函数,分别接收成功结果与失败原因。

❓:这里就产生问题了,我们该如何拿到Promise实例的状态值呢,又该如何拿到成功结果或失败原因呢?

🙋:是Promise实例调用的then方法,根据隐式绑定原则,then方法内部的this就指向Promise实例,所以我们直接从this上拿状态值。对于成功结果或失败原因,自然我们也得从this上拿。

🌰:使用示例
const promise1 = new Promise((resolve, reject) => {
  resolve('Success!');
  // reject('error!');
});

promise1.then((value) => {
  console.log(value); // "Success!"
}, (err) => {
  console.log(err);  // 'error!'
});

简单实现

Promise.prototype.then = function(onFulfilled, onRejected){
    if(this.state === FULFILLED){
        typeof onFulfilled === 'function' && onFulfilled(this.value);
    }
    if(this.state === REJECTED){
        typeof onRejected === 'function' && onRejected(this.reason);
    }
    if(this.state === PENDING){
        // TODO
    }
}

3. Promise.prototype.catch()

Promise对象的 **catch()**方法用于注册一个在 promise 被拒绝时调用的函数。它会立即返回一个等价的 Promise对象,这可以允许链式调用其它 promise 的方法。此方法是 Promise.prototype.then(undefined, onRejected)的一种简写形式。

let promise = new Promise(function(resolve, reject) {
  resolve('Success');
});

promise.then(function(value) {
  console.log(value); // "Success!"
  throw 'error!';  // 等价于 return Promise.reject('error!');
}).catch(function(e) {
  console.log(e); // "error"
}).then(function(){
  console.log('捕获到了异常');
}, function () {
  console.log('你好呀');
});

简单实现

Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected);
};

4. Promise.prototype.finally()

finally()方法指定不管promise最后的状态如何,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。

let promise = new Promise(function(resolve, reject) {
  resolve('Success');
});

promise.then(function(value) {
  console.log(value); // "Success!"
  return Promise.reject('error!');
}).catch(function(e) {
  console.log(e); // "error!!"
}).then(function(){
  console.log('捕获到了异常');
}).finally(()=>{
  console.log('我是finall,不管promise结果如何我都要执行');
});

简单实现

Promise.prototype.finally = function (callback) {
  let P = this.constructor;    // P 指向当前 promise 实例的构造器,简单说就是 Promise 构造函数
  return this.then(
    value  => P.resolve(callback()).then(() => value),
    reason => P.resolve(callback()).then(() => { throw reason })
  );
};

5. Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。所有实例的状态都变成fulfilled,新生成实例的状态才会变成fulfilled;只要有一个实例被rejected,新生成实例的状态就变成rejected

注意

fulfilled状态下返回值是一个按顺序存储每一个实例返回值的数组,而rejected状态下返回值则是第一个被拒绝实例的返回值
Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
const p1 = new Promise((resolve, reject) => {
    resolve('hello');
}).then(result => result);

const p2 = new Promise((resolve, reject) => {
    throw new Error('报错了');
}).then(result => result);

Promise.all([p1, p2])
    .then(result => console.log(result))
    .catch(e => console.log(e));//Error:报错了

简单实现

Promise.all = function(iterable){    
    // 假定传入的参数就是数组或字符串等具有 Iterator 接口的对象,这里对参数省略过多校验
    const results = [];    // 用于存放结果
    let index = 0;    // 记录下标
    let count = 0;    // 记录已存放结果个数
    return new Promise(function(resolve, reject){
        if(iterable[Symbol.iterator]().next().done)    // 判断传入的可迭代对象是空的
            return resolve([]);        // return 终止
        for(let item of iterable){  
            let ind = index++;    // 只要循环下标就 +1,使用 let 来让每一次循环存储一个独有的下标
            Promise.resolve(item)    // 迭代出来的值无论是 promise 类型还是基本类型值,都给它封成 promise 
            .then(value =>{
                results[ind] = value;
                count++;    // 存放结果后才 +1
                if(count === iterable.length)    // 长度相同即判定都完成了
                    resolve(results);
            }, reason => {
                reject(reason);    // //只要有一个失败,return 的 promise 状态就为 reject
            })
        }
    });
}

6. Promise.allSettled()

该方法用来确定一组异步是否都结束(不管成功或失败)。方法接受一个数组作为参数,只有当参数数组中所有 Promise对象 都发生变化,返回的 Promise 对象才会发生状态变更。

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
    console.log(results);
});

简单实现

Promise.allSettled = function(iterable){    
    // 假定传入的参数就是数组或字符串等具有 Iterator 接口的对象,这里对参数省略过多校验
    const results = [];    // 用于存放结果
    let index = 0;    // 记录下标
    let count = 0;    // 记录已存放结果个数
    return new Promise(function(resolve, reject){
        if(iterable[Symbol.iterator]().next().done)    // 判断传入的可迭代对象是空的
            return resolve([]);        // return 终止
        for(let item of iterable){   
            let ind = index++;    // 只要循环下标就 +1,使用 let 来让每一次循环存储一个独有的下标
            Promise.resolve(item)    // 迭代出来的值无论是 promise 类型还是基本类型值,都给它封成 promise 
            .then(value =>{
                results[ind] = { status: 'fulfilled', value };
                count++;
                if(count === iterable.length)    // 长度相同即判定都完成了
                    resolve(results);
            }, reason => {
                results[ind] = { status: 'rejected', reason };
                count++;
                if(count === iterable.length)    // 长度相同即判定都完成了
                    resolve(results);    // 因为包装实例的状态只会变为 fulfilled
            })
        }
    });
}

7. Promise.race()

该方法同样是将多个 Promise 实例包装成一个新的 Promsie 实例,该方法与 Promise.all()方法一样,区别是该方法中只要参数之中有一个实例率先改变状态,该方法的实例状态跟着改变,那个率先改变的 Promise 实例的返回值就传递给该方法实例的回调函数。

const p = Promise.race([
    fetch('./index.js'),
    new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
    })
]);
p.then(console.log).catch(console.error);

简单实现

Promise.race = function(iterable){
    // 假定传入的参数就是数组或字符串等具有 Iterator 接口的对象,这里对参数省略过多校验
    return new Promise(function(resolve, reject){
        for(let item of iterable){
            Promise.resolve(item)
            .then(value => {
                resolve(value);
            }, reason => {
                reject(reason);
            })
        }
    })      
}

8. Promise.any()

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

const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const alsoRejected = Promise.reject(Infinity);

Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
    console.log(result); // 42
});

Promise.any([rejected, alsoRejected]).catch(function (results) {
    console.log(results instanceof AggregateError); // true
    console.log(results.errors); // [-1, Infinity]
});

简单实现

Promise.any = function(iterable){
    // 假定传入的参数就是数组或字符串等具有 Iterator 接口的对象,这里对参数省略过多校验
    const err = new AggregateError();    // 用于存放错误
    let index = 0;    // 记录下标
    let count = 0;    // 记录已存放结果个数
    return new Promise(function(resolve, reject){
        if(iterable[Symbol.iterator]().next().done)    // 判断传入的可迭代对象是空的
            return resolve([]);        // return 终止
        for(let item of iterable){
            let ind = index++;    // 只要循环下标就 +1,使用 let 来让每一次循环存储一个独有的下标
            Promise.resolve(item)
            .then(value => {
                resolve(value);
            }, reason => {
                err[ind] = (new Error(reason));
                count++;
                if(count === iterable.length)    // 长度相同即判定都完成了
                    reject(err);
            })
        }
    })      
}

9. Promise.resolve()

该方法能够将现有对象转换为 Promise 对象。

Promise.resolve('foo')
// 相当于
new Promise(resolve => resolve('foo'))

🔉 传入的参数如果是 promise 类型,不作处理直接返回。

简单实现

Promise.resolve = function(value) {
    if(value instanceof Promise)    return value
    const promise = new Promise(function(resolve, reject) {
        resolvePromise(promise, value, resolve, reject)
    });
    return promise;
}

10. Promise.reject()

返回一个带有拒绝原因的 Promise 对象。

Promise.reject(new Error('fail')).then(() => {
}, (error) => {
  console.error(error);
});

简单实现

Promise.reject = function(reason) {
    return new Promise(function(resolve, reject) {
        reject(reason)
    });
}

posted on 2024-07-13 20:00  梁飞宇  阅读(9)  评论(0)    收藏  举报