Promise原理分析

Promise原理分析及简单实现 前端日记 今天是前端日记的第五天,清楚了promise的使用后,接下来我们开始分析promise的原理以及做简单的实现,然后与大家一起分享。一个前端小白的学习之路。 promise分析 先上代码,实例化一个promise var promise = new Promise(function (resolve, reject) { //做一些异步操作 setTimeout(funct... 阅读详情

前言

最近讨论到了 Promise,此前知道也使用过它,但是对于其原理却不甚了解。

于是翻了翻 MDN 上的文档,又找了几篇文章看了看,研究了研究。

最终,自己尝试了一番,对于其原理也有所了解。

Promise的使用

先回顾一下 Promise 的使用。

这里只是简单的调用,如果需要系统学习,还是移步 MDN 上的文档。

new Promise((resolve) => {
    setTimeout(() => {
        console.log(1)
        resolve(1)
    })
})
.then((response) => (console.log(++response), response))
.then((response) => {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log(1)
            resolve(1)
        })
    })
})
.then((response) => (console.log(++response), response))

执行结果如下:

img

代码分析

一个 Promise 就是一个代表了异步操作最终完成或者失败的对象。

---- 摘自 MDN

第一步,实例化一个 Promise 对象。

它的参数就是一个函数,此函数会接受两个参数,分别是 resolve 和 reject。

当操作成功时,则执行 resolve。

当操作失败时,则执行 reject。

new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(1)
        resolve(1)
    })
})

回调之后的操作可以用其提供的 then 方法。

then 接受两个参数,分别是 resolve 和 reject。原理同上。

new Promise((resolve) => {
    setTimeout(() => {
        console.log(1)
        resolve(1)
    })
})
.then((response) => (console.log(++response), response))

从上述代码里可以看出,我们使用了 setTimeout。

也就是说,then 方法会在 setTimeout 里的方法之前执行。

如果没有 Promise 的特殊机制,输出的结果可能就是 undefined、undefined、1、1 了。

这就是 Promise 的魅力,也是我想要知道的地方。

原理分析

既然是要分析其原理,那么按照其特性和使用方式来仿造一个是一个不错的选择。(主要是我不知道它的源码是什么<(_ _)>)

基本结构

先实现实例化的部分。

从上面的代码,我们已经知道,实例化的时候,只需要传 一个参数 就可以了,同时这个 参数 是一个 函数。

从执行结果来看,在我们实例化的时候,这个 函数 已经 执行 了。

并且这个函数会接收到 两个参数,这 两个参数 都是 函数。

function PromiseDemo(foo) {
    if (typeof foo != 'function') {
        throw Error('Promise 的参数必须是函数')
    }

    // 成功后执行的函数
    let resolve = response => {}

    // 失败后执行的函数
    let reject = response => {}

    // 实例化后,立即执行函数
    foo(resolve, reject)
}

then 方法部分。

then 方法是 Promise 对象的一个方法,我们需要将其暴露出来。

同时,then 方法支持链式的调用,所以返回值肯定是一个 Promise 对象。

function PromiseDemo(foo) {
    // 成功后执行的函数
    let resolve = response => {}

    // 失败后执行的函数
    let reject = response => {}

    // 实现 then 函数
    let then = (onResolved, onRejected) => {
        return new PromiseDemo((resolved, rejected) => {
            // todo...
        })
    }

    // 实例化后,立即执行函数
    foo(resolve, reject)

    return {
        then: then
    }
}

到这里,基本的结构已经有了,我们已经可以执行相关代码了,就是还没有想要的效果。

属性完善

通过一开始的示例分析,我们可以看出,then 参数接收到的参数是从上层传递到下层的。

这句话有点绕,参数的参数。所以,Promise 对象就要有一个存放返回值的属性,这里就给它命名为 data。

同时,then 函数的参数,是在 setTimeout 执行之后才执行的。那么,Promise 对象就要有一个存放任务的列表,这里就给它命名为 queue。

到这里,问题就来了,什么时候应该将任务放入任务列表呢?是还没有执行的,还是执行成功的,还是执行失败的?

说到这里,我们就要有一个标识表明这个任务是处于什么状态,是未执行,还是已执行,还是执行失败。这里就给它命名为 state,值分别为 pending、resolved、rejected。

上述文字有点长,主要就是定义了 Promise 的三个属性:state、queue、data。

let state = 'pending'
    , queue = []
    , data

实现 then 函数

为什么不返回 this

上面分析实例的时候有说到,为了能够达成链式调用,我们在 then 函数的返回值要是一个 Promise 对象。

而且基础代码里编写的是直接实例化了一个新的对象,那么可能会造成疑惑,直接返回 this 不行么?

