Promise入门(上)

197 阅读2分钟

在了解Promise之前,要先知道什么是异步,什么是同步。 大概可以这么理解,所谓的异步,就是操作跟操作之间是没关系的,这就同时带来一个特点,可以同时进行多个操作。 而同步操作之间是相关的,同时只能做一件事,必须等前一件事做完了,后面的才能进行。 异步有多个优点,但也有缺点,那就是代码会更复杂。而同步的优点就是代码简单。

比方说用异步操作请求一个电商网站的数据,大概是这样的:

ajax('/banners',function(banner_data){
    ajax('/hotsItems',function(hotsItems_data){
        ajax('/slides',function(slides_data){
        //......
        },function(){
            alert("error")
        })
    },function(){
        alert("error")
    })
},function(){
alert("error")
})
//做多重的异步操作,会导致经典的回调地狱

这个时候用多重嵌套,会显得特别麻烦,而用同步操作会显得简单,它会走完第一个数据之后,再走下一个:

//同步版,假如有个ajax_async:
let banner_data = ajax_async('/banners');
let hotsItems_data = ajax_async('/hotsItems');
let slides_data = ajax_async('/slides'); 
...
//但用户体验差,也没回卡死

用异步操作,性能高,用户体验好,但是代码复杂;但同步操作,页面可能会卡死,也用不得。


Promise--消除异步操作

Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件,更合理更强大。用同步一样的方式,来书写异步代码。 本质上,一个promise是某个函数返回的对象,你可以把回调函数绑定在这个对象上,而不是把回调函数当作参数传进函数。

//当我们需要一个promise的时候,需要new一个promise对象,里面接收一个函数作为参数,里面异步的代码都写在函数里面,这个函数有两个参数:resolve,reject
let p = new Promise(function(resolve,reject){
    //异步代码
    //resolve--成功
    //reject--失败
});

//-------------
//此处用promise封装一个ajax操作
//此处已引入一个jquey文件
let p = new Promise(function(resolve,reject){
    $.ajax({
        url:'文件1路径',
        dataType:'json',
        success(data){
            //成功的时候调用resolve
            resolve(data)
        },
        error(err){
            //失败的时候调用reject
            reject(err)
        }
    })
}); 
//当promise调用有结果了,会调用then,里面有两个函数作为参数,
p.then(function(data){
    //成功了调用这个函数
    console.log(data)
    alert('成功'+data)
},function(err){
    //失败会调用这个函数
    console.log(err)
    alert('失败'+err)
})

假如要封装两个promise,要如何操作?promise对象上有一个方法all(),里面接收一个数组作为参数,可以把两个promise扔进去,然后再使用then方法

let p1 = new Promise(function(resolve,reject){
    $.ajax({
        url:'文件1路径',
        dataType:'json',
        success(data){ 
            resolve(data)
        },
        error(err){
            reject(err)
        }
    })
}); 
let p2 = new Promise(function(resolve,reject){
    $.ajax({
        url:'文件2路径',
        dataType:'json',
        success(data){ 
            resolve(data)
        },
        error(err){ 
            reject(err)
        }
    })
}); 

 Promise.all([
    p1,p2
 ]).then(function(arr){
    //全都成功
    //会有一个数组作为结果,里面装的是文件1 2 的数据,所以要分解出两个结果
    let [res1,res2] = arr;
    console.log(res1);
    console.log(res2);
 },function(){
    //至少有一个失败  
 })

这时候会发现一个问题:这里要写两个Promise对象,但它们只有地址不一样,其他都一样,那可以封装一个方法,把创建好的Promise对象返回出去:

function createPromise(url){
    return new Promise(function(resolve,reject){
    $.ajax({
        url:url,
        dataType:'json',
        success(data){ 
            resolve(data)
        },
        error(err){ 
            reject(err)
        }
    })
}); 
}
Promise.all([
    createPromise('文件1路径');
    createPromise('文件2路径');
 ]).then(function(arr){ 
    let [res1,res2] = arr;
    console.log(res1);
    console.log(res2);
 },function(){
    //至少有一个失败  
 })

当使用高版本jquery的时候,这个jquery会自带Promise。

Promise.all([
    $.ajax({url:'文件1路径',dataType:'json'}),
    $.ajax({url:'文件2路径',dataType:'json'})
]).then(function(){
    //成功
},function(){
    //失败
})

有了Promise之后异步,大概是这样的;

Promise.all([$.ajax(),$.ajax()]).then(result=>{
    //成功
},err=>{
    //失败
})
//异步的本质没有变,有异步的优势,不影响用户体验,写法上也没比同步复杂多少

Promise的其他用法

Promise.race:可以同时读多个资源,谁先来先读谁,用法跟all类似

Promsie.race([
    $.ajax({url:'http://a1.baidu.com/data'}),
    $.ajax({url:'http://a2.baidu.com/data'}),//如果a2快,先读a2
    $.ajax({url:'http://a3.baidu.com/data'}),
    $.ajax({url:'http://a4.baidu.com/data'}),
    $.ajax({url:'http://a5.baidu.com/data'})
])

以上是Promise的简单入门,接下来还有Promise进阶及原理实现,欢迎关注。