本文已参与「新人创作礼」活动,一起开启掘金创作之路。
提到Promise想必大家都不会陌生,Promise 是异步编程的一种解决方案,比传统的解决方案:回调函数和事件更合理、更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
Promise在前端开发中应用广泛,实际开发主要应用于封装axios请求、验证多个请求结果是否都是满足条件、合并请求结果并处理错误等等。本篇文章将带你从零开始了解Promise,熟悉Promise的概念与使用,完成自定义(手写)Promise,并且扩展一些其它功能,最后也会介绍异步编程的终极解决方案async
与await
的简单使用。除此之外,也会带领大家学习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 的事件循环(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,一个正在努力学习的前端工程狮🦁。希望得到你的关注,我也会继续分享学习和生活中的点点滴滴,点个赞再走吧😘!
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。