答案是否定的,原因很简单,是由于 Promise 自身的属性决定了不能直接返回 this,不然其中任何一个属性发生修改都会对后面的操作造成影响。

编码

回归正轨。

let then = (onResolved, onRejected) => {
    return new PromiseDemo((resolved, rejected) => {
        // todo...
    })
}

then 函数有两个参数,并且返回值是一个实例化的 Promise 对象。

也就是说,在处理的过程中,我们将会涉及四个函数,分别是:onResolved, onRejected, resolved, rejected。

先分析一下四个函数的执行情况。

如果之前的 Promise 尚未处理(使用的异步代码,比如:setTimeout, ajax ),那么当前的状态 state = 'pending',那我们就不能执行任何一个函数。

这个时候我们就要将这四个函数存储好,表明这属于同一个任务。

// 如果还没执行结束,则将任务推向队列,并返回
if (state == 'pending') {
    queue.push([onResolved, onRejected, resolved, rejected])
    return
}

如果之前的 Promise 已经执行,那么当前的状态 state = 'resolved' 或者 state = 'rejected'。

这个时候我们就要分辨到底是什么情况了。

// callback 是 then 函数两个参数中的一个
// next 是 Promise 成功失败函数中的一个
let callback, next
// 判断是否出错
if (state == 'resolved') {
    callback = onResolved
    next = resolved
} else {
    callback = onRejected
    next = rejected
}

当我们处理完之后,我们就要执行相关函数了。

callback(data)

为了能够将参数传递给下游,callback 的返回值需要直接给 next 使用。

next(callback(data))

好了,结束。

真的结束了么?

由于 callbak 是用户调用 then 函数传递过来的,那用户真的一定会传参数么?用户传过来的参数一定是一个函数么?那么直接执行 callback 就会有问题!!!

// 如果是函数,则直接执行
// 并将参数传递给下游
if (typeof callback == 'function') {
    next(callback(data))
    return
}
next(data)

好了,这样貌似没什么问题了,整理一下代码。

function then(onResolved, onRejected) {
    return new PromiseDemo((resolved, rejected) => {
        handle(onResolved, onRejected, resolved, rejected)
    })
}

function handle(onResolved, onRejected, resolved, rejected) {
    // 如果还没执行结束,则将任务推向队列,并返回
    if (state == 'pending') {
        queue.push([onResolved, onRejected, resolved, rejected])
        return
    }

    let callback, next
    // 判断是否出错
    if (state == 'resolved') {
        callback = onResolved
        next = resolved
    } else {
        callback = onRejected
        next = rejected
    }
    // 如果是函数,则直接执行
    // 并将参数传递给下游
    if (typeof callback == 'function') {
        next(callback(data))
        return
    }
    next(data)
}

实现 resolve 函数

相对于 then 函数的复杂,resolve 函数就相对简单点。

为了避免重复执行,这里直接将 state 置为 rejected。

先考虑一下,如果传过来的值是一个 Promise 对象,那我们该怎么处理?如果是一个非 Promise 对象的参数,该怎么处理?

由于 Promise 对象本身是拥有 then 函数的,我们应该执行它,这样这个对象处理后的值,会流转到下一层。

let resolve = response => {
    state = 'resolved'
    if (response && (typeof response == 'function' || typeof response == 'object')) {
        if (response.hasOwnProperty('then') && typeof response.then == 'function') {
            response.then.call(response, resolve, reject)
            return
        }
    }
    data = response
    runCallbacks()
}

这里有个 runCallbacks 是干嘛的呢?

还记得我们将未执行的任务放到 queue 中了不?那么当前的任务执行完,是不是该执行下一个任务了呢?

let runCallbacks = () => {
    queue.forEach(callback => handle.apply(null, callback))
}

OK,到这里,resolve 函数已经编写完成了。

实现其它

Promise 还有其它的一些方法,例如:reject、catch 等。

这里就不一一写了,下面该试验一下我们的 PromiseDemo 是否有用了。

demo 测试

先来源码

function PromiseDemo(foo) {
    if (typeof foo != 'function') {
        throw Error('Promise 的参数必须是函数')
    }

    let state = 'pending'
        , queue = []
        , data

    function then(onResolved, onRejected) {
        return new PromiseDemo((resolved, rejected) => {
            handle(onResolved, onRejected, resolved, rejected)
        })
    }

    function handle(onResolved, onRejected, resolved, rejected) {
        // 如果还没执行结束,则将任务推向队列,并返回
        if (state == 'pending') {
            queue.push([onResolved, onRejected, resolved, rejected])
            return
        }

        let callback, next
        // 判断是否出错
        if (state == 'resolved') {
            callback = onResolved
            next = resolved
        } else {
            callback = onRejected
            next = rejected
        }
        // 如果是函数,则直接执行
        // 并将参数传递给下游
        if (typeof callback == 'function') {
            next(callback(data))
            return
        }
        next(data)
    }

    let runCallbacks = () => {
        queue.forEach(callback => handle.apply(null, callback))
    }

    let reject = response => {
        state = 'rejected'
        data = response
        runCallbacks()
    }

    let resolve = response => {
        state = 'resolved'
        if (response && (typeof response == 'function' || typeof response == 'object')) {
            if (response.hasOwnProperty('then') && typeof response.then == 'function') {
                response.then.call(response, resolve, reject)
                return
            }
        }
        data = response
        runCallbacks()
    }

    try {
        foo(resolve, reject)
    } catch (e) {
        reject(e)
    }

    return {
        then: then
    }
}

