《JavaScript》异步编程(三)深入浅出Promise,附大厂真题面经

setTimeout(() => {

return res+1

}, 1000)

}).then(res => {

console.log(res)

})

原因是.then虽然返回的是promise但是它是同步的,并不会等你的异步代码执行完毕后再执行,那么如果.then都是异步代码怎么办,答案很简单,new 一个promise呗

new Promise((resolve) => {

console.log(1)

setTimeout(() => {

resolve(2)

}, 1000)

}).then(res => {

console.log(res)

return new Promise(resolve => {

setTimeout(() => {

resolve(res + 1)

}, 1000)

})

}).then(res => {

console.log(res);

return new Promise(resolve => {

setTimeout(() => {

resolve(res + 1)

}, 1000)

})

}).then(res => {

console.log(res)

return new Promise(resolve => {

setTimeout(() => {

resolve(res + 1)

}, 1000)

})

}).then(res => {

console.log(res)

})

API

=============================================================

静态方法


Promise.resolve(param)

这个方法等同于下方代码,实际上就是在做一个resolve的操作

new Promise((resolve,reject)=>{

resolve(param)

})

Promise.reject(param)

同样,这个方法等同于下方代码,实际上在做一个reject的操作

new Promise((resolve,reject)=>{

reject(param)

})

Promise.all([p1,p2…,pn])

这个方法就比较特殊了,它接收一个数组作为参数,数组的每一项都是一个Promise,只当数组的每一项Promise的状态都变成fulfilled,其结果才会变成fulfilled,只要有一个处于reject状态,那么这个Promise就是reject状态;

这个方法最常用的地方就是,当我们项目中的某个接口,它的参数取决于其他多个接口的返回,因此这个接口的触发必须需要等所有接口都有返回之后才出发,这样就可以使用Promise.all

Promise.allSetted([p1,p2…,pn])

这个函数的用法和all很接近,也是接收一组Promise作为参数,区别在于,Promise.allSetted的结果是一定的,只要当这组Promise的状态都改变了,不管是fulfilled还是reject,那么这个Promise.allSetted的这个Promise就会变成fulfilled;

Promise.race([p1,p2…,pn])

Prmoise.race()也接收一组Promise作为参数,它代表的是这组Promise有且只要有一个Promise的状态发生变化了,那么Prmoise.race的状态也就跟随其发生变化;

实例方法


promise.then(onFulfilled,onReject)

promise状态改变后的回调,返回新的promise对象

promise.catch(error)

这个catch等同于promise状态为reject时的回调;

promise.then((null,onReject)=>{

// …

})

promise.finally(()=>{})

等同于

promise.then(()=>{

// …

},()=>{

// …

})

这也就导致了,不管promise的状态如何变化,一定会执行函数;

手写Promise

===================================================================

这个环节,主要简单的实现一下Promise,目的是为了更好的了解Promise的细节,实际项目中,我想没有任何一家公司会说,官方的Promise不行,你自己实现一个…这要是存在,太不科学了,还有一种情况,是招聘,但即使是招聘,也很少会遇到说要手写一个Promise,笔试的单位现在都不多了吧,何况还要手写实现一个Promise,太夸张了,面试过程中更多应该是问到原理性质问题。

实现


根据Promises/A+规范,Promise是一个对象或者说是方法,它有一个then方法,有一个catch方法,以及最后一个findlly方法,这里最后一种不弄了,仅以常用的then和catch为例

第一步:定义一个Promise的类,并且它有then方法和catch方法

class Promise {

constructor() {}

then() {}

catch () {}

}

第二步:我们知道Promise有三种状态,分别是:待定(pending),已兑现(fulfilled),已拒绝(rejected),

那么我们自然而言也要定义这三种状态,并且初始状态是pending;

// 状态

const STATUS = {

PENDING: “pending”,

FULFILLED: “fulfilled”,

REJECTED: “reject”

}

// 实现Promise

class Promise {

constructor() {

this.status = STATUS.PENDING;

}

then() {}

catch () {}

}

