前端异步编程系列之Promise/Deferred模式(3/4)

在这篇文章中,我会介绍另外一种异步编程的解决方案:Promise/Deferred模式。这种模式最早出现于Dojo的代码中,09年被Kris Zyp抽象为一个提议草案,发布于CommonJS规范中,并抽象出Promise/A、Promise/B、Promise/D这样典型的异步Promise/Deferred模型,这使得异步操作可以以一种优雅的方式出现。他最大的特点就是可以先执行异步调用,然后延迟传递处理操作。有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。本篇文章通过Promise/A模式来作为敲门砖来简略介绍Promise/Deferred模式,以ES6的Promise实现来重点介绍Promise的特性以及对于异步编程问题的解决方案。

1.Promise/A的定义。

Promise/A提议对单个异步操作有如下规定:

1.Promise操作只会有三个状态:未完成,完成,失败

2.他的状态转换只能是:未完成 => 完成 和 未完成 => 失败两种,并且转换是不可逆,并且完成和失败之间不能相互转换。

3.状态一旦变化就不能被更改。

如下图所示:

而在api的定义上,最低要具备一个then方法即可,并且then方法的行为包括:

1.接受完成态,错误态时的回调方法,以便在Promise状态改变时,调用相应回调方法。

2.只接受函数

3.then方法会继续返回一个Promise,以实现链式调用。

其实then方法的行为只是将他接受的回调函数储存起来,在某一刻Promise状态改变时,再进行调用罢了。

示例代码如下:

const myPromise = function () {
    this.handle = {};  // 储存处理函数
};
// then的作用在于把,成功和失败的回调给储存起来。以方便在以后的某个时刻调用
myPromise.prototype.then = function(resolveHandler,rejectHandler) {
    let handle = {};
    if(typeof resolve == "function") {
        handle.resolve = resolveHandler
    }
    if(typeof reject == "function") {
        handle.reject = rejectHandler
    }
    this.handle = handle;
}

不过如果要完整走完流程,还需要一个可以改变Promise状态的对象,而这个对象就是Deferred,即延迟对象。他用来改变Promise的状态,示例代码如下:

const myDeferred = function () {
    this.status = "pending";  // 未完成的等待状态。
    this.promise = new myPromise();  // 让deferred和一个promise进行关联,以控制promise的状态。
};
// 更改为完成状态,并执行相应的处理函数。
myDeferred.prototype.resolve = function (obj) {
    this.status = "resolve";
    let handle = this.promise.handle;
    if(handle && handle.resolve) {
        handle.resolve(obj);
    }
}
// 更改为失败状态,并执行相应的处理函数。
myDeferred.prototype.reject = function (obj) {
    this.status = "reject";
    let handle = this.promise.handle;
    if(handle && handle.reject) {
        handle.reject(obj);
    }
}

在这里,Deferred的作用主要就是更改状态,然后从关联的Promise中取出then方法所存储的相应的处理函数。

Promise和Deferred的整体关系图如下所示:

可以看出,Promise主要作用于外部,通过then方法,存储逻辑处理函数,而Deferred用于内部,改变Promise的状态,并调用相应的处理函数。

拿node中读取文件为例,读取一个文件,经过Promsie/Deferred封装后,会变成如下形式:

const fs = require("fs");
function read(path) {
    let deferred = new myDeferred();
    fs.readFile(path,(err,data) => {
        if(err) {
            deferred.reject(err);
            return;
        }
        deferred.resolve(data);
    })
    return deferred.promise;
}
// 异步调用一个文件
rea
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值