Promise(一)极简版demo

Promise(一)极简版demo

前言

在所有的编程语言中,异步处理都是一个绕不开的话题。而在JS的这个话题中,Promise则是当之无愧的主角之一,这应该是我们日常用的最多的异步API了。从今天开始将更新一些有关Promise的笔记。

异步逻辑

先来看一个异步操作:

ini 复制代码
setTimeout(() => {
    data = 'result';
    return data;
}, 1000);

显然这样是无法获取结果的,那如果我们将代码修改一下:

ini 复制代码
let result = setTimeout(() => {
    // 异步获取结果
    data = 'result';
    return data;
}, 1000);

JS的主线程是同步运行的,当代码运行到这里的时候,根据setTimeout的机制,返回值result的值是该定时器的ID。所以此处也无法获取值。既然已经联想到JS的机制了,或许我们可以考虑,使用变量赋值:

javascript 复制代码
let data = ''
setTimeout(() => {
    data = 'result';
}, 1000)
console.log(data); // ''
setTimeout(() => {
    console.log(data);
}, 1001); // 1001ms后,打印出来的结果是result

也就是说,变量赋值是有效的,只是如何抓住异步执行完的时机呢?毕竟我们没法估计实际的异步操作时间。

那么最好的办法就是把具体操作也放到异步逻辑中去,这样就可以利用JS的线性执行和任务队列来帮助我们抓住这个Timing:

ini 复制代码
setTimeout(() => {
    data = 'result';
    console.log(data);
}, 1000)
​
const handler = (data) => {}
setTimeout(() => {
    data = 'result';
    const handler = (data) => {}
}, 1000)

使用过Promise的我们会发现,这似乎很眼熟:

scss 复制代码
new Promise((resolve, reject) => {
    try {
        // 执行一个异步操作,成功
        const data = syncFunc();
        // 调用resolve传递返回值
        resolve(data);
    } catch (error) {
        // 失败
        reject(error)
    }
})

在Promise中我们也需要传入一个方法函数,只是这个函数中resolve, reject的实现对于使用者来说是黑盒。但起码我们知道为什么它这么要求了。

代码实现

scss 复制代码
class Promise {
    constructor(executor) {
        executor(resolve, reject) // 用户传入的executor通常都是异步的,在Promise的内部应该执行它
    }
}

至于resolvereject到底要做什么呢?我们先按下不表.

我们先来看看Promise A+规范的要求:

2.1 Promise state

A promise must be in one of three states: pending, fulfilled, or rejected.

2.1.1 When pengding, a promise may transition to fulfilled or rejected.

2.1.2 When fulfilled, must not transition, must have a value which must not change.

2.1.3 When rejected, must not transiton, must have a reason which must not change.

根据这部分说明,我们进一步更新代码:

ini 复制代码
const PENDING = 'PENDING';     // 等待态
const FULFILLED = 'DULFILLED'; // 成功态
const REJECTED = 'REJECTED';   // 失败态
class Promise {
    constructor() {
        this.state = PENDING;
        this.value = '';
        this.reason ='';
    }
}

完成这些定义后,我们还缺少一些相关的状态转化的实现,这就是resolve、reject要做的了

ini 复制代码
class Promise {
    constructor(executor) {
        this.state = PENDING;
        this.value = '';
        this.reason ='';
​
        const resolve = (value) => { // 成功时传入值
            this.state = FULFILLED;
            this.value = value;
        }
        const reject = (error) => {
            this.state = REJECTED;
            this.reason = error;
        }
        
        try {
            executor(resolve, reject);
        } catch (error) {
            reject(error);
        }
        
    }
}

这样我们就完成了上述的内容,它既符合异步处理的思想,也符合Promise的实际运行逻辑、Promise A+规范的要求

结语

下一篇我们继续实现Promise

相关推荐
鱼樱前端16 小时前
uni-app快速入门章法(二)
前端·uni-app
silent_missile17 小时前
vue3父组件和子组件之间传递数据
前端·javascript·vue.js
克里斯蒂亚诺更新18 小时前
微信小程序app.js中每30秒调用一次wx.getLocation
javascript·微信小程序·小程序
IT_陈寒18 小时前
Vue 3.4 实战:这7个Composition API技巧让我的开发效率飙升50%
前端·人工智能·后端
鄃鳕18 小时前
C++坑系列,C++ std::atomic 拷贝构造函数问题分析与解决方案
java·javascript·c++
少年阿闯~~19 小时前
HTML——1px问题
前端·html
Never_Satisfied19 小时前
在JavaScript / HTML中,实现`<iframe>` 自适应高度
开发语言·javascript·html
Mike_jia19 小时前
SafeLine:自托管WAF颠覆者!一键部署守护Web安全的雷池防线
前端
brzhang19 小时前
把网页的“好句子”都装进侧边栏:我做了个叫 Markbox 的收藏器,开源!
前端·后端·架构
VincentFHR21 小时前
Canvas 高性能K线图,支持无限左右滑动
前端·数据可视化·canvas