执行一开始的 demo,结果如下:

img

流程图

说也说了,写也写了,整个流程是什么样子的呢?

img

参考资料

  1. Promise原理解析

  2. 深入理解 Promise

最后

终于写完了,有点啰嗦,基本上把我想表达的都表达出来了。

– EOF –
本文转载自IMJCW
原文链接:Promise原理分析

JavaScript 中的 Promise 进阶:手写实现与原理分析 本文旨在帮助读者深入理解 JavaScript Promise 的内部实现原理,通过手写一个简化版 Promise 来掌握其核心机制。内容涵盖 Promise 的基本概念、状态管理、then 方法实现、链式调用、错误处理等核心特性。从生活实例引入 Promise 概念解释 Promise 核心原理和状态机制分步骤手写实现 Promise分析 Promise 与事件循环的关系实际应用场景和常见问题解答Promise:表示一个异步操作的最终完成(或失败)及其结果值的对象。 阅读详情

相关推荐

AI大模型学习(13)小白也能学会的10分钟豆包大模型的python教程1

豆包AI大模型API是字节跳动推出的智能对话接口服务,开发者可以通过简单的HTTP请求调用强大的AI能力,实现智能问答、内容生成等功能。

isoft888的专栏,致力于C#/python分享物联网、大数据,神经网络的等领域,欢迎讨论交流! 1001

Promise使用踩坑

resolve只接受status为200 resolve函数只能接受响应状态码为200的,其它响应码都会丢给reject处理。我在项目中尝试用过201状态码,都直接被丢给reject处理了,搞得我debug半天。 then函数后应使用一个catch函数捕捉异常 当promise的then函数中发生了异常,将会抛给catch处理,所以应该在后面加一个catch捕捉异常,以更容易发现问题出在哪里,如果...

monkey-jie的博客 803

S型速度曲线C程序实现

S型速度曲线C语言程序实现 前言 S型曲线相较于梯形速度曲线具有运行更加平稳的特点,S型曲线共有八种运行情况,感兴趣可以查阅相关文献 代码段 #include <stdio.h> #include <math.h> #define FP64 double int main(void) { /**************************** 定义相关变量(需要映射到PLC寄存器才能进行监控) ***********************/ FP6

LSX312441548的博客 8392

如何将 Promise.then 中的值直接 return 出来

Promise 如何返回值,而不是返回 Promise 对象_为什么 Promise 返回值一直都是 undefined。都是 undefined。一、需求定义一个 foo 函数,在里面执行异步操作Promise 如何返回值,而不是返回 Promise 对象。实际开发中使用封装好的异步请求函数,为什么调用该函数返回的值一直都是 undefined。

islanddddddd的博客 2475

VisionPro脚本实战:用C#替代QuickBuild,让复杂定位项目代码更清爽

本文探讨了如何通过C#脚本重构VisionPro复杂定位项目,替代臃肿的QuickBuild架构。通过实战案例展示了脚本化开发如何减少60%代码量并提升35%运行效率,使项目更易维护。文章详细介绍了环境搭建、多模板定位重构及高级技巧,帮助开发者突破QuickBuild限制,实现更高效的视觉应用开发。

weixin_30417487的博客 502

非线性动力学_用MatCont分析非线性动力学方程组(一)

写在前面:笔者打算写两到三篇系列文章介绍MatCont,此为第一篇《用MatCont分析非线性动力学方程组(一)》。MatCont是一个基于Matlab而开发的免费工具包,专门用来做非线性动力学模型分叉、向量场、周期性等分析,符号(连续性)运算和数值(离散性)运算均适用。该工具的开发及研究项目由比利时Ghent大学的Willy Govaerts教授、荷兰Utrecht大学的Yuri Kuznets...

weixin_39700215的博客 2767

promise中的return

虽然第一个then有return值,但是包在了延迟任务里,就挂载起来了,这时候还是会继续执行第二个then返回的undefined。

秀秀的奇妙旅行 1806