第三步:根据规范的术语部分,还有一些别的参数,同时Promise接收一个函数作为参数,并且该函数接收两个函数作为参数,这两个函数就是使用Promise时的resolve和reject

// 状态

const STATUS = {

PENDING: “pending”,

FULFILLED: “fulfilled”,

REJECTED: “reject”

}

// 实现Promise

class Promise {

constructor(fn) {

// 状态

this.status = STATUS.PENDING;

// 值

this.value = undefined;

// 原因

this.reason = undefined;

fn(() => {}, () => {})

}

then() {}

catch () {}

}

第四步:这两个参数,第一个可以使当前这个Promise的状态变成fulfilled,第二个可以使当前这个Promise变成reject

// 状态

const STATUS = {

PENDING: “pending”,

FULFILLED: “fulfilled”,

REJECTED: “reject”

}

// 将Promise设置成fulfilled

function fulfilledPromise(promise, value) {

// 这里加一个判断,在规范中说,只有处于pending状态的Promise才可以改变状态

if (promise.status !== STATUS.PENDING) {

return;

}

promise.status = STATUS.FULFILLED;

promise.value = value;

}

// 将Promise设置成reject

function rejectPromise(promise, reason) {

// 同样不能改变

if (promise.status !== STATUS.PENDING) {

return;

}

promise.status = STATUS.REJECTED;

promise.reason = reason;

}

// 实现Promise

class Promise {

constructor(fn) {

// 状态

this.status = STATUS.PENDING;

// 值

this.value = undefined;

// 原因

this.reason = undefined;

fn((value) => {

// 将this传递进去,用于改变当前Promise的状态

// value则是使用promise时,会传递值进去用作后面.then的值,相当于resolve(value)

fulfilledPromise(this, value)

}, (reason) => {

// 和fulfilledPromise一样

rejectPromise(this, reason)

})

}

then() {}

catch () {}

}

在这一步,我们确认了一但稳定了Promise的状态,就不能再改变了;

第五步:实现then方法,then方法在规范上也有定义,then方法有两个参数,一个参数是onFulfilled,它代表状态变成fulfilled时执行,另一个则是onRejected,它代表状态变成reject执行,值的注意的是,这两个方法返回的也是Promise

// 状态

const STATUS = {

PENDING: “pending”,

FULFILLED: “fulfilled”,

REJECTED: “reject”

}

// 将Promise设置成fulfilled

function fulfilledPromise(promise, value) {

// 这里加一个判断,在规范中说,只有处于pending状态的Promise才可以改变状态

if (promise.status !== STATUS.PENDING) {

return;

}

promise.status = STATUS.FULFILLED;

promise.value = value;

// 执行

runCbs(promise.fulfiledCbs, value);

}

// 将Promise设置成reject

function rejectPromise(promise, reason) {

// 同样不能改变

if (promise.status !== STATUS.PENDING) {

return;

}

promise.status = STATUS.REJECTED;

promise.reason = reason;

// 执行

runCbs(promise.rejectedCbs, reason);

}

function isFunction(value) {

return Object.prototype.toString.call(value) === “[object Function]”;

}

function resolvePromise(promise, value) {

}

function rejectPromise(promise, value) {

}

// 执行队列

function runCbs(cbs, value) {

cbs.forEatch(cb => cb(value))

}

// 实现Promise

