《JavaScript高级程序设计》- 第十一章:期约

第十一章:期约

介绍Promise之前,先介绍一下异步编程

同步行为与异步行为在计算机科学中一对对立统一的概念

  1. 同步行为:内存中严格按照顺序执行处理器指令。在执行的每一步,都可以推断出程序的状态。
  2. 异步行为:类似于系统中断,即:当前进程外部的实体可以执行的代码;

11.1 回调地狱

在早期JavaScript中,只支持定义回调函数表明异步;通常需要深度嵌套的回调函数(回调地狱)来解决;

function double(value){
    setTimeout( () => setTimeout(console.log, 0, value * 2), 1000);
}
double(3);	// 大概1000毫秒后,6
  1. 异步操作值

    在内部setTimeout中可以异步操作传入值value;所以可以提取一个回调函数来利用;

    function double(value,callback){
        setTimeout( () => setTimeout(() => callback(value *2) ), 1000);
    }
    double(3, (x) => { console.log(`I get the ${x}!`)} );	// 大概1000毫秒后,I get the 6!
    
  2. 失败处理

    上面的异步操作值,达成一种成功处理的效果。反之,也需要实现失败处理的效果;

    const successCallback  = (x) => { console.log(`Success:${x}`); };
    const faliureCallback = (e) => { console.log(`Failure:${e}`); };
    function double(value,success,faliure){
        setTimeout( () => {
        	try{
                if( typeof value !== 'number' ) {
                    throw 'Yout must input a number as first argument';
                }
                success(2*value);	// 成功处理
            }catch(e){	
                faliure(e);		// 失败处理
            }
        }, 1000);
    }
    double(3, successCallback, faliureCallback);	// 大概1000毫秒后,Success:6
    double('a', successCallback, faliureCallback);	// 大概1000毫秒后,Failure:Yout must input a number as first argument
    

    这种模式已经不可取了,因为必须初始化异步操作时定义回调。

  3. 嵌套异步回调

    假如一个异步的返回值,被另一个异步使用呢?

    function double(value,success,faliure){
        setTimeout( () => {
        	try{
                if( typeof value !== 'number' ) {
                    throw 'Yout must input a number as first argument';
                }
                success(2*value);	// 成功处理
            }catch(e){	
                faliure(e);		// 失败处理
            }
        }, 1000);
    }
    
    const successCallback  = (x) => { double(x, (y) => console.log(`Success:${ y }`)) };	// 嵌套调用
    const faliureCallback = (e) => { console.log(`Failure:${e}`); };
    
    double(3, successCallback, faliureCallback);	// 大概1000毫秒后,Success:12
    

    显然,这一层嵌套已经不好维护了。该回调策略显然不可用!(回调地狱,真的是地狱)

11.2 期约

ES6新增了Promise类型,成为了主导性的异步编程机制。如fetch()Battery Status API等浏览器API都是以期约为基础;

11.2.1 期约基础
  1. 期约需要new操作符来实例化;

  2. 创建期约的时候,需要传入执行器(不然会报错);

    let p = new Promise( ()=>{} );
    setTimeout(console.log, 0, p);	// Promise { <pending> }
    
  3. 期约状态机

    期约拥有状态,且是私有的,不能直接通过JavaScript检测、修改;只能改变一次

    • pending:期约的最初始状态——待定;表示尚未开始或正在执行中。
    • resolved:期约可以落定,落定成功即为解决resolved),有时候也称兑换fulfilled);
    • rejected:期约可以落定,落定失败即为拒绝rejected);
  4. 解决值与拒绝理由

    当状态为兑现的时候,会返回一个解决值;当为拒绝的时候,会返回一个拒绝理由

  5. 期约的使用例子

    期约向服务器发送一个HTTP请求并预定会返回一个JSON。 如果请求返回范围在200~299的状态码, 则足以让期约的状态变为兑现。 此时期约内部就可以收到一个JSON字符串。 类似地, 如果请求返回的状态码不在200~299这个范围内, 那么就会把期约状态切换为拒绝。 此时拒绝的理由可能是一个Error对象, 包含着HTTP状态码及相关错误消息。

  6. 通过执行函数控制期约状态

    执行函数主要有两个职责:

    • 初始化期约的异步行为
    • 控制状态的最终转换:resolved()reject();

    因为执行器是期约的初始化程序,所以执行器函数是同步函数

    let p1 = new Promise( (resolve,reject)=>{ resolve(); } );
    setTimeout(console.log, 0, p1); // Promise { undefined }
    
    let p2 = new Promise( (resolve,reject)=>{ reject(); } );
    setTimeout(console.log, 0, p2); // Promise { <rejected> undefined }
    

    除此之外,还可以延迟状态切换:

    let p1 = new Promise( (resolve,reject)=>{ 
    	setTimeout(()=>{ resolve() },5000);
    } );
    

    注意:状态切换是不可逆的,当进行二次切换的时候,是静默失败的

    let p1 = new Promise( (resolve,reject)=>{ 
    	resolve();
        reject();	// 静默失败
    } );
    setTimeout(console.log, 0, p1); // Promise { undefined }
    
  7. Promise.resolve()

    期约并非一开始就必须处于创建状态;而是可以通过静态方法:Promise.resolve()来创建一个已解决的状态的期约

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值