js手写Promise

先写一个简单的Promise:

function Promise(executor) {
    var self = this;
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;


    function resolve(value) {
        if(self.status === 'pending') {
            self.status = 'resolve';
            self.value = value;
        }
    }
    function reject(reason) {
        if(self.status === 'pending') {
            self.status = 'rejected';
            self.reason = reason;
        }
    }
    executor(resolve, reject);
}

Promise.prototype.then = function (infulfilled, inrejected) {
    if(this.status === 'resolve') {
        infulfilled(this.value)
    }
    if(this.status === 'rejected') {
        inrejected(this.reason)
    }
};

var p = new Promise(function (resolve, reject) {
    resolve('resolve');
});

p.then(function (data) {
    console.log(data);
}, function (err) {
    console.log(err);
});

流程大概就是:
先用构造函数new一个对象p

var p = new Promise(function (resolve, reject) {
    resolve('resolve');
});

在构造函数Promise中将p对象属性初始化:

this.status = 'pending';
this.value = undefined;
this.reason = undefined;

构造函数内部会执行executor这个函数,而这个函数就是传进去的函数:

function (resolve, reject) {
    resolve('resolve');
}

这个再调用构造函数写好的resolve函数:

function resolve(value) {
    if(self.status === 'pending') {
        self.status = 'resolve';
        self.value = value;
    }
}

把p对象的status属性改为resolve,把到时候调用的参数value值保存中自身的属性value中。
然后p调用原型对象的then属性,它是一个函数:

function (infulfilled, inrejected) {
    if(this.status === 'resolve') {
        infulfilled(this.value)
    }
    if(this.status === 'rejected') {
        infulfilled(this.value)
    }
}

根据p此时p对象自身的status状态执行对应函数,此时status === ‘resolve’,执行infulfilled函数即then参数中的第一个函数,最后:

p.then(function (data) {
    console.log(data); // 输出suc
}, function (err) {
    console.log(err);
});

一个简单的Promise就写完了,现在只支持同步调用,不支持异步调用,比如改成这样就没法调用

var p = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve('resolve');
    })
});

不能支持异步的是因为:当构造函数调用executor函数时,发现了setTimeout(一个异步函数),它就会把它放到一边,继续运行下面的函数,即到了p调用then,此时它的status因为没有调用resolve,所以它的status还是pending,所以什么都没有执行。

解决方法就是:在then里面添加一个判断,如果status是pending的话,就把函数存进一个数组,这个数组专门用来执行回调函数:

if(this.status === 'pending') {
    this.onResolvedCallbacks.push(function () { //onResolvedCallbacks是一个存放函数的数组
        infulfilled(self.value)
    });
    this.onRejectedCallbacks.push(function () { //onRejectedCallbacks是一个存放函数的数组
        infulfilled(self.reason)
    });
}

在构造函数创建专门拿来放函数的数组:

    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    function resolve(value) {
        if(self.status === 'pending') {
            self.status = 'resolve';
            self.value = value;
            self.onResolvedCallbacks.forEach(function (fn) {
                fn();
            })
        }
    }
    function reject(reason) {
        if(self.status === 'pending') {
            self.status = 'rejected';
            self.reason = reason;
            self.onRejectedCallbacks.forEach(function (fn) {
                fn();
            })
        }
    }

并且每次执行executor函数时会将函数数组里的都执行一遍。

完整代码:

function Promise(executor) {
    var self = this;
    this.status = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];

    function resolve(value) {
        if(self.status === 'pending') {
            self.status = 'resolve';
            self.value = value;
            self.onResolvedCallbacks.forEach(function (fn) {
                fn();
            })
        }
    }
    function reject(reason) {
        if(self.status === 'pending') {
            self.status = 'rejected';
            self.reason = reason;
            self.onRejectedCallbacks.forEach(function (fn) {
                fn();
            })
        }
    }
    executor(resolve, reject);
}

Promise.prototype.then = function (infulfilled, inrejected) {
    var self = this;
    if(this.status === 'resolve') {
        infulfilled(this.value)
    }
    if(this.status === 'rejected') {
        inrejected(this.reason)
    }
    if(this.status === 'pending') {
        this.onResolvedCallbacks.push(function () {
            infulfilled(self.value)
        });
        this.onRejectedCallbacks.push(function () {
            inrejected(self.reason)
        });
    }
};

var p = new Promise(function (resolve, reject) {
    setTimeout(function () {
        resolve('resolve');
    })
});

p.then(function (data) {
    console.log(data);
}, function (err) {
    console.log(err);
});

再对比之前的流程:

不能支持异步的是因为:当构造函数调用executor函数时,发现了setTimeout(一个异步函数),它就会把它放到一边,继续运行下面的函数,即到了p调用then,此时它的status因为没有调用resolve,所以它的status还是pending,所以什么都没有执行。

这样到了调用then时,因为status是pending,就会将要调用的函数放入函数数组,这个时候同步函数执行完了,开始执行放在一边的seTimeout里面的函数resolve,它就会把之前存放数组的函数遍历执行,最后输出了suc。

上面的Promise还没支持捕获异常,因为异常时,没有执行任何函数,它的status还是pending, 所以要修改一下executor的执行条件:

try {
    executor(resolve, reject);
} catch(err) {
    reject(err)
}

这样捕获到异常时会直接执行reject,输出error:

var p = new Promise(function (resolve, reject) {
    throw new Error('error')
});

p.then(function (data) {
    console.log(data);
}, function (err) {
    console.log(err); //输出Error: error
});

