聊一聊 Promise中then方法的各种骚操作

10 篇文章 1 订阅

先说一下微任务:

微任务队列:

异步任务需要适当的管理。为此,ECMA 标准规定了一个内部队列 PromiseJobs,通常被称为“微任务队列(microtask queue)”(ES8 术语)

  • 队列(queue)是先进先出的:首先进入队列的任务会首先运行。

  • 只有在 JavaScript 引擎中没有其它任务在运行时,才开始执行任务队列中的任务。

    https://zh.javascript.info/microtask-queue

“任务队列"是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列”,就是读取里面有哪些事件。https://www.ruanyifeng.com/blog/2014/10/event-loop.html

​ ——阮一峰

我的理解:微任务队列其实就是一些事件的傀儡队列,这个傀儡就是回调函数,当主线程任务完成之后,开始读取微任务队列中的事件时,就是去执行事件对应的回调函数。

ps:(可以想象成一个工作狂,他会提前准备一个框框(微任务队列)放一些当前任务中可以慢慢处理的其他任务,然后先去做他当前的主要的工作,做完主要工作就回去检查这个框框,这个框的任务也做完了,就去问老大(宏任务队列)还有没有下一个任务(下一个宏任务))

微任务中也可以有微任务,所以会有无限套娃的风险。https://developer.mozilla.org/zh-CN/docs/Web/API/HTML_DOM_API/Microtask_guide

promise中的then方法:

在这里插入图片描述

  1. 明确then的回调函数是什么时候进入微任务队列的

思否:https://segmentfault.com/q/1010000022578087
我觉得这个答案更符合我的理解:
then的回调函数什么时候进入PromiseJobs取决于then方法前一个promise的状态,
如果调用 then 时 promise 是 pending 状态,回调会进入 promise 的 [[PromiseFulfill/RejectReactions]] 列表里;否则会进入 PromiseJobs。

看例子:

eg1(调用then的promise状态为pending):
new Promise(()=>{}).then((res)=>{console.log("我是then"+res)})
console.log("我是同步的")
输出:
"我是同步的"
结论:如果调用 then 时 promise 是 pending 状态,回调会进入 promise 的[[PromiseFulfill/RejectReactions]] 列表里等待执行;
eg2(调用then的promise状态不为pending):
new Promise((res)=>{res(1)}).then((res)=>{console.log("我是then:"+res)})
console.log("我是同步的")
输出:
"我是同步的"
"我是then:1"
结论:
如果调用 then 时 promise 不是 pending 状态,则会进入 PromiseJobs,待同步任务执行完,则执行PromiseJobs中的任务
eg3:
new Promise((res)=>{}).then(console.log("我是then"))
console.log("我是同步的")
输出:
"我是then"
"我是同步的"
思考:调用then的promise是pending状态,为什么"我是then"还是会打印?👇
eg4:
new Promise((res)=>{res(1)}).then(console.log("我是then"))
console.log("我是同步的")
输出:
"我是then"
"我是同步的"
思考:????为什么还是会打印👇

