Promise从入门到自定义

143 阅读22分钟

src=http___pic1.zhimg.com_v2-57d5a426a55657d5de729f0194c6cc2e_1200x500.jpg&refer=http___pic1.zhimg.webp

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

提到Promise想必大家都不会陌生,Promise 是异步编程的一种解决方案,比传统的解决方案:回调函数和事件更合理、更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。

Promise在前端开发中应用广泛,实际开发主要应用于封装axios请求、验证多个请求结果是否都是满足条件、合并请求结果并处理错误等等。本篇文章将带你从零开始了解Promise,熟悉Promise的概念与使用,完成自定义(手写)Promise,并且扩展一些其它功能,最后也会介绍异步编程的终极解决方案asyncawait的简单使用。除此之外,也会带领大家学习JavaScript中的宏任务(宏队列)微任务(微队列)的相关知识,了解事件循环机制,梳理事件循环的顺序,确定JavaScript代码的执行顺序。

现在让我们一起开始学习吧!💪🏻💪🏻💪🏻

一. 前置知识

在学习promise的相关知识之前,我们有必要对一些与之相关的基础知识初步认知,这样在之后的编码过程中才不会混淆概念,有助于我们理清思路。

区别实例对象与函数对象

  • 实例对象:new函数产生的对象,称为实例对象,简称为对象
  • 函数对象:将函数作为对象使用时,简称为函数对象
function Fn() { 
    //Fn函数
}
const fn = new Fn() //Fn是构造函数 fn是实例对象(简称为对象)
console.log(Fn.prototype) //Fn是函数对象
Fn.bind({}) //Fn是函数对象

在上面的代码中,我们定义了一个函数对象Fn,然后通过new关键字创建了它的一个实例对象fn,简单来说括号的左边是函数(函数对象),点的左边是对象(实例对象)

它们二者之间存在以下区别:

  • 函数对象本身就是函数,可以使用"."调用方法或属性。
  • 函数对象的构造函数是Function,Function的prototype(原型对象)身上具有call、apply、bind等方法,但是实例对象构造函数是Fn,Fn的原型对象身上是不具备这三个方法的,继续沿着原型链向上查找最终是Object。

两种类型的回调函数

JavaScript中的回调函数分为同步回调函数与异步回调函数两种类型,下面对这两种类型的回调函数做简单说明,其中涉及到的js事件循环机制,宏任务与微任务等相关知识不做深入介绍,想要深入学习的同学可自行搜索相关资料学习。

# 如何理解js的事件循环机制

# JS的同步和异步、微任务和宏任务

# Js 的事件循环(Event Loop)机制以及实例讲解

# JS事件循环机制(event loop)之宏任务/微任务

同步回调

  • 理解:立即执行,完全执行完了才结束,不会放入回调队列中
  • 例子:数组遍历相关的回调函数、Promise的excutor函数

异步回调

  • 理解:不会立即执行,会放入回调队列中将来执行
  • 例子:定时器回调、/ajax回调、/Promise的成功|失败的回调
const arr = [1, 3, 5]
arr.forEach(item => { 
    //遍历回调 同步回调函数
    console.log(item);
})
console.log('after forEach()');
setTimeout(() => { 
    //异步回调函数 会放在队列中将来执行
    console.log('time callback');
}, 0)
console.log('after setTimeout');

/* 
1
3
5
after forEach()
after timeout
time callback
*/

由以上代码示例看出,JavaScript中的代码执行是有顺序的,具体执行的顺序受多种因素的影响,后续会做进一步说明,这里大家只需要了解其基本概念就可以了。

JavaScript中的error处理

在前端项目中,由于JavaScript本身是一个弱类型语言,加上浏览器环境的复杂性网络问题等等,很容易发生错误。下面将从错误的类型、错误处理以及错误对象三个方面对JavaScript中的错误做一个简单介绍,帮助大家在遇到错误时可以快速定位错误产生的原因,及时解决。

错误的类型

  • Error:所有错误的父类型
  • RefrenceError:引用的变量不存在
  • TypeError:数据类型不正确的错误
  • RangeError:数据值不在其所允许的范围内
  • SyntaxError:语法错误
