Promise (1) 初步接触

总想着王者荣耀排位赛再提升个等级就弃掉游戏好好学习,然而打了两个周也没升上去,看来是应该换个方向发挥了。

最近看了《javascript Promise迷离书》,对Promise的理解颇有加深。那么就从总结Promise开始吧。

1 什么是Promise?

  抽象描述: promise是一个规范,提供了一套精心定义的、用来与代表一个可能会在任意时刻完成或失败的异步过程的结果的对象交互的接口。“Promise把异步处理对象和处理规则进行规范化, 并按照采用统一的接口来编写,而采取规定方法之外的写法都会出错。”--《javascript Promise迷离书》第一章。(大概就是知道用promise来干什么的时候才能清楚这段话的意思吧)

  简单描述:promise是一个异步对象,在Promise对象创建时可能是未知的,状态变换后Promise表示一个异步操作的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,它允许你为异步代码执行结果的成功和失败分别绑定相应的处理方法(handlers ),用于处理resolve的value(常用变量名)或reject 的reason(常用变量名)。

1.1 Promise的构造函数(Constructor)

new Promise构造器之后,会返回一个promise对象,创建Promise对象的基本语法:

new Promise(function(resolve, reject) {
    // 异步处理
    // 处理结束后、判定什么情况下resolve这个Promise,什么情况下reject这个Promise.
    // 通常resolve(value),将promise的状态转变成成功,value为之后要用的值
    // 通常reject(reason),将promise的状态转变为失败,reason为之后错误处理需要用的值
    if ( /* 异步操作成功的判定条件 */ ) {
        resolve(value);
    } else {
        reject(reason);
    }
});

  new一个Promise对象,给Promise构造函数传递的参数是一个函数(Promise构造函数只接受函数作为参数,不然是真的会报错给你看的)。该函数带有两个参数resolve和 reject。在Promise内部实现中会给这个函数参数resolve和reject传递两个回调函数。代码参考es6-promise,修改理解大概如下图中的Promise的构造函数内的resolvePromise和rejectPromise函数。resolvePromise它会对传递进来的value值进行处理,rejectPromise它会对传递的reason值进行处理。这段代码做的事情就是,new一个Promise对象,传递给Promise对象的函数内部执行了resolve(value),就相当于执行了resolvePromise(value),同理reject。

function Promise(resolver) {
    resolver(function resolvePromise(value) {
        _resolve( /*......*/ , value);
    }, function rejectPromise(reason) {
        _reject( /*......*/ , reason);
    });
}

  那么resolve和reject主要做了什么事情了?如下图创建的testResolvePromise,在Promise构造函数接受的函数内部执行了 resolve。testResolvePromise对象的[[PromiseStatus]]值是"resolved",[[PromiseValue]]值"resolve: value"(这个字符串就是我们传入resolve函数的值)。对比testRrejectPromise,testRrejectPromise对象的[[PromiseStatus]]值是"rejected",[[PromiseValue]]值"reject:reason"(这个字符串就是我们传入reject函数的值)。resolve和reject改变了promise的状态。同时将处理后的值赋给了Promise对象的某个属性(为什么是处理后,见后文。如果你resolve的value值是一个Promise对象,那么就不是简单的赋值了。)。

总结:给Promise构造函数传递的参数是一个函数(是一个函数)。

1.2 Promise的状态

  用new Promise 实例化的promise对象有三个状态: pending,fulfilled,rejected。

pending: promise对象刚被创建的初始状态,既未完成也没有失败的状态,此状态可以迁移至fulfilled和rejected状态。

fulfilled:意味着操作成功完成,resolve(成功)时,此时的状态不能迁移(不能改变的)。

rejected:意味着操作失败reject(失败)时,此时的状态不能迁移(不能改变的)。

