关于Promise的一些个人理解

作者: xiaer | 来源:发表于2016-03-22 15:06 被阅读20935次

提醒:本文中的内容是我看了一些文档后自己的理解,可能会有一些理解上的错误。若简友发现了可以提出来,我会及时修改。_

新的ES6中引入了Promise,目的是让回调更为优雅。层层嵌套的回调会让javascript失去美感和可读性,同时javascript也推荐采用链式的方式去书写函数调用。于是Promise就应运而生。Promise即承诺的意思,new一个Promise就是新建一个承诺。在新建一个承诺的时候你需要做两件事情:
1. 指定承诺所需完成的事
2. 设置承诺是否实现的标准
下面我们来定义一个承诺,并让程序实现我们的这个承诺。
承诺的内容是:获取data.php的数据
承诺是否实现的评判是:是否获取data.php的数据
这里我们会用到jQuery.ajax()方法,这会让我们的代码显得简单精炼。下面是代码:

var http = {
    get: function(url) {
        var promise = new Promise(function(resolve, reject) {
            $.ajax({
                url: url,
                method: 'get',
                success: function(data) {
                    resolve(data);
                },
                error: function(xhr, statusText) {
                    reject(statusText);
                }
            });
        });
        return promise;
    }
};
http.get('data.php').then(function(data) {
    document.write(data);
}, function(err) {
    document.write(err);
});
/* data.php文件 */
<?php
echo '{"name":"Tom","age":"22"}';

在http对象中只定义了一个get方法。在get方法中我们new了一个Promise的对象,而不是直接使用jQuery.ajax()方法去获取我们想要的数据。在这个get方法的最后我们返回的就是我们new的这个promise对象。对于这类有延迟的操作我们都可以使用Promise去处理,返回给主线程的是一个Promise的对象,而不是直接的结果,这是延迟程序对主线程的一个承诺。主线程可以通过返回的Promise的对象获取数据或者处理错误。这使得异步处理变得简单而优雅。
在jQuery.ajax()中我们使用了两个方法来判断是否实现了我们的承诺,它们分别是resove和reject方法。如果jQuery.ajax()执行了success,并且返回的data中有数据,那么我们就判定这个承诺已经实现了(fulfilled),则调用resolve方法。如果jQuery.ajax()执行了error,那么我们就判定这个承诺被拒绝了(rejected),则调用reject方法。
那resove和reject这两个方法分别执行了哪些操作呢?这个我们就需要从Promise这个构造函数本身的结构说起。Promise这个构造函数结构大概是下面这样的:

/* 用于描述思维的代码 */
function Promise(executor) {
    // 共有三种状态:pending(准备)、fulfilled(完成)、rejected(拒绝)
    this.PromiseStatus = 'pending';
    // 用于存储返回的数据
    this.PromiseValue;
    // 完成
    var resolve = function(reson) {};
    // 拒绝
    var reject = function(reson) {};
    ...
    // 开始执行承诺
    executor(resolve, reject);
}
Promise.prototype.then = function() {};
Promise.prototype.chain = function() {};
Promise.prototype.catch = function() {};
...

PromiseStatus:用于记录Promise对象的三种状态,这三中状态分别是:
pending:待定状态,Promise对象刚被初始化的状态
fulfilled:完成状态,承诺被完成了的状态
rejected:拒绝状态,承诺完成失败的状态
Promise的初始状态是pending。随后会更具承诺完成的情况更改PromiseStatus的值。

PromiseStatus:用于记录返回的数据或者错误。当承诺完成时,会把返回的数据赋给PromiseStatus。如果承诺执行失败了,那么失败的原因也会赋给此变量。

resolve()和reject():Promise构造函数中有两个闭包的函数resolve()和reject()。在new一个新的Promise的时候会传递一件你需要做的事情(executor)。这个executor是一个函数,在Promise的构造函数中它会被传入两个参数,这两个参数即我们的两个闭包的函数resolve()和reject(),以便你在executor中判定是否完成了你的承诺。

executor(): executor()函数中执行的代码就是子程序需要完成事。在executor()函数内如果调用了resolve(),resolve()则会把Promise对象的状态PromiseStatus修改为fulfilled,把resolve(value)中的value值赋给Promise对象的PromiseValue。然后再依次执行由then()方法构成的回调链中的回调函数。同样,在executor()中调用reject()的过程也是类似的。调用过程如下:

/* 用于描述思维的代码 */
executor(resolve, reject) {
    ...
    resolve(value);
    ...
}
...
resolve(value) {
    PromiseStatus = 'fulfilled';
    PromiseValue = value;
    ...
    // 接着调用回调链中的回调函数
}