// RefrenceError:引用的变量不存在
console.log(a); //ReferenceError: a is not defined

// TypeError:数据类型不正确的错误
let b = null
console.log(b.xxx);
//TypeError: Cannot read properties of null (reading 'xxx')

// RangeError:数据值不在其所允许的范围内
function fn(){
    fn() //递归调用
}
fn() 
 //RangeError: Maximum call stack size exceeded

// SyntaxError:语法错误
let c = """"
// SyntaxError: Unexpected string

JavaScript中常见的错误类型有以上几种,详细内容请参考# 前端开发中的Error以及异常捕获 或自行查阅资料学习。

错误处理

  • 捕获错误:try...catch
  • 抛出错误:throw error
//捕获错误 try catch
try {
    let d
    console.log(d.xx);
} catch (error) {
    console.log(error);
}
//抛出错误 throw error
function something() {
    if (Date.now() % 2 === 1) {
        console.log('当前时间为奇数');
    } else {
        throw new Error('当前时间为偶数')
    }
}
try {
    something()
} catch (error2) {
    console.log(error2.name);
    console.log(error2.message);
    console.log(error2.stack);
}
//Error
//VM16899:12 当前时间为偶数
//VM16899:13 Error: 当前时间为偶数
    at something (<anonymous>:5:15)
    at <anonymous>:9:5

常见的捕获错误异常的方法就是使用try catch,然后通过throw抛出异常错误,同时对其进行处理。

详细内容请查阅MDN

错误对象

  • message属性:错误相关信息
  • stack属性:函数调用栈记录信息

抛出的错误还有几个属性如:name(名称)、message(信息)、stack(函数调用栈信息)

详细内容请查阅MDN

二. Promise的理解与使用

现在让我们正式进入Promise的学习,这一章节将介绍原生Promise的相关知识,包括Promise是什么、为什么要使用Promise、如何使用Promise三个方面的相关知识。

Promise是什么

理解

  • 抽象表达:Promise是JS中进行异步编程的新的解决方案
  • 具体表达:
    • 从语法上说:Promise是一个构造函数
    • 从功能上说:promsie对象用来封装一个异步操作并可以获取其结果

Promise的状态改变

  • pending 变为 resolved
  • pending 变为 rejected

说明 :

  • 只有这两种 且一个promise对象只能改变一次
  • 无论变为成功还是失败都只会有一个结果数据
  • 成功的结果数据一般称为value 失败的结果一般称为reason

Promise的基本流程

Promise的基本使用

//1.创建一个新的promise对象
const p = new Promise((resolve, reject) => {
    //执行器函数
    //2.执行异步任务
    setTimeout(() => {
        const time = Date.now()

        if (time % 2 === 0) {
            //3.1成功调用resolve(value)
            resolve('成功的数据,time:' + time)
        } else {
            //3.2失败调用reject(reason)
            reject('失败的数据,time:' + time)
        }

    }, 1000)
})

p.then(
    //onResolved
    value => {
        //接收得到成功的value数据
        console.log('成功的回调',value);
    },
    //onRejected
    reason => {
        //接收得到失败的reason数据
        console.log('失败的回调',reason);
    }
)

为什么要使用Promise

指定回调函数的方式更加灵活

  • 旧的:必须在启动异步任务前指定
  • promise:启动异步任务 =>返回promise对象 =>给promise对象绑定回调函数(甚至可以在异步任务结束后指定)
//成功的回调函数
function successCallback(result) {
    console.log('文件创建成功' + result);
}
//失败的回调函数
function failureCallback(error) {
    console.log('文件创建失败' + error);
}

//1.1使用纯回调函数
createAudioFileAsync(audioSettings, successCallback, failureCallback)

//1.2使用Promise
const p = createAudioFileAsync(audioSettings)
setTimeout(() => {
    p.then(successCallback, failureCallback)
}, 3000)

支持链式调用 可以解决回调地狱问题

  • 什么是回调地狱?:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调函数执行的条件
  • 回调地狱的缺点:不便于阅读/不便于异步处理
  • 解决方案:promise链式调用
  • 终极解决方案 :async/await
//2.1回调地狱
doSomething(function (result) {
    doSomethingElse(result, function (finalResult) {
        doThirdThing(newResult, function (finalResult) {
            console.log('Get the final result:' + finalResult);
        }, failureCallback)
    }, failureCallback)
}, failureCallback)

//2.2使用promise的链式调用解决回调地狱
doSomething().then(function (result) {
    return doSomethingElse(result)
})
    .then(function (newResult) {
        return doThirdThing(newResult)
    })
    .then(function (finalResult) {
        console.log('Get the final result' + finalResult);
    })
    .catch(failureCallback) //异常穿透

//2.3 async/await: 回调地狱的终极解决方案
async function request() {
    try {
        const result = await doSomething()
        const newResult = await doSomethingElse(result)
        const finalResult = await doThirdThing(newResult)
        console.log('Get the final result' + finalResult);
    } catch (error) {
        failureCallback(error)
    }

}

如何使用Promise

API

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

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

说明:excutor会在Promise内部立即同步回调,异步操作在执行器中执行

2.Promise.prototype.then方法:(onResolved,onRejected)=>{}

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

说明:指定用于得到成功value的成功的回调和用于得到失败reason的失败回调

3.Promise.prototype.catch方法:(onRejected)=>{}

  • onRejected函数:失败的回调函数(reason)=>{}

说明:then()的语法糖,相当于:then(undefined,onRejected)

4.Promise.resolve方法:(value)=>{}

  • value:成功的数据或promise对象

说明:返回一个成功/失败的promise对象

5.Promise.reject方法:(reason)=>{}

  • reason:失败的原因

说明:返回一个失败的promise对象

6.Promise.all方法:(promise)=>{}

  • promises:包含n个promise的数组

说明:返回一个新的promise,只有所有的promise都成功才算成功,只要有一个失败就直接失败

7.Promise.race方法:(promises)=>{}

  • promises:包含n个promise的数组

说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的状态

new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('成功的数据')
        //reject('失败的数据') (无意义 状态只改变一次)
    }, 1000)
}).then(value => {
    console.log('onResolve', value);
}).catch(reason => {
    console.log('onRejected', reason);
})

//产生一个成功值为1的promise的对象
const p1 = new Promise((resolve, reject) => {
    resolve(1)
})
const p2 = Promise.resolve(2)
const p3 = Promise.reject(3)

p1.then(value => { console.log(value); })
p2.then(value => { console.log(value); })
p3.catch(reason => { console.log(reason); })

const pAll = Promise.all([p1, p2, p3])
pAll.then(
    values => { },
    reason => {
        console.log('all onRejected', reason);
    }
)

const pRace = Promise.race([p1, p2, p3])
pRace.then(
    value => {
        console.log('race onResolved', value);
    },
    reason => {
        console.log('race onRejected', reason);
    }
)

关键问题

1.如何改变promise的状态

  • resolve(value):如果当前是pendding就会变为resolved
  • reject(reason):如果当前是pennding就会变为rejected
  • 抛出异常:如果当前是pennding就会变为rejected
//1.如何改变promise的状态
const p = new Promise((resolve, reject) => {
    // resolve(1)// promise变为resolved成功状态
    // reject(2) // promise变为rejected成功状态
    // throw new Error('出错了!') //程序执行抛出异常 promise变为rejected reason为抛出的error
    throw 'error'
    //可以抛出任何
})
p.then(
    value => { },
    reason => { console.log('reason', reason); }
)

2.一个promise指定多个成功/失败回调函数,都会调用吗

  • 当promise改变为对应状态时都会调用
//2.一个promise指定多个成功/失败回调函数,都会调用吗
p.then(
    value => { },
    reason => { console.log('reason2', reason); }
)

3.改变promise状态和指定回调函数谁先谁后

  • 都有可能,正常情况下是指定回调再改变状态,但也可以先改状态再指定回调
  • 如何先改状态再指定回调
    • 在执行器中直接调用resolve()/reject
    • 延长更长时间才调用then()
  • 什么时候才能得到数据
    • 如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
    • 如果先改变状态,那当指定回调时,回调函数就会调用,得到数据
//3.改变promise状态和指定回调函数谁先谁后
//先指定回调函数后改变状态
const p2 = new Promise((resolve, reject) => {
   setTimeout(() => {//后改变回调函数(同时指定数据),异步执行回调函数
       resolve(2)
   }, 1000)
}).then(//先指定回调函数,保存当前指定的回调函数
   value => { },
   reason => { }
)

//先改变状态后指定回调函数
const p3 = new Promise((resolve, reject) => {
   //先改变回调函数(同时指定数据)
   resolve(3)
}).then(//后指定回调函数
   value => { },
   reason => { }
)

const p4 = new Promise((resolve, reject) => {
   //先改变回调函数(同时指定数据)
   setTimeout(() => {//后改变回调函数(同时指定数据),异步执行回调函数
       resolve(3)
   }, 1000)
})

setTimeout(() => {
   p4.then()
}, 1100)

4.peomise.then()返回新的promise的结果状态由什么决定

  • 简单表达:由then()指定的回调函数执行的结果决定
  • 详细表达:
    • 如果抛出异常,新promise变为rejected,reason为抛出的异常
    • 如果返回的是非promise的任意值,新promise变为resolved,value为返回值
    • 如果返回的是另一个新promise,此promise的结果就会成为新promise的结果
//4.peomise.then()返回新的promise的结果状态由什么决定
new Promise((resolve, reject) => {
    resolve('p5true')
    // reject('p5false')
}).then(
    value => {
        console.log('onResolved1()', value);
        // return 'true'
        // return Promise.resolve(5)
        // return Promise.reject(5)
        throw 5
    },
    reason => {
        console.log('onRejected1()', reason);
    }
).then(
    value => {
        console.log('onResolved2()', value);
    },
    reason => {
        console.log('onRejected2()', reason);
    }
)

5.promise如何串联多个操作任务

  • promise的then返回一个新的promise,可以看成then()的链式调用
  • 通过then的链式调用串联多个同步/异步任务
//5.promise如何串联多个操作任务
new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('执行异步任务一');
        resolve(1)
    }, 1000)
}).then(
    value => {
        console.log('任务一的结果:', value);
        console.log('执行同步任务二');
        return 2
    },
    reason => {
        console.log(reason);
    }
).then(
    value => {
        console.log('任务二的结果:', value);
        //启动异步任务三
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log('执行异步任务三');
                resolve(3)
            }, 1000)
        })
    }
).then(
    value => {
        console.log('任务三的结果:', value);
    }
)

6.promise异常传透

  • 当使用promise的then链式调用时,可以在最后指定失败的回调
  • 前面任何操作出了异常,都会传到最后失败的回调中处理
//6.promise异常传透
new Promise((resolve, reject) => {
    // resolve(61)
    reject(61)
}).then(
    value => {
        console.log('onResolved61', value);
        return 61
    },
    reason => { throw reason }
).then(
    value => {
        console.log('onResolved62', value);
        return 63
    },
    // reason => { throw reason }
    reason=> Promise.reject(reason)
).then(
    value => {
        console.log('onResolved63', value);
    },
    reason => { throw reason }
).catch(reason => {
    console.log('onRejected61', reason);
    // throw reason
    // return Promise.reject(reason)
    return new Promise(()=>{}) // 返回一个pendding的promise 中断promise链
}).then(
    value=>{
        console.log('onResolved()',value);
    },
    reason=>{
        console.log('onRejected()',reason);
    }
)

7.中断promise链

  • 当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
  • 办法:在回调函数中返回一个pendding状态的promise对象

三.自定义(手写)promise

定义整体结构

/* 
自定义Promise函数模块 IFIE
*/
//自调用函数表达式
(function (params) {
    /* 
        Promise构造函数
        excutor 执行器函数(同步执行)
    */
    function Promise(excutor) {

    }
    /* 
    Promise原型对象的then()
    指定成功和函数的回调函数
    返回一个新的promise对象
    */
    Promise.prototype.then = function (onResolved, onResolved) {

    }
    /* 
    Promise原型对象的catch()
    指定失败和函数的回调函数
    返回一个新的promise对象
     */
    Promise.prototype.catch = function (onResolved, onResolved) {

    }
    /* 
    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函数对象的reace方法
    返回一个promise,其结果由第一个完成的promise决定
    */
    Promise.reace = function (promises) {

    }
    //向外暴露Promise函数
    window.Promise = Promise
})(window)

构造函数实现与完善

function Promise(excutor) {
        //当前Promise对象保存起来
        const self = this
        self.status = 'pending' //给promise对象指定status属性,初始值为pending
        self.data = undefined //给promise对象指定一个用于存储结果数据的属性
        self.callbacks = [] //每个元素的结构:{onResolved(){},onRejected(){}}
        function resolve(value) {
            //如果当前状态不是pending,直接结束
            if (self.status !== 'pending') {
                return
            }
            //将状态改为resolved
            self.status = 'resolved'
            //保存value数据
            self.data = value
            //如果有待执行callback函数,立即异步执行回调函数onResolved
            if (self.callbacks.length > 0) {
                setTimeout(() => { //放入队列中执行所有成功的回调
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onResolved(value)
                    })
                })
            }
        }

        function reject(reason) {
            //如果当前状态不是pending,直接结束
            if (self.status !== 'pending') {
                return
            }

            //将状态改为rejected
            self.status = 'rejected'
            //保存value数据
            self.data = reason
            //如果有待执行callback函数,立即异步执行回调函数onResolved
            if (self.callbacks.length > 0) {
                setTimeout(() => { //放入队列中执行所有失败的回调
                    self.callbacks.forEach(callbacksObj => {
                        callbacksObj.onRejected(reason)
                    })
                })
            }
        }

        //立即同步执行excutor
        try {
            excutor(resolve, reject)
        } catch (error) { //如果执行器抛出异常,promise对象变为REJECTED状态
            reject(error)
        }

    }

自定义promise_then方法实现

    /* 
    Promise原型对象的then()
    指定成功和失败的回调函数
    返回一个新的promise对象
    返回promise的结果由onResolved/onRejected执行结果决定
    */
    Promise.prototype.then = function (onResolved, onRejected) {

        onResolved = typeof onResolved === 'function' ? onResolved : value => value //向后传递成功的value
        //指定默认的失败的回调(实现错误/异常传透的关键点)
        // onRejected = typeof onRejected === 'function' ? onRejected : reason => Promise.reject(reason)
        onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } //向后传递失败的reason

        const self = this

        //返回一个新的promise对象
        return new Promise((resolve, reject) => {
            //调用指定的回调函数处理,根据执行结果,改变promise的状态
            function handle(callback) {
                /* 
                    1.如果抛出异常,return的promise就会失败,reason就是error
                    2.如果回调函数执行返回非promise,return的promise就会成功,value就是返回的值
                    3.如果回调函数返回的是promise,return的promise结果就是根据这个promise的结果
                    */
                try {
                    const result = callback(self.data)
                    if (result instanceof Promise) {
                        //3.如果回调函数返回的是promise,return的promise结果就是根据这个promise的结果
                        /* result.then(
                            value =>
                                resolve(value)//当result成功时,让return的promise也成功
                            ,
                            reason =>
                                reject(reason)//当result失败时,让return的promise也失败
                        ) */
                        result.then(resolve, reject)
                    } else {
                        //2.如果回调函数执行返回非promise,return的promise就会成功,value就是返回的值
                        resolve(result)
                    }
                } catch (error) {
                    //1.如果抛出异常,return的promise就会失败,reason就是error
                    reject(error)
                }
            }
            //当前状态还是pending状态,将回调函数保存起来
            if (self.status === PENDING) {
                self.callbacks.push({
                    onResolved(value) {
                        handle(onResolved)
                    },
                    onRejected(reason) {
                        handle(onRejected)
                    }  
                })
            } else if (self.status === RESOLVED) {
                //当前状态是resolved状态,异步执行onResilve并改变并改变return的Promise状态
                setTimeout(() => {
                    handle(onResolved)
                })
            } else {
                //当前状态是rejected状态,异步执行onRejected并改变并改变return的Promise状态
                setTimeout(() => {
                    handle(onRejected)
                })
            }
        })
    }

Promise.resolve()/reject()的实现

Promise.resolve()

    /* 
    Promise函数对象的resolve方法
    返回一个指定value的成功的promise
    */
    Promise.resolve = function (value) {
        //返回一个成功/失败的promise
        return new Promise((resolve, reject) => {
            //value是promise 
            if (value instanceof Promise) {
                //使用value的结果作为promise的结果
                value.then(resolve, reject)
            } else {
                //value不是promise => promise变为成功,数据是value
                resolve(value)
            }
        })
    }

Promise.reject()

    /* 
    Promise函数对象的reject方法
    返回一个指定reason的失败的promise
    */
    Promise.reject = function (reason) {
        //返回一个失败的promise
        return new Promise((resolve, reject) => {
            reject(reason)
        })
    }

Promise.all()/race()的实现

Promise.all()

    /* 
    Promise函数对象的all方法
    返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败则失败
    */
    Promise.all = function (promises) {
        //用来保存所有成功value的数组
        const values = new Array(promises.length)
        //用来保存成功promise的数量
        let resolveCount = 0
        return new Promise((resolve, reject) => {
            //遍历获取每个promise的结果
            promises.forEach((p, index) => {
                Promise.resolve(p).then(
                    value => {
                        resolveCount++
                        //p成功,将成功的value保存values
                        //values.push(value)
                        values[index] = value
                        //如果全部成功,将return的promise改为成功
                        if(resolveCount === promises.length){
                            resolve(values)
                        }
                    },
                    reason => {
                        //只要有一个失败则整个都失败
                        reject(reason)
                    }
                )
            })
        })
    }

Promise.race()

    /* 
    Promise函数对象的reace方法
    返回一个promise,其结果由第一个完成的promise决定
    */
    Promise.race = function (promises) {
        return new Promise((resolve, reject) => {
            //遍历获取每个promise的结果
            promises.forEach((p, index) => {
                Promise.resolve(p).then(
                    value => {
                        //一旦有成功,将return变为成功
                        resolve(value)
                    },
                    reason => {
                        //只要有一个失败则整个都失败
                        reject(reason)
                    }
                )
            })
        })
    }

Promise.resolveDelay()/rejectDelay()的实现

    /* 
    返回一个promise对象,它在指定时间后才返回结果
    */
    Promise.resolveDelay = function (value, time) {
        //返回一个成功/失败的promise
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                //value是promise 
                if (value instanceof Promise) {
                    //使用value的结果作为promise的结果
                    value.then(resolve, reject)
                } else {
                    //value不是promise => promise变为成功,数据是value
                    resolve(value)
                }
            }, time)
        })
    }

    /* 
    返回一个promise对象,它在指定时间后才返回结果
    */
    Promise.rejectDelay = function (reason, time) {
        //返回一个失败的promise
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                reject(reason)
            }, time)
        })
    }

自定义Promise_class版本

/* 
自定义Promise函数模块 IFIE
*/
//自调用函数表达式
(function (params) {

    const PENDING = 'pending'
    const RESOLVED = 'resolved'
    const REJECTED = 'rejected'

    class Promise {
        /* 
            Promise构造函数
            excutor 执行器函数(同步执行)
        */
        constructor(excutor) {
            //当前Promise对象保存起来
            const self = this
            self.status = PENDING //给promise对象指定status属性,初始值为pending
            self.data = undefined //给promise对象指定一个用于存储结果数据的属性
            self.callbacks = [] //每个元素的结构:{onResolved(){},onRejected(){}}
            function resolve(value) {
                //如果当前状态不是pending,直接结束
                if (self.status !== PENDING) {
                    return
                }
                //将状态改为resolved
                self.status = RESOLVED
                //保存value数据
                self.data = value
                //如果有待执行callback函数,立即异步执行回调函数onResolved
                if (self.callbacks.length > 0) {
                    setTimeout(() => { //放入队列中执行所有成功的回调
                        self.callbacks.forEach(callbacksObj => {
                            callbacksObj.onResolved(value)
                        })
                    })
                }
            }

            function reject(reason) {
                //如果当前状态不是pending,直接结束
                if (self.status !== PENDING) {
                    return
                }

                //将状态改为rejected
                self.status = REJECTED
                //保存value数据
                self.data = reason
                //如果有待执行callback函数,立即异步执行回调函数onResolved
                if (self.callbacks.length > 0) {
                    setTimeout(() => { //放入队列中执行所有失败的回调
                        self.callbacks.forEach(callbacksObj => {
                            callbacksObj.onRejected(reason)
                        })
                    })
                }
            }

            //立即同步执行excutor
            try {
                excutor(resolve, reject)
            } catch (error) { //如果执行器抛出异常,promise对象变为REJECTED状态
                reject(error)
            }

        }
        /* 
        Promise原型对象的then()
        指定成功和失败的回调函数
        返回一个新的promise对象
        返回promise的结果由onResolved/onRejected执行结果决定
        */
        then(onResolved, onRejected) {

            onResolved = typeof onResolved === 'function' ? onResolved : value => value //向后传递成功的value
            //指定默认的失败的回调(实现错误/异常传透的关键点)
            // onRejected = typeof onRejected === 'function' ? onRejected : reason => Promise.reject(reason)
            onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason } //向后传递失败的reason

            const self = this

            //返回一个新的promise对象
            return new Promise((resolve, reject) => {
                //调用指定的回调函数处理,根据执行结果,改变promise的状态
                function handle(callback) {
                    /* 
                        1.如果抛出异常,return的promise就会失败,reason就是error
                        2.如果回调函数执行返回非promise,return的promise就会成功,value就是返回的值
                        3.如果回调函数返回的是promise,return的promise结果就是根据这个promise的结果
                        */
                    try {
                        const result = callback(self.data)
                        if (result instanceof Promise) {
                            //3.如果回调函数返回的是promise,return的promise结果就是根据这个promise的结果
                            /* result.then(
                                value =>
                                    resolve(value)//当result成功时,让return的promise也成功
                                ,
                                reason =>
                                    reject(reason)//当result失败时,让return的promise也失败
                            ) */
                            result.then(resolve, reject)
                        } else {
                            //2.如果回调函数执行返回非promise,return的promise就会成功,value就是返回的值
                            resolve(result)
                        }
                    } catch (error) {
                        //1.如果抛出异常,return的promise就会失败,reason就是error
                        reject(error)
                    }
                }
                //当前状态还是pending状态,将回调函数保存起来
                if (self.status === PENDING) {
                    self.callbacks.push({
                        onResolved(value) {
                            handle(onResolved)
                        },
                        onRejected(reason) {
                            handle(onRejected)
                        }
                    })
                } else if (self.status === RESOLVED) {
                    //当前状态是resolved状态,异步执行onResilve并改变并改变return的Promise状态
                    setTimeout(() => {
                        handle(onResolved)
                    })
                } else {
                    //当前状态是rejected状态,异步执行onRejected并改变并改变return的Promise状态
                    setTimeout(() => {
                        handle(onRejected)
                    })
                }
            })
        }
        /* 
        Promise原型对象的catch()
        指定失败和函数的回调函数
        返回一个新的promise对象
         */
        catch(onRejected) {
            return this.then(undefined, onRejected)
        }
        /* 
        Promise函数对象的resolve方法
        返回一个指定value的成功的promise
        */
        static resolve = function (value) {
            //返回一个成功/失败的promise
            return new Promise((resolve, reject) => {
                //value是promise 
                if (value instanceof Promise) {
                    //使用value的结果作为promise的结果
                    value.then(resolve, reject)
                } else {
                    //value不是promise => promise变为成功,数据是value
                    resolve(value)
                }
            })
        }
        /* 
        Promise函数对象的reject方法
        返回一个指定reason的失败的promise
        */
        static reject = function (reason) {
            //返回一个失败的promise
            return new Promise((resolve, reject) => {
                reject(reason)
            })
        }
        /* 
        Promise函数对象的all方法
        返回一个promise,只有当所有promise都成功时才成功,否则只要有一个失败则失败
        */
        static all = function (promises) {
            //用来保存所有成功value的数组
            const values = new Array(promises.length)
            //用来保存成功promise的数量
            let resolveCount = 0
            return new Promise((resolve, reject) => {
                //遍历获取每个promise的结果
                promises.forEach((p, index) => {
                    Promise.resolve(p).then(
                        value => {
                            resolveCount++
                            //p成功,将成功的value保存values
                            //values.push(value)
                            values[index] = value
                            //如果全部成功,将return的promise改为成功
                            if (resolveCount === promises.length) {
                                resolve(values)
                            }
                        },
                        reason => {
                            //只要有一个失败则整个都失败
                            reject(reason)
                        }
                    )
                })
            })
        }
        /* 
        Promise函数对象的reace方法
        返回一个promise,其结果由第一个完成的promise决定
        */
        static race = function (promises) {
            return new Promise((resolve, reject) => {
                //遍历获取每个promise的结果
                promises.forEach((p, index) => {
                    Promise.resolve(p).then(
                        value => {
                            //一旦有成功,将return变为成功
                            resolve(value)
                        },
                        reason => {
                            //只要有一个失败则整个都失败
                            reject(reason)
                        }
                    )
                })
            })
        }

        /* 
        返回一个promise对象,它在指定时间后才返回结果
        */
        static resolveDelay = function (value, time) {
            //返回一个成功/失败的promise
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    //value是promise 
                    if (value instanceof Promise) {
                        //使用value的结果作为promise的结果
                        value.then(resolve, reject)
                    } else {
                        //value不是promise => promise变为成功,数据是value
                        resolve(value)
                    }
                }, time)
            })
        }

        /* 
        返回一个promise对象,它在指定时间后才返回结果
        */
        static rejectDelay = function (reason, time) {
            //返回一个失败的promise
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    reject(reason)
                }, time)
            })
        }
    }



    //向外暴露Promise函数
    window.Promise = Promise
})(window)

四.async与await

mdn 文档

async函数

  • 函数的返回值为promise对象
  • promise对象的结果由async函数执行的返回值决定

await表达式

  • await右侧的表达式一般为promise对象,但也可以是其它的值
  • 如果表达式是promise对象,await返回的是promise成功的值

五.JS异步之宏队列与微队列

原理图

说明

  • js中用来存储待执行回调 函数的队列包含2个不同特定的列队
  • 宏列队:用来保存待执行的宏任务(回调),比如:定时器回调/DOM事件回调/ajax回调
  • 微列队:用来保存待执行的微任务(回调),比如: promise的回调/MutationObserver的回调
  • js执行时会区别这2个队列
    • (1)JS引擎首先必须先执行所有的初始化同步任务代码
    • (2)每次准备取出第一个宏任务执行前,都要将所有的微任务一个一个取出来执行

六.练习题

下面有几道练习题分享给大家,请把你的答案留在评论区😉

setTimeout(()=>{
    console.log(1);
},0)
Promise.resolve().then(()=>{
    console.log(2);
})
Promise.resolve().then(()=>{
    console.log(4);
})
console.log(3);
setTimeout(()=>{
    console.log(1);
},0)
new Promise((resolve)=>{
    console.log(2);
    resolve()
}).then(()=>{
    console.log(3);
}).then(()=>{
    console.log(4);
})
console.log(5);
const first = () =>
(new Promise((resolve, reject) => {
    console.log(3);
    let p = new Promise((resolve, reject) => {
        console.log(7);
        setTimeout(() => {
            console.log(5);
            resolve(6)
        }, 0)
        resolve(1)
    })
    resolve(2)
    p.then((arg) => {
        console.log(arg);
    })
}))

first().then((arg) => {
    console.log(arg);
})
console.log(4);
setTimeout(() => {
    console.log(0);
}, 0)
new Promise((resolve, reject) => {
    console.log(1);
    resolve()
}).then(() => {
    console.log(2);
    new Promise((resolve, reject) => {
        console.log(3);
        resolve()
    }).then(() => {
        console.log(4);
    }).then(() => {
        console.log(5);
    })
}).then(() => {
    console.log(6);
})

new Promise((resolve, reject) => {
    console.log(7);
    resolve()
}).then(() => {
    console.log(8);
})

总结

以上就是Promise从入门到自定义的全部内容,欢迎各位的意见纠正。

我是Atrox,一个正在努力学习的前端工程狮🦁。希望得到你的关注,我也会继续分享学习和生活中的点点滴滴,点个赞再走吧😘!

我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