从时序精度到视觉盛宴:PY32F030驱动WS2812的工程艺术与避坑指南

本文深入探讨了基于PY32F030微控制器驱动WS2812智能LED的完整解决方案。通过精确的时序控制、硬件PWM结合DMA传输技术,实现了稳定可靠的驱动效果,并提供了电源管理、信号完整性和常见问题排查等实用避坑指南,帮助开发者轻松应对严格的纳秒级时序挑战。

wind6的博客 120

Promise中的return的理解与补充

通过async/await去操作得到的对Promise象,也就是说,要想获取到Promise.then的返回值,就必须利用await获取,要想使用await,就必须在函数前面加上async。是Promise对象resolved的语法糖这也就是最终awaitPromise对象是返回的值的原因(这点可以深入看一下ES6的Promise)。由此肯定then中的return的结果是接下来链式写法then中的resolved参数,让我们看下官方文档如何描述。打印结果如下,问题解决。...

一缕阳光@的博客 5230

RK3588 EVB开发板原理图讲解【六】

该原理图展示了eMMC Flash与主控芯片之间的连接关系,以及相关的电源、信号线路和去耦电容等。

weixin_48721556的博客 1172

华为OD机考双机位C卷 - 评委评分 (Java & Python& JS & C/C++ & GO )

华为OD机考双机位C卷 - 评委评分 (OD上机考试双机位C卷)。提供在线OJ刷题。Java、C++、Python、GO语言、C语言、JavaScript题解,并提供完整思路讲解。

算法大师! 1750

前端 .then 返回有数据但是return 不出来 ,并 解决处理后的 Promise下的Object

.then 返回有数据但是return 不出来 ,并获取处理后的 Promise下的Object。 原因是:因为axios是异步操作,在获取返回值时请求操作还没有完成就已经完成了赋值操作,所以结果的undefined。当我打印了返回的return 值发现 并没有直接返回我想要的数据,而是在Promise 内部。当我封装完成后在内部打印发先我的数据能够拿到,但是return 的时候一直都市undefined.此时则需要对其进行处理改装成异步,即加上 async 和await 就可以了。

lzfengquan的博客 1684

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

promise原理分析

图解promise中的then运行轨迹: 文章地址: promise原理分析

weixin_40863414的博客 181

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Promise原理分析二

Promise原理分析二,对reject, resolve, race, all的全面解析~

哆啦咪^Pluser 1025

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Promise原理分析一

Promise对象用于异步计算。一个Promise对象代表着一个还未完成,但预期将来会完成的操作,一起探究Promise的原理。

哆啦咪^Pluser 2449

Promise:手写Promise,原理分析

源码地址:https://gitee.com/lagou-19-web-paid/practice/tree/master/promise 1- Promise 对象的基础模型 (同步,分析执行流程) Promise 是一个类,类接收的是一个构造函数,在执行类的时候这个构造函数也会同步执行。 构造函数在同步执行的时候,会传递俩个回调函数,分别是成功回调[resolve]、失败回调[reject]。 成功回调:回调函数内接收一个参数,可以是一个普通值,也可以是一个 Promise 对象。此阶段暂时只考虑

_midnight的博客 332

await原理 js_由 Promise 实现 async await 源码及原理分析

async-awaitasync-awaitconst _async = (func) => {const p = new Promise((resolve, reject) => {try {const value = func()if (((typeof value === 'object' && value !== null) || typeof value ==...

weixin_42510888的博客 698

promise是什么?简单分析promise原理

预备知识 回调函数 高级函数 发布-订阅模式 promise A+ 规范 promise是什么,能干什么 Promise是异步编程的一种解决方案,它可以解决异步回调地狱的问题,防止层层嵌套对程序代码带来的难维护性。既然带来了方便,我们就有必要学习它的原理以及底层实现,所以笔者就按照PromiseA+规范写了一个简单的Promise,并实现了Promise.all(),Promise.race(...

weixin_33898233的博客 944

ES6-Promise 原理分析

promise是什么 以下来自百度 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。 Promise对象有以下两个特点。 (1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:P...

qq_45516476的博客 1087

Promise介绍和原理分析

`Promise`是`JavaScript`中一种处理异步操作的对象。`Promise`对象代表了一个尚未完成、但最终将会完成的异步操作,并且可以通过`Promise`实例来获取该异步操作的结果或状态。`Promise`对象有三种状态:`pending(进行中)`、`fulfilled(已完成)`、`rejected(已拒绝)`。

Br不二 269

Promise工作原理分析

Promise Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值 描述 一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。 一个 Promise 必然处于以下几种状态之一: 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。

Niall_Tonshall的博客 895
上一篇: ES6对象的合并
下一篇: 499问题查询解决
IMJCW
博客等级 码龄10年 13粉丝 58原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值