eg: 如图创建了一个testPromisePending对象,用setTimeout设置一个时间10秒后再执行resolve。在这时间段前还没有执行resolve,此时的testPromisePending的[[PromiseStatus]]值是"pending"。10秒过后再在控制太输出一次testPromisePending,此时它的状态就迁移了[[PromiseStatus]]值是"resolved",即是fulfilled状态。

“promise对象的状态,从Pending转换为FulfilledRejected之后, 这个promise对象的状态就不会再发生任何变化”,--《javascript Promise迷离书》(书中的流程图十分的清晰,有利于promise的工作流程理解)

  pending状态---->resolve(value)----->fulfilled状态.

  pending状态---->reject(reason)----->rejected状态.

 总结:如果一个promise不是pending状态,就说明这个promise是settled(不变的),它要么fulfilled状态要么是rejected状态。

1.3 Promise的then方法

  把这个方法单独拿出来说,只是为了承接上文,Promise构造函数接受一个函数作为参数,函数里面内部代码执行了resolve或reject后续可以干什么,有resolve(value)或 reject(reason)传递了值后续怎么处理?这时候then方法闪亮登场了,promise的then方法里面可以设置resolve(value) 或reject(reason)时调用的回调函数。then方法接受两个可选参数,当两个参数不是函数就会被忽略掉。

var testPromise = new Promise(function(resolve, reject) {
    if ( /* 异步操作成功的判定条件 */ ) {
        resolve(value);
        //函数内部resolve了value值,那么我们怎么处理value值了;
    } else {
        reject(error);
        //函数内部reject了reason值,那么我们怎么处理reason值了;
    }
});
testPromise.then(function onFulfilled(value) {
    //当testPromise的状态是fulfilled的时候执行
}, function onRejected(reson) {
    //当testPromise的状态是rejected的时候执行
})

pending状态---->resolve(value)----->fulfilled状态---->执行then方法里面onFulfilled(value)方法

pending状态---->reject(reason)----->rejected状态---->执行then方法里面onRejected(reason)方法

  当testPromise的状态迁移成 fulfilled或rejected的时候时才执行后续的then方法。testPromise的状态是fulfilled就执行onFulfilled方法,此时的value参数的值就是之前resolve的值,onFulfilled函数内部就可以对fulfilled的promise和传递进来value值进行后续的处理了testPromise的状态是rejected就执行onRejected方法,此时的reason参数的值就是之前reason的值,onRejected函数内部就可以对rejected的promise和传递进来reason值进行后续的处理了。 (上面的路线只会执行一条,)

  对了then执行完后返回的结果还是一个promise对象,妈呀这么执行下去promise是不是没完没了呀?对呀对呀这就是后续为什么promise适合处理某些场景的原因之一(加粗,加粗,后面需要解释)。每次调用then都会返回一个新创建的promise,神奇了!!还有更更神奇的事儿,这个新创建的promisethen方法执行的回调onFulfilled和onRejected有关系(废话)。  

  ⑴.调用then方法会返回的promise是新创建的

  ⑵.这个新创建promise的值跟onFulfilled和onRejected的函数内部有无return 以及return的值有关系。如果没有return则返回一个状态为fulfilled的[[PromiseValue]](不同实现内部属性不一定叫PromiseValue)为undefined的promise对象。

  ⑶.承接⑵如果有return,retuen 一个普通的object对象那么新创建promise对象的 [[PromiseValue]] 的值就等于 object。 如果 return 的是一个Promise对象,还是会返回一个新的promise对象,且属性值和return 的Promise对象值一样

  返回了一个普通的promise,imANewPromiseB长什么样子

var testPromiseA = new Promise(function(resolve, reject) {
    resolve("testPromiseA")
});
var testForreturnPromise = new Promise(function(resolve, reject) {
    resolve("just test for testPromiseB")
});
//返回了一个普通的promise,imANewPromiseB长什么样子
var imANewPromiseB = testPromiseA.then(function onFulfilled(value) {
    //返回了一个promise
    return testForreturnPromise
})
// 在控制台输出,imANewPromiseB和 testForreturnPromise 的属性值一样,但他们不是同一个promise。
//imANewPromiseB 是一个新的promise 对象

  在控制台输出,imANewPromiseB和 testForreturnPromise 的属性值一样,但他们不是同一个promise,且imANewPromiseB和testPromiseA也不是同一个promise 对象。imANewPromiseB是一个新的promise。