👇👇👇

  1. then方法的参数

    then方法接受两个参数(onFulfilled, onRejected)

    1. If onFulfilled is not a function, it must be ignored.

    2. If onRejected is not a function, it must be ignored.

      ​ 文档——https://promisesaplus.com/

    上面说的很清楚,如果接受的参数不是一个函数,那么必须被忽略(不管他)所以会有值穿透的情况

    好,再来看看上面的思考:

    new Promise(()=>{}).then(console.log("我是then"))
    console.log("我是同步的")
    
    首先明确一点:console.log是一个方法,也就是一个函数,所以你再看看你then里面传的是什么,是console.log("xxxxxx"),所以你在这里同步立即执行这个函数,然后把这个函数的返回值传到then里面去,所以相当于你在then里面传了一个值undefined
    
    不信,我们来看看:
    new Promise((res)=>{res(1)}).then(console.log("我是then"))
    console.log("我是同步的")
    这个输出和上面一样,但是不一样的是,调用then的promise有结果  1 ,且状态不是pending
    所以就算中间的then会被忽略,再调用一个正常then还是可以接受到数据
    
    new Promise((res)=>{res(1)})
        .then(console.log("我是then"))
        .then(res=>{console.log("promise的结果:"+res)})
    console.log("我是同步的")
    输出:
    "我是then"
    "我是同步的"
    "promise的结果:1"
    
    不信再来:
    new Promise(()=>{})
        .then((function(){console.log(2)})())//中间这个then传入一个立即执行的函数效果和上面一样
        .then(res=>{console.log(res)})
    console.log("我是同步的")
    输出:
    2
    "我是同步的"
    
    好了,到了这里应该都明白了,接下来,看一下then添加回调函数的写法:https://wangdoc.com/javascript/async/promise.html#promiseprototypethen
    
    let func = function() {
        return new Promise((resolve, reject) => {
            resolve('我是老大new Promise');
        });
    };
    
    let cb = function() {
        return '我是回调函数的返回值';
    }
    // 1. 
    func().then(function () {
        return cb();//这一句等同于 return '我是回调函数的返回值'
    }).then(resp => {
        console.warn(resp);  // 输出 '我是回调函数的返回值'
        console.warn('1 =========<');
    });
    // 2. 
    func().then(function () {
        cb();//在这个函数里面只是执行了一下cb函数,但是没有返回任何东西:所以默认返回undefined
        return undefined
    }).then(resp => {
        console.warn(resp);// 输出: undefined
        console.warn('2 =========<');
    });
    // 3. 
    func()
        .then(cb())// 这个then里面传入的相当于是cb函数的返回值 '我是回调函数的返回值',所以发生值穿透
        .then(resp => {
            console.warn(resp); // 值穿透 ——>  输出:'我是老大new Promise'
            console.warn('3 =========<');
    });
    // 4. 
    func().then(cb)// 这里的then里面传入的是一个函数,而不是一个值,所以内部会对这个函数进行一个封装,返回'我是回调函数的返回值'
        .then(resp => {
            console.warn(resp); //输出:'我是回调函数的返回值'
            console.warn('4 =========<');
    });
    内部封装大致如下:👇👇
    
    .then(new Promise((res,rej)=>{
            res(cb());
        }))
    

在这里插入图片描述

在这里插入图片描述

console.log()和console.log是不一样的

then方法内部会进行一个判断:看是否是函数

  1. 当then里面传入console.log时,相当于传入了一个函数log,于是promise的函数执行器就会帮你调用new Promise(),去调用这个函数,

    传入console.log时,在then中相当于发生如下过程
    new Promise(res=>res(1)).then(()=>{
    		return new Promise((res,rej)=>{
                res(console.log());
            })
    	})
    
  2. 当then里面传入console.log()时,相当于传入了一个非函数,也就是console.log()这个函数的返回值undefined,所以会发生值穿透,所以上面第二种情况,先打印2,再打印new Promise中的res的参数值

在这里插入图片描述

  1. then的回调方法的注册时机(事件机制是先注册再执行)

注册时机其实还是看调用then的promise状态,只要promise状态改变了,其调用的then的方法就会被注册,但是还没有被执,执行再按照注册顺序进行

https://juejin.cn/post/6844903987183894535

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
下面是手写一个简单的 Promise.then() 方法的实现方式: ```javascript function MyPromise(executor) { this.status = 'pending'; this.value = undefined; this.onResolvedCallbacks = []; const resolve = (value) => { if (this.status === 'pending') { this.status = 'fulfilled'; this.value = value; this.onResolvedCallbacks.forEach((callback) => { callback(this.value); }); } }; executor(resolve); } MyPromise.prototype.then = function (onResolved) { return new MyPromise((resolve) => { if (this.status === 'fulfilled') { // 如果状态已经是 fulfilled,则直接执行回调函数 resolve(onResolved(this.value)); } else { // 如果状态还是 pending,则将回调函数加入到待执行列表 this.onResolvedCallbacks.push((value) => { resolve(onResolved(value)); }); } }); }; // 使用示例 const p = new MyPromise((resolve) => { setTimeout(() => { resolve('Hello, World!'); }, 2000); }); p.then((value) => { console.log(value); // 输出: 'Hello, World!' }).then(() => { console.log('Done'); }); ``` 在上述代码,我们定义了一个 `MyPromise` 构造函数,它接受一个执行器函数 `executor`,并创建一个新的 Promise 对象。在 `MyPromise` 的原型上定义了 `then` 方法,用于添加回调函数。 在 `then` 方法,我们首先判断当前 Promise 的状态。如果状态是已完 (`fulfilled`),则直接执行传入的回调函数 `onResolved`,并使用 `resolve` 方法创建一个新的 Promise 对象,并将回调函数的返回值作为新 Promise 的值传递。 如果状态仍然是待定 (`pending`),则将回调函数加入到待执行列表 `onResolvedCallbacks` 。当 Promise 的状态变为已完时,会依次执行待执行列表的回调函数,并传递相应的值。 需要注意的是,上述实现只是 Promise.then() 方法的简化版本,并没有考虑到其他情况(如错误处理、链式调用等)。完整的 Promise 实现还包括对这些情况的处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

summer·

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值