关于链式调用先等着吧,他妈也太复杂了……

当你需要手写一个 Promise 的时候,你可以按照以下步骤进行: 1. 创建 Promise 构造函数,并传入一个执行器函数作为参数: ```javascript function MyPromise(executor) { // TODO: 实现 Promise 的状态和值的存储 } ``` 2. 在构造函数中创建状态和值的存储变量,并初始化为初始状态: ```javascript function MyPromise(executor) { this.state = 'pending'; this.value = undefined; // TODO: 实现其他必要的变量和逻辑 } ``` 3. 定义 resolve 和 reject 函数,用于在异步操作完成时改变 Promise 的状态和值,并添加对应的回调函数: ```javascript function MyPromise(executor) { this.state = 'pending'; this.value = undefined; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; // TODO: 触发所有注册的成功回调函数 } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.value = reason; // TODO: 触发所有注册的失败回调函数 } }; // TODO: 调用执行器函数,并传入 resolve 和 reject 函数 } ``` 4. 在构造函数中调用执行器函数,并传入 resolve 和 reject 函数: ```javascript function MyPromise(executor) { this.state = 'pending'; this.value = undefined; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; // TODO: 触发所有注册的成功回调函数 } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.value = reason; // TODO: 触发所有注册的失败回调函数 } }; try { executor(resolve, reject); } catch (error) { reject(error); } } ``` 5. 添加 then 方法,用于注册成功回调函数和失败回调函数,并返回一个新的 Promise 对象: ```javascript function MyPromise(executor) { this.state = 'pending'; this.value = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; // TODO: 触发所有注册的成功回调函数 } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.value = reason; // TODO: 触发所有注册的失败回调函数 } }; try { executor(resolve, reject); } catch (error) { reject(error); } } MyPromise.prototype.then = function(onFulfilled, onRejected) { // 创建新的 Promise 对象 const newPromise = new MyPromise((resolve, reject) => { // TODO: 根据当前 Promise 的状态和值执行对应的回调函数,并处理返回值 }); // 返回新的 Promise 对象 return newPromise; }; ``` 6. 在成功回调函数和失败回调函数中处理返回值,并根据返回值的类型决定新 Promise 对象的状态和值: ```javascript function MyPromise(executor) { this.state = 'pending'; this.value = undefined; this.onFulfilledCallbacks = []; this.onRejectedCallbacks = []; const resolve = (value) => { if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; // TODO: 触发所有注册的成功回调函数 } }; const reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.value = reason; // TODO: 触发所有注册的失败回调函数 } }; try { executor(resolve, reject); } catch (error) { reject(error); } } MyPromise.prototype.then = function(onFulfilled, onRejected) { const newPromise = new MyPromise((resolve, reject) => { if (this.state === 'fulfilled') { // 如果当前 Promise 已经是 fulfilled 状态,则异步执行成功回调函数 setTimeout(() => { try { const result = onFulfilled(this.value); // 处理返回值,并根据返回值的类型决定新 Promise 对象的状态和值 handlePromiseResult(newPromise, result, resolve, reject); } catch (error) { reject(error); } }, 0); } else if (this.state === 'rejected') { // 如果当前 Promise 已经是 rejected 状态,则异步执行失败回调函数 setTimeout(() => { try { const result = onRejected(this.value); // 处理返回值,并根据返回值的类型决定新 Promise 对象的状态和值 handlePromiseResult(newPromise, result, resolve, reject); } catch (error) { reject(error); } }, 0); } else { // 如果当前 Promise 还是 pending 状态,则将回调函数添加到对应的队列中,等待执行 this.onFulfilledCallbacks.push(() => { setTimeout(() => { try { const result = onFulfilled(this.value); handlePromiseResult(newPromise, result, resolve, reject); } catch (error) { reject(error); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { const result = onRejected(this.value); handlePromiseResult(newPromise, result, resolve, reject); } catch (error) { reject(error); } }, 0); }); } }); return newPromise; }; function handlePromiseResult(promise, result, resolve, reject) { if (promise === result) { // 如果返回的是当前 Promise 对象本身,则抛出 TypeError reject(new TypeError('Chaining cycle detected for promise')); } else if (result instanceof MyPromise) { // 如果返回的是一个 Promise 对象,则根据其状态和值决定新 Promise 对象的状态和值 if (result.state === 'fulfilled') { resolve(result.value); } else if (result.state === 'rejected') { reject(result.value); } else { // 如果返回的 Promise 对象还是 pending 状态,则等待其状态改变后再决定新 Promise 对象的状态和值 result.then(resolve, reject); } } else if (result && (typeof result === 'object' || typeof result === 'function')) { // 如果返回的是一个对象或函数,则尝试获取 then 方法 let then; try { then = result.then; } catch (error) { reject(error); } if (typeof then === 'function') { // 如果返回值有 then 方法,则将其视为 Promise-like 对象,并调用 then 方法 const promiseLikeObj = new MyPromise(then.bind(result)); promiseLikeObj.then(resolve, reject); } else { // 如果返回值没有 then 方法,则将其视为普通值,并将其作为新 Promise 对象的值 resolve(result); } } else { // 如果返回的是一个普通值,则将其作为新 Promise 对象的值 resolve(result); } } ``` 以上是一个简单的手写 Promise 的实现,仅供参考。实际上,原生的 Promise 还包含了更多的特性和细节,比如处理异步操作、链式调用、错误处理等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值