自己写一个 Promise 的实现

启发自一月份的时候参加的某司的前端面试,当时我在和面试官聊项目经历的时候,谈到了Promise,引出了面试官此后长达半小时的对“如何用ES5的语法实现Promise”的灵魂拷问。因为答得不理想,所以今天就来补补课。

首先,来回顾一下Promise。Promise是ES6中提供的一个对象,能以同步、顺序的语句表达异步的操作。

(MDN开发者文档对于Promise的描述:Promise - JavaScript | MSN。)

下面是一个Promise的具体使用例子:

const fn = function(resolve, reject) {
    console.log("Promise execution!");
    let date = new Date();
    let time = date.getTime();
    if (time % 2 == 0) {
        resolve("She loves me!");
    } else {
        reject("She doesn't love me!");
    }
}

const defer = new Promise(fn);

defer.then(function(value) {
    console.log("resolve: " + value);
}, function(reason) {
    console.log("reject: " + reason);
});

上述代码中,Promise对象的实例defer接收了fn函数作为参数。这里fn函数被称为executor函数,根据定义,“executor函数会在Promise构造函数返回新建的对象前被调用”。

但是,我们注意到fn函数的定义中并没有对resolvereject这两个函数进行定义。那么,在执行fn函数语句的时候,这两个函数是如何得到执行的呢?

此外,当程序运行到defer.then的时候,then函数的两个参数都是回调函数 ——分别记做onfulfilledonrejected—— 都与resolvereject函数有着千丝万缕的关系:当fulfilled的时候,调用onfulfilled函数,反之调用onrejected函数。
(插一句,回调函数的记忆方式:callback: call then back. 调用之后返回主函数。)

为了实现以上功能,我采取的方法是利用setTimeout函数,利用它的异步回调特性,来延迟resolvereject!。

下面是我的实现:

function NewPromise(fn) {
    this.value = null;
    this.resolveFn;
    this.rejectFn;
    // execute the fn function.
	// bind NewPromise object onto resolve and reject funtcions, 
	// so that the value of "this" keyword inside those two functions are both NewPromise object!
    fn(this.resolve.bind(this), this.reject.bind(this));
}

NewPromise.prototype.resolve = function(value) {
    this.value = value;
    setTimeout(() => {
        this.resolveFn(this.value);
    }, 0);
}

NewPromise.prototype.reject = function(reason) {
    this.value = reason;
    setTimeout(() => {
        this.rejectFn(this.value);
    }, 0);
}

NewPromise.prototype.then = function(resolveFn, rejectFn) {
    this.resolveFn = resolveFn;
    this.rejectFn = rejectFn;
}

const fn = (resolve, reject) => {
    console.log("Promise execution!");
    let date = new Date();
    let time = date.getTime();
    if (time % 2 == 0) {
        resolve("She loves me!");
    } else {
        reject("She doesn't love me!");
    }
}

const defer = new NewPromise(fn);

defer.then((value) => {
    console.log("resolve: " + value);
}, (reason) => {
    console.log("reject: " + reason);
});

上述代码中,fn函数首先在生成NewPromise对象的时候得到执行。但是由于在调用resolvereject的时候,使用了setTimeout函数,虽然只是延迟0秒执行,但是由于JavaScript的单线程 + 事件循环的特性,实际resolveFnrejectFn的调用必须等到主线程代码执行完毕才有机会开始。因此,主线程继续往下接着执行then函数,在then函数中,对NewPromise对象中的resolveFnrejectFn进行赋值。
(这里resolveFnrejectFn只是得到了赋值,并没有执行!)

then执行完毕后,主线程执行结束,再执行setTimeout中的回调函数resolveFn或者rejectFn,此时,resolveFnrejectFn已经被赋值,也顺利得到了valuereason的值。

以上就是我用ES5的语法写的Promise初级版本(虽然使用了一部分ES6的箭头函数语法…)。总结起来就是利用setTimeout来延迟resolvereject函数的后半部分执行,前半部分对value赋值依旧正常执行,主线程结束后再利用resolve回调resolveFn,打印结果。(rejectFn同理。)

附录:
本文参考的文章:原文链接1原文链接2

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值