总结:每次调用then都会返回一个新创建的promise对象。

1.4 为啥要用promise?

  有一个作用就是把代码从异步回调函数拯救出来,让代码看起来逻辑清晰可爱。因为Promise把异步处理对象和处理规则进行规范化。

function getJSON(url) {
    return new Promise(function(resolve, reject) {
        let xhr = new XMLHttpRequest(); //神奇的对象
        xhr.open(‘GET‘, url);
        xhr.onreadystatechange = handler;
        // 无论readyState值何时发生改变,XMLHttpRequest对象都会激发一个readystatechange事件,handler被调用,然后根据结果resolve,或者reject
        xhr.responseType = ‘json‘;
        xhr.setRequestHeader(‘Accept‘, ‘application/json‘);
        xhr.send();
        function handler() {
            if (this.readyState === this.DONE) {
                if (this.status === 200) {
                    resolve(this.response);
                    //successDo(this.response)
                } else {
                    reject(new Error(‘getJSON: `‘ + url + ‘` failed with status: [‘ + this.status + ‘]‘));
                    //faileDo(this.response)
                }
            }
        };
    });
}
// 使用promise
getJSON(url).then(function onFulfilled(value) {
    //successDo
}, function onRejected(reson) {
    //faileDo
})
// 使用回调
getJSON(url, successDo, faileDo)

  使用回调的方式来做getJSON,拿数据和对拿到数据成功和失败都在一个函数里面操作处理。

  使用promise来做getJSON,getJSON只需要做好自己拿数据,且通过resolve和reject返回拿数据成功还是失败的逻辑,并不关心成功或失败的处理。后续的then方法会根据getJSON返回的promise的状态执行onFulfilled方法或者onRejected方法来处理,数据拿成功或者数据拿失败的逻辑。这个流程比较符合人类(我这种人类)的习惯,一步一步执行操作,拿数据返回成功或失败----->处理拿数据成功或失败。

总结:Promise 可以让异步处理对象更像一个流程操作。使用Promise 的时候要思考Promise 的适用场景。并不是说在异步处理的时候Promise永远都是最好的选择。

时间: 2024-11-18 12:32:29

Promise (1) 初步接触的相关文章

为什么要使用puppet 及初步接触

为什么要使用puppet 及初步接触 1.简介 云计算环境下,密度高,机器数量多,还要求弹性和伸缩性,这对于运维提出更高的要求.系统管理员需要经常安装操作系统,对系统参数进行配置和优化,对人员进行授权和定期更新公钥,对软件包进行升级,添加和配置某个服务.这些日常繁琐的任务不但单调.重复,也容易出错.为了提高效率,积累知识,不断改进,管理员一般会想到将这些任务使用脚本进行自动化,然后不断优化和改进这些脚本,可以大大提高效率.但是自己写的脚本,具有下面一些缺点: 可伸缩性是一个问题,要管理成千上万台

C#初步接触

如同非常多刚開始学习的人一样,刚接触C#的时候,也是一头雾水,学习了好长时间,都搞不清楚一些基本名称是什么.什么是C#?什么是.net?什么是visual studio?它们之间有什么关系?以下我们就从这几个问题入手,来探究C#. 关于上边的几个问题,我发现了一个神级的回答.假设我们把用开发软件比作写汉字,那么visual studio就是笔,.net 就是纸,C#就是汉字的书写规则,依次类推,我们就能够依照C#的规则,使用vs在.net上边编敲代码. 理解了这几个问题,我们就能够从C#的基础知

【Qt学习笔记】1.初步接触