then(onFulfilled, onRejected):这个方法实际上是把onFulfilled()函数和onRejected()函数添加到Promise对象的回调链中。回调链就像一个由函数组构成的队列,每一组函数都是由至少一个函数构成(onFulfilled() 或者 onRejected() 或者 onFulfilled() 和 onRejected())。当resolve()或者reject()方法执行的时候,回调链中的回调函数会根据PromiseStatus的状态情况而被依次调用。

onFulfilled(value)和onRejected(reason):参数value和reason的实参都是PromiseValue。这里有一点值得注意,如果onFulfilled(value)和onRejected(reason)这两个回调函数中return返回值不是一个Promise的对象,那么这个返回值会被赋给PromiseValue,并在下一个then()的onFulfilled(value)和onRejected(reason)中做为实参使用。但如果这个返回值是一个Promise的对象,那么剩下的由then()构造的回调链会转交给新的Promise对象并完成调用。

有这样一个问题,如果在第一个then()中执行了onRejected(reason)回调函数,并且没有return任何值的时候,那么下一个then()中将会调用onFulfilled(value)方法,而不是onRejected(reason)。因为在执行上一个then()的onRejected(reason)回调函数的时候并没有出现错误或异常,所以PromiseStatus的状态就被更改为fulfilled了。为了避免这个问题,我们可以在onRejected(reson)中返回一个Promise对象并reject()。代码如下,我们要去访问一个并不存在的文件solve.php:

var http = {
    get: function(url) {
        var promise = new Promise(function(resolve, reject) {
            $.ajax({
                url: url,
                method: 'get',
                success: function(data) {
                    resolve(data);
                },
                error: function(xhr, statusText) {
                    reject(statusText);
                }
            });
        });
        return promise;
    }
};
http.get('solve.php').then(function(data) {
    return data;
}, function(err) {
    return Promise.reject('Sorry, file not Found.');
}).then(function(data) {
    document.write(data);
}, function(err) {
    document.write(err);
});

Promise.reject()方法会返回一个被reject()的Promise对象,因此使得我们可以继续走下一个then()中的onRejected(reason)方法。
以上便是我对Promise以及Promise的执行过程的一个基本理解,这是我参考的文档:MDN: Promise

相关文章

  • 关于Promise的一些个人理解

    提醒:本文中的内容是我看了一些文档后自己的理解,可能会有一些理解上的错误。若简友发现了可以提出来,我会及时修改。_...

  • Promise 的不完全试坑记录

    Promise 主要就是记忆一下关于 Promise 的一些不太好理解的问题 当在 resolve 或者 reje...

  • Promise对象

    Promise 多个异步回调: 详情关于promise对象的一些讲解 Promise.all() .catch()用法

  • Promise理解-个人解析

    Promise的含义 Promise 是异步编程的一种解决方案。它由社区最早提出和实现,ES6将其写进了语言标准,...

  • 关于Promise的几点理解

    Promise对象为异步而生,接受一个函数作为参数,该函数里放入需要在主线程上执行的代码。该段代码在执行时,Pro...

  • 关于promise的粗浅理解

    定义 在JavaScript的世界中,所有代码都是单线程执行的。 由于这个“缺陷”,导致JavaScript的所有...

  • 关于Promise对象的理解

    简单实例 对Promise执行顺序的理解 输出结果 说明 Promise对象在创建的时候就会立即执行,所以我们看到...

  • Promise理解与实现

    promise理解 promise的意思是承诺。承诺理解为某个时候一些条件满足后,会兑现一件事情。 new Pro...

  • Promise async/await

    Promise async/await 参考初探promise promise 理解 JavaScript ...

  • Promise原理解析

    Promise原理解析 标签(空格分隔): Node.js Promise原理解析 简介 Promise 对象用于...

网友评论

  • 8f84110a2927:PromiseStatus:用于记录返回的数据或者错误。当承诺完成时,会把返回的数据赋给PromiseStatus。如果承诺执行失败了,那么失败的原因也会赋给此变量。这里的PromiseStatus是不是应该修改为PromiseValues?写的很好,简单明了,思路清晰
  • 方丈先生:蒙蔽的路过
  • 逆水行舟不尽则退:在本地测试编写的文件,提示不能跨域,怎么继续进行下去呢
    xiaer:我写这篇文章的时候是在本地的Apache服务器上测试的。可以看到我访问的是data.php。这里有一篇文章关于js跨域的,希望可以帮到你:https://segmentfault.com/a/1190000002647143

    我比较建议在本地搭建一个简单的服务器环境来测试会比较方便。:blush:
  • oshapeman:大赞!
  • 我是xy:例子写得真好!
  • 67fd803a6726:写的太好了 加鸡腿!!
  • 秋夜已凉:简直就是赞!
  • 萍水相逢hu:终于理解了promise,写的太棒了
  • jkhmnk:加鸡腿,写的清晰明了 :pray:
  • stois:例子很棒

本文标题:关于Promise的一些个人理解

本文链接:https://www.haomeiwen.com/subject/qccklttx.html