第14章 Promise对象

概要

Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理更强大。
在学习本章前有必要去了解一下js的Event Loop机制。

14.1 Promise的含义

Promise对象有两个特点:
1.对象的状态不受外界影响。Promise对象代表一个异步操作,有3种状态:Pending(进行中)、Fulfilled(已成功)和Rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态。
2.一旦状态改变就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变只有两种可能:从Pending变为Fulfilled和从Pending变为Rejected。只要这两种情况发生,状态就凝固了,不会再变,而是一直保持这个结果。
Promise对象的出现,避免了层层嵌套的回调函数,从可读性角度来看,我们可以认为有了Promise对象,就可以将异步操作以同步操作的流程表达出来。
Promise也有缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误不会反应到外部。再者,当处于Pending状态时,无法得知目前进展到哪一个阶段。

14.2 基本语法

function PromiseTestFunc(ms) {
    let instance = new Promise((resolve,reject) => 
        {
            setTimeout(resolve,ms,'done');
        }
    );
    return instance;
}

PromiseTestFunc(10000).then((value)=> 
    {console.log(value);}
);

上述代码表明一个当状态由Pending转为Resolve时,我们将done字符串传入回调函数的过程。即Promise实例的状态发生转变时,就会触发then方法绑定相应的回调函数(此处为resolve回调函数,then的第二个参数就是在转变为Rejected状态所使用的。)

要着重讲一下以下这种情况,当resolve函数中传入的参数是Promise对象。
先看代码

var p1 = new Promise((resolve, reject) => {
    console.log('p1 execute.')
    setTimeout(() => {
        reject(new Error('fail'));
    },3000);
}); 

var p2 = new Promise((resolve, reject) => {
    console.log('p2 execute.')
    setTimeout(() => {
        resolve(p1);
    }, 1000);
});

p2
    .then((value) => {
        console.log(value);
    })
    .catch((error) => {
        console.log(error); 
    })
// Error: fail

从代码中可以知道p2的状态虽然从Pending变为了Resolve,但是由于Resolve函数中返回的参数是一个任出于Pending状态的Promise对象p1,所以要先等待p1的状态完成变换再执行回调函数;若p1的状态已经变换完成(无论是resolve还是reject)p2的回调函数都会立刻执行。

14.3 Promise.prototype.then()

Promise实例具有的then方法,其作用是为Promise实例添加回调函数。

/**
 * Represents the completion of an asynchronous operation
 */
interface Promise<T> {
    /**
     * Attaches callbacks for the resolution and/or rejection of the Promise.
     * @param onfulfilled The callback to execute when the Promise is resolved.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of which ever callback is executed.
     */
    then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;

    /**
     * Attaches a callback for only the rejection of the Promise.
     * @param onrejected The callback to execute when the Promise is rejected.
     * @returns A Promise for the completion of the callback.
     */
    catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}

在定义中可以看到then方法的返回结果依然是一个Promise实例,因此在then方法可以继续调用then方法。这种链式调用,每个then方法中的回调函数都是处理上一个Promise实例的传入参数。

14.4 Promise.prototype.catch()

Promise.prototype.catch方法是.then(null,rejection)的别名,用于指定发生错误时的回调函数。
Promise对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获。除非有特殊需求,一般不要在then方法中写Rejected状态的回调函数,而应该总是使用catch方法。
特别要强调的是类似如下写法,哪怕出现了错误但由于Promise实例的状态已经变换,异常会成为未捕捉的错误。

var p = new Promise((resolve,reject) => {
    resolve('done');
    setTimeout(() => {
        throw new Error('error occurred');
    }, 0);
});

在前端也可以通过监听异常来捕捉这些抛到最外层没人要的异常。

/**
 * 用于捕获未处理的Promise错误
 */
window.addEventListener('unhandledrejection',event => {
    console.log('unhandledrejection:' + event.reason);
});

/**
 * js中最常见的error事件的事件处理程序
 */
window.onerror = function(message, source, lineno, colno, error) { 
    console.log(error);
 }

14.5 Promise.all()

将多个Promise实例包装成一个Promise。语义类似于c#中的Task.WaitAll方法,等待一组Promise实例都完成状态变换再执行回调函数。

14.6 Promise.race()

该方法同样是将多个Promise实例包装成一个Promise。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值