Promise用法小结

定义:是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

可以按用途理解为:

1.主要用于异步计算

2.可以将异步操作队列化,按照期望的顺序执行,返回执行符合预期的结果。

3.可以在对象之间传递和操作Promise,帮助我们处理队列。

Promise产生的原因

异步操作的常见用法:

// 第一种
document.getElementById("start").addEventlistener("click",start,false);
function start(){
    // 响应事件执行相关的操作
}

// 第二种   jqery用on的事件监听
$('start').on('click',start);

回调函数:

//常见的回调函数有Ajax
$.ajax('http://baidu.com',{
    sucess: function(res){
        // 回调函数
    }
})

// 在页面加载完毕后进行加载
$(function(){
    // 回调函数
});

在浏览器中JS的异步操作主要以事件为主,回调主要出现在Ajax和File API中。

NodeJs无阻塞高并发大量操作依赖回调函数。在使用不慎时,容易陷入回调地狱。

在异步回调中无法使用try catch,无法使用return 等语句。

异步回调会在一个新的栈中运行,之前的栈是无法拿到之前的栈的信息。在异步回调中无法使用try  catch。

总结一下回调带来的四个问题:

  1. 嵌套层次很深,难以维护;
  2. 无法正常使用return和throw;
  3. 无法正常检查堆栈信息;
  4. 多个回调之间难以联系。

Promise的使用

下面是Promise实例的范例:

new Promise(       //创建Promise实例
    // 执行器exector
    function (resolve, reject){
        //一段耗时很长的异步操作
        resolve();        // 数据处理完成
        reject();         // 数据处理出错
    }
)
.then( function A(){
    //成功,下一步    
},function B(){
    //失败,相应处理
});

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise是一个代理对象,它和原先要进行的操作并无关系,它通过引入一个回调,避免更多回调。

Promise有三个状态:

  • pending [待定]  初始状态
  • fulfilled   [实现]   操作成功
  • rejected  [被否决]   操作失败

Promise状态发生改变,就是触发 .then()里面的响应函数,处理后续操作。

Promise状态一经改变就不是再变。如果Promise函数调用了resolve再调用reject,其还是fulfilled的状态。

Promise实例一经创建,执行器立即执行。

每个then返回一个新的Promise实例。

根据上面的例子可以看出:

  • .then()接收两个函数作为参数,分别代表fulfilled和rejected;
  • .then()返回一个新的Promise实例,所以它可以链式调用;
  • 当前面的Promise状态改变时,.then()会根据其最终状态选择特定的响应执行函数执行;
  • 状态响应函数可以返回新的Promise,或者其它值;
  • 如果返回新的Promise,那么下一级.then()会在新的Promise状态改变后执行;
  • 如果返回其他任何值,则会立即执行下一级.then()。

then()嵌套then()

在then()函数内嵌套then()函数,在一个then()内嵌套一组链式调用效果。

尽量把then展开,变成一个简单的队列。

错误处理

Promise会自动捕获内部异常,并交给reject响应函数处理。

如果在Promise中的执行器发生了错误,Promise的状态会被置为rejected。之后fulfilled函数就不会得到执行,后边通过catch捕获错误的函数就会被执行,执行后返回错误的信息。

then函数接收:fulfilled的响应函数 或者 rejected的响应函数。

错误处理的两种做法:

  1. reject('错误信息').then(null, message => {})
  2. throw new Error('错误信息').catch(message => {})

下面展示一下两个方法:

方法一:

new Promise( (resolve, reject) => {
    setTimeout( () => {
        reject('bye');
    },2000);
})
    .then( value => {
        console.log( value + 'world');
    }, value => {
        console.log('Error: ',value);
    });  

运行出的结果为:

方法二:

new Promise( resolve => {
    setTimeout( () => {
        throw new Error('bye');
    },2000);
})
    .then( value => {
        console.log( value + 'world');
    })
    .catch( error => {
        console.log('Error:'+error.message);
    });

运行结果为:

可以看到:第二种方法在更加清晰好读,可以捕获前面的错误。

错误和then连用  (.catch()+.then())

这个是在.catch后接.then()。catch也有Promise实例,如果没有抛出错误的话,它返回的Promise也是fulfilled状态,所以其后的then都会被执行。如果有抛出异常,都会很明显地展示。

注意:强烈建议在所有队列最后都加上catch,以避免漏掉错误处理造成意想不到的问题。

Promise.all()

批量执行:Promise.all([p1,p2,p3,...])用于将多个Promise实例,包装成一个新的Promise实例。

返回的就是一个普通的Promise实例。

接受一个数组作为参数,数组可以是Promise对象,也可以是别的值,只有Promise对象会等待状态改变。当所有的子promise都完成,该Promise才算完成,返回值为全部值的数组。

当有任何一个失败,该Promise失败,返回值是第一个失败的子Promise的结果。

如下用法:

let p1 = new Promise( resolve => {
    setTimeout( () => {
        resolve('I\'m P1');
    }, 1000);
});
let p2 = new Promise( resolve => {
    setTimeout( () => {
        resolve('I\'m P2');
    }, 3000);
});
Promise.all([p1,p2])
    .then(value => {
        console.log(value);
    })

Promise.all()常见的是和map()一起用

 

实现队列

Promise.then()可实现   then这个函数会返回一个新的promise实例特性,串成一个队列将每次产生新的Promise赋给一个值即可。

实现队列:使用forEach / reduce

但是使用两个方法都会产生一些常见错误:

forEach:没有把then()产生的新的Promise实例赋给Promise,没有生成队列,当新的Promise完成时,后面的then会同步触发。

reduce: Promise实例创建后,会立即运行执行器代码,所以这个无法达到队列的效果。

 

Promise.resolve()

有时需要将现有对象转为 Promise 对象,Promise.resolve()方法就起到这个作用。返回一个fulfilled的Promise实例或原始的Promise实例。

Promise方法的参数范围四种情况:

  • 参数为空,返回状态为fulfilled的Promise实例。
  • 参数是一个跟Promise无关的值,同上,不过fulfilled响应函数会得到这个值。
  • 参数为Promise实例,则返回该实例,不做任何修改。
  • 参数为thenable,立即执行它的 .then()方法。

Promise对象的状态,只能由执行器里面的函数来改变,不能由外界来改变。Promise.resolve()对对象的状态值进行修改。

Promise.reject()

返回一个rejected状态的Promise实例。

这个不认thenable。

Promise.race()

类似Promise.all(),区别在于它有任意一个完成,就算完成。

如下:

let p1 = new Promise( resolve => {
    setTimeout( () => {
        resolve('I\'m P1');
    }, 10000);
});
let p2 = new Promise( resolve => {
    setTimeout( () => {
        resolve('I\'m P2');
    }, 2000);
});
Promise.race([p1,p2])
    .then(value => {
        console.log(value);
    })

常见用法:

将异步操作和定时器放在一起,如果定时器先触发,就认为超时,告知用户。

 

可见:Promise可将回调函数包装为promise函数。

这样做的优点:1.可读性好  2.返回的结果可以加入任何Promise队列。

 

async/await

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。

作用:

  1. 赋予JS以顺序手法编写异步脚本的能力。
  2. 保留了异步运算的无阻塞特性,还继续使用同步语法
  3. 还能正常使用return/try/catch。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值