class Promise {

constructor(fn) {

// 状态

this.status = STATUS.PENDING;

// 值

this.value = undefined;

// 原因

this.reason = undefined;

// then fulfilled的处理队列,因为then可以有很多个,并且按顺序执行

this.fulfiledCbs = [];

// 同样then rejected可能也有很多个…

this.rejectedCbs = [];

fn((value) => {

// 将this传递进去,用于改变当前Promise的状态

// value则是使用promise时,会传递值进去用作后面.then的值,相当于resolve(value)

fulfilledPromise(this, value)

}, (reason) => {

// 和fulfilledPromise一样

rejectPromise(this, reason)

})

}

// 两个参数,一个参数是onFulfilled,一个参数是onRejected

then(onFulfilled, onRejected) {

const promiseCurrent = this;

const promiseReturn = new Promise(() => {});

// then的执行取决于当前Promise的状态

// 状态等于fulfilled

if (promiseCurrent.status === STATUS.FULFILLED) {

// 判断是onFulfilled是否是函数

if (!isFunction(onFulfilled)) {

// 将老的直接返回出去

return promiseCurrent;

}

// 使用setTimeout模拟异步

setTimeout(() => {

try {

// 值传进去,并且实现reslove(value)

const value = onFulfilled(promiseCurrent.value);

resolvePromise(promiseReturn, value)

} catch (error) {

rejectPromise(promiseReturn, error);

}

}, 0)

}

// 状态等于reject

if (promiseCurrent.status === STATUS.REJECTED) {

// 判断是onRejected是否是函数

if (!isFunction(onRejected)) {

// 将老的直接返回出去

return promiseCurrent;

}

// 使用setTimeout模拟异步

setTimeout(() => {

try {

// 值传进去,并且实现reslove(value)

const reason = onRejected(promiseCurrent.value);

resolvePromise(promiseReturn, reason)

} catch (error) {

rejectPromise(promiseReturn, error);

}

}, 0)

}

// 状态等于pending

if (promiseCurrent.status === STATUS.PENDING) {

// 如果状态处于pending状态,那么代表第一个Primise还处于处理中的状态,必须要等到状态稳定

// 将成功的存入队列,同时要模拟异步

promiseCurrent.fulfiledCbs.push(setTimeout(() => {

try {

// 值传进去,并且实现reslove(value)

const value = onFulfilled(promiseCurrent.value);

resolvePromise(promiseReturn, value)

} catch (error) {

rejectPromise(promiseReturn, error);

}

}), 0)

// reject也要存,同时要模拟异步

promiseCurrent.rejectedCbs.push(setTimeout(() => {

try {

// 值传进去,并且实现reslove(value)

const reason = onRejected(promiseCurrent.value);

resolvePromise(promiseReturn, reason)

} catch (error) {

rejectPromise(promiseReturn, error);

}

}), 0)

}

return promiseReturn

}

catch () {}

}

第六步:其实到这里,then方法已经差不多了,唯一差的就还是resolvePromise这两个,这两个的作用是对Promise进行解析,这个解析的过程就相对比较复杂了;另外,这一部分解析其实在规范里面都有写流程,代码就是根据这个流程实现的;

// 状态

const STATUS = {

PENDING: “pending”,

FULFILLED: “fulfilled”,

REJECTED: “reject”

}

// 将Promise设置成fulfilled

function fulfilledPromise(promise, value) {

// 这里加一个判断,在规范中说,只有处于pending状态的Promise才可以改变状态

if (promise.status !== STATUS.PENDING) {

return;

}

promise.status = STATUS.FULFILLED;

promise.value = value;

// 执行

runCbs(promise.fulfiledCbs, value);

}

// 将Promise设置成reject

function rejectPromise(promise, reason) {

// 同样不能改变

if (promise.status !== STATUS.PENDING) {

return;

}

promise.status = STATUS.REJECTED;

promise.reason = reason;

// 执行

runCbs(promise.rejectedCbs, reason);

}

function isFunction(value) {

return Object.prototype.toString.call(value) === “[object Function]”;

}

function isObject(value) {

return Object.prototype.toString.call(value) === “[object Object]”;

}

// 因为Promise是我们自己实现的,因此只要判断是否源自于我们定义的这个Promise

function isPromise(value) {

return value instanceof Promise

}