一.前言 Qt是一个跨平台的C++图形面向对象的框架,今天开始学习并记录学习过程,希望通过这段时间的努力学会Qt的使用. 同时我也希望在学习的过程中对C++的各种特性有能深刻的认识. 此外,我在Qt初步的学习过程中,所用的环境应该是 VS2015 IDE 二.安装 官网下载Qt安装包和 Qt for VS addin,分别安装,并配置. 三.Hello World 接下来用Qt框架来完成第一个程序 首先打开VS,创建一个Qt工程 熟悉的C++界面,但Qt是有可视化界面的,点击解决方案管理器中的.

C语言初步接触

这几天对C语言有了初步的了解,看了不少的语法知识. #include<stdio.h> int main() { printf("hello world\n"); return 0; } 这是我接触的第一个简单的程序设计,相信大部分人都是从hello word开始的吧! 另外还接触到了变量的知识,变量的名字不要与关键词重名,这点很容易理解. 还有一个const关键词,它可以使变量在程序中保持它的初始值不变,只要把const关键词放在变量的类型前面(放在后面也是可以的)比如:

软件工程实践----初步接触软件工程的总结

这学期的软件工程课即将结束,下面我就对本学期的软件工程课做一下基本的总结. 首先,这是我学期初在阅读了相关资料后提的一些问题:http://www.cnblogs.com/bsdbch/p/4027935.html 这些问题,有的在实际的课程实践中碰到了,因此得到了更深一步的了解.比如关于如何进行需求分析.产品定位,再比如如何控制代码的质量,如何架构整体框架从而让子函数.子类变得更小.但是也有些问题,由于我们的产品没有达到用那些高级方法的高度,所以没有过多的了解.比如关于程序模块间的耦合. 下面

初步接触LVS

今天整理下思绪,定下要掌握LVS原理和使用方法.于是,看了部分关于LVS的概述和文章. 章博士在2002年写的LVS的几篇文章,在我看来,今天都值得一看.http://www.linuxvirtualserver.org/zh/lvs1.html LVS的英文官网,http://www.linux-vs.org/ 附上采访章博士的一篇老文章,看完不由竖起大拇指.https://linux.cn/article-1553-1.html 还有在看的过程中,接触到一个集群中的新概念——脑裂.有一篇文章

初步接触QT嵌入式

拿到这块板子已经有一个多月了,处理器是三星公司的S5PV210AH-A0,主频最高可达1GHz,ARM CortexTM-A8内核,v7精简指令集,512MB DDR2 RAM,4GB 8-bit eMMC,这配置是相当高了.配备7寸的LCD显示屏,外部接口有17路外部中断GPIO,4路ADC,3路UART,1路SPI,2路PWM. 首先拿到板子启动它自带的是andorid4.0系统,工作中要用的是QT,于是就折腾到内核和文件系统,学习如何下载内核和文件系统,理解板子带的demo,读配置bash

实验记录一 初步接触cortex-M3

应该说老早就在接触cortex-M3了.以前没想到会接触嵌入式,结果因为导师的缘故,在选择项目管理时,就呵呵了.不废话.搭配环境很简单,纯粹傻瓜式.可由于自己的马虎,却让自己一直困惑.记得在前段时间,不得已在实验室呆了一个通宵,也是醉了.北方的深夜是极其冷的,何况学校晚上现在还未曾供暖.最后才发现自己弄错了仿真器.贴贴撞撞下,现在也算是真正意义上跑出来第一个样例程序(右边D1测试灯闪烁).上次虽然也把程序烧进了CPU,可事实上失败的.关于CPU板卡上跳线引脚和跳线帽问题,我纠结许久后才发现跳线帽

Maven初步接触

最近随着搜资料,网上这样的字眼越来越多,我了解到这是构建项目的一种方式,于是准备简单看一下 首先粘几篇文章,作为学习的初步资料,我会根据学习过程(由易到难)合理调整他们的顺序 Maven入门 http://blog.csdn.net/prstaxy/article/details/45702225