function resolvePromise(promise, x) {

// 规范上说,如果promsie等于x,那么就需要reject掉,不能循环调用

if (promise === x) {

rejectPromise(promise, new TypeError(“can be the same”));

return;

}

// 判断x是否是promise

if (isPromise(x)) {

// fulfilled

if (x.status === STATUS.FULFILLED) {

fulfilledPromise(promise, x.value);

return;

}

// reject

if (x.status === STATUS.REJECTED) {

rejectPromise(promise, x.reason);

return;

}

// pending

if (x.status === STATUS.PENDING) {

x.then(() => {

fulfilledPromise(promise, x.value);

}, () => {

rejectPromise(promise, x.reason);

})

return

}

return;

}

// x是对象或者函数

if (isObject(x) || isFunction(x)) {

let then;

// 标记,确保只调用一次;

let called = false;

try {

then = x.then;

} catch (error) {

rejectPromise(promise, error)

}

if (isFunction(then)) {

try {

then.call(x, (y) => {

if (called) {

return;

}

called = true;

resolvePromise(promise, y);

}, ® => {

if (called) {

return;

}

called = true;

rejectPromise(promise, r);

});

} catch (error) {

// 已经被拒绝掉了

if (called) {

return;

}

called = true;

rejectPromise(promise, error);

}

return;

}

// 不是function

else {

fulfilledPromise(promise, x);

return

}

}

// x不是是对象或者函数

else {

fulfilledPromise(promise, x);

return;

}

}

// 执行队列

function runCbs(cbs, value) {

cbs.forEatch(cb => cb(value));

}

// 实现Promise

class Promise {

constructor(fn) {

// 状态

this.status = STATUS.PENDING;

// 值

this.value = undefined;

// 原因

this.reason = undefined;

// then fulfilled的处理队列,因为then可以有很多个,并且按顺序执行

this.fulfiledCbs = [];

// 同样then rejected可能也有很多个…

this.rejectedCbs = [];

fn((value) => {

// 将this传递进去,用于改变当前Promise的状态

// value则是使用promise时,会传递值进去用作后面.then的值,相当于resolve(value)

fulfilledPromise(this, value);

}, (reason) => {

// 和fulfilledPromise一样

rejectPromise(this, reason);

})

}

// 两个参数,一个参数是onFulfilled,一个参数是onRejected

then(onFulfilled, onRejected) {

const promiseCurrent = this;

const promiseReturn = new Promise(() => {});

// then的执行取决于当前Promise的状态

// 状态等于fulfilled

if (promiseCurrent.status === STATUS.FULFILLED) {

// 判断是onFulfilled是否是函数

if (!isFunction(onFulfilled)) {

// 将老的直接返回出去

return promiseCurrent;

}

// 使用setTimeout模拟异步

setTimeout(() => {

try {

// 值传进去,并且实现reslove(value)

const value = onFulfilled(promiseCurrent.value);

resolvePromise(promiseReturn, value);

} catch (error) {

rejectPromise(promiseReturn, error);

}

}, 0)

}

// 状态等于reject

if (promiseCurrent.status === STATUS.REJECTED) {

// 判断是onRejected是否是函数

if (!isFunction(onRejected)) {

// 将老的直接返回出去

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

// 使用setTimeout模拟异步

setTimeout(() => {

try {

// 值传进去,并且实现reslove(value)

const value = onFulfilled(promiseCurrent.value);

resolvePromise(promiseReturn, value);

} catch (error) {

rejectPromise(promiseReturn, error);

}

}, 0)

}

// 状态等于reject

if (promiseCurrent.status === STATUS.REJECTED) {

// 判断是onRejected是否是函数

if (!isFunction(onRejected)) {

// 将老的直接返回出去

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-8tQuQwic-1712272066268)]

[外链图片转存中…(img-dfurWNr2-1712272066268)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

[外链图片转存中…(img-GtBZz3WN-1712272066269)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

今天的文章可谓是积蓄了我这几年来的应聘和面试经历总结出来的经验,干货满满呀!如果你能够一直坚持看到这儿,那么首先我还是十分佩服你的毅力的。不过光是看完而不去付出行动,或者直接进入你的收藏夹里吃灰,那么我写这篇文章就没多大意义了。所以看完之后,还是多多行动起来吧!

可以非常负责地说,如果你能够坚持把我上面列举的内容都一个不拉地看完并且全部消化为自己的知识的话,那么你就至少已经达到了中级开发工程师以上的水平,进入大厂技术这块是基本没有什么问题的了。

资料领取方式:戳这里前往免费领取

  • 18
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值