一招异步回调Promise解决callback回调地狱难题

  • Post author:
  • Post category:其他


Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值



Promise描述

Promise 对象代表一个在这个promise 被创建出来时不一定已知的值,但是它能够把对应的程序和异步操作成功的结果或失败的原因绑定起来。Promise对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:

  1. pending: 初始状态,不是成功或失败状态。
  2. fulfilled: 意味着操作成功完成。
  3. rejected: 意味着操作失败。

    待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个原因(错误)被拒绝(rejected)。当这些情况之一发生时,我们用 promise 的 then 方法的相关处理程序才会被调用。
let p = new Promise(function(resolve, reject) {
    console.log("1")
    var flag = true;
    if (flag) {
        resolve('3');
    } else {
        reject('失败');
    }
});

p.then(function(data) {
//data的值是上面调用resolve(...)方法传入的值
    console.log(data);
}, function(reason) {
//reason的值是上面调用reject(...)方法传入的值
    console.log(reason);
});
console.log("2")
//1
//2
//3



链式调用

Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。比如说执行一个ajax请求,假如你成功了,就执行resolve,假如你失败了就执行reject方法。

resolve表示promise操作成功时返回的回调

let p = new Promise(function(resolve, reject) {
    console.log('执行primise');
    resolve("fulfilled状态")
})
.then(function(data){
	console.log(data)
});
//执行promise
//fulfilled状态

输出“执行promise”后调用resolve方法,then接收resolve传出来的参数data,然后再打印“fulfilled状态”

那reject肯定就是promise操作失败后的回调了

let p = new Promise(function (resolve, reject) {
          var flag = false;
          if(flag){
            resolve('执行promise');
          }else{
          console.log("失败")
            reject('rejected状态');
          }
        })
        p.then(function(data){
            console.log(data);
        },function(reason){ 
            console.log(reason);
        });
 //失败
 //rejected状态

flag为false,执行reject方法,then方法中接受两个回调,一个成功的回调函数,一个失败的回调函数。第一个resolve是对promise成功时候的回调, 第二个reject就是失败的时候的回调。执行失败后promise的状态修改为rejected,这样我们在then中就能捕捉到,然后执行“失败”情况的回调。

Promise对象调用的then方法其实和回调函数callback差不多一个意思,等于说把原来的回调函数的写法分离出来,在异步调用结束(promise对象中的内容)之后,用链式调用的方式执行回调函数(then)。Promise的then方法中返回的是一个新的 Promise对象,实现链式调用,而不会产生回调地狱。使用Promise可能代码不会减少,甚至更多,但是却大大增强了其可读性和可维护性

function fn(str) {
    var p = new Promise(function(resolve, reject) {
        //处理异步任务
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve(str)
            } else {
                reject('操作失败')
            }
        })
    })
    return p;
}

fn('点赞')
    .then((data) => {
        console.log(data);
        return fn('收藏');
    })
    .then((data) => {
        console.log(data);
        return fn('评论')
    })
    .then((data) => {
        console.log(data);
    })
    .catch((data) => {
        console.log(data);
    })
//点赞
//收藏
//评论

调用fu函数后会返回一个Promise的实例p,当p执行成功会执行resolve回调,在then中打印出data,然后再次调用fu。也就是说只有上一个Promise对象有结果了之后才会才会执行下一个回调,通过多次调用 then() 可以添加多个回调函数,它们会按照插入顺序进行执行

回调函数的方式

call()
function call() {
    console.log('点赞')
    call1()
}
function call1() {
    console.log('收藏')
    call2()
}
function call2() {
    console.log('评论')
}
//点赞
//收藏
//评论



catch异常捕获

catch与try catch类似,catch是用来捕获异常的,和then方法中接受的第二参数rejected的回调是一样的,不过reject是执行之前(resolve回调或者promise中的script代码),如果抛出异常,就会在控制台报错,进程卡死在这里,但是如果用catch捕获的话,异常时会执行catch方法,不会报错卡死。

这表示在链式操作中抛出一个失败之后,使用catch能不影响后面的操作继续执行

new Promise((resolve, reject) => {
    console.log('初始化');
    resolve();
})
.then(() => {
    throw new Error('这里发生了一个错误');
    console.log('前面有错误,我不会被执行了');
})
.catch(() => {
    console.log('捕捉到前面的错误了,我替你执行');
})
.then(() => {
    console.log('无论前面发生了什么我都要执行');
});
//初始化
//捕捉到前面的错误了,我替你执行
//无论前面发生了什么我都要执行

通常,一遇到异常抛出,浏览器就会顺着 Promise 链寻找下一个 rejected 失败回调函数或者由catch执行指定的回调



all方法

all方法提供了并行执行异步操作的能力

(1)只有fn、fn1、fn2的状态都变成fulfilled(执行成功,resolve),Promise的状态才会变成fulfilled,此时fn、fn1、fn2的返回值组成一个数组,传递给Promise的回调函数。

(2)只要fn、fn1、fn2之中有一个被rejected(执行失败,reject),Promise的状态就变成rejected,此时第一个被rejected的实例的返回值,j就会传递给Promise的回调函数。

// 结果如下:(分别执行得到结果,all统一执行完三个函数并将值存在一个数组里面返回给then进行回调输出)
function fn(){
    var p = new Promise(function(resolve, reject) {
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve("1")
            } else {
                reject('操作失败')
            }
        })
    })
    return p;
}
function fn1(){
    var p = new Promise(function(resolve, reject) {
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve("2")
            } else {
                reject('操作失败')
            }
        })
    })
    return p;
}
function fn2(){
    var p = new Promise(function(resolve, reject) {
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve("3")
            } else {
                reject('操作失败')
            }
        })
    })
    return p;
}
Promise
    .all([fn(), fn1(), fn2()])
    .then(function(results){
        console.log(results);
    });
//[ '1', '2', '3' ]



race方法

race方法相反,谁先执行完成就先执行谁的回调。无论是成功的resolve回调还是失败的reject回调,只要有一个执行完成就会先执行race的回调,其余的将不会再执行race的回调

function fn() {
    var p = new Promise(function(resolve, reject) {
        //处理异步任务
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve("1")
            } else {
                reject('操作失败')
            }
        }, 1000)
    })
    return p;
}

function fn1() {
    var p = new Promise(function(resolve, reject) {
        //处理异步任务
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve("2")
            } else {
                reject('操作失败')
            }
        }, 2000)
    })
    return p;
}

function fn2() {
    var p = new Promise(function(resolve, reject) {
        //处理异步任务
        var flag = true;
        setTimeout(function() {
            if (flag) {
                resolve("3")
            } else {
                reject('操作失败')
            }
        }, 3000)
    })
    return p;
}
Promise
    .race([fn(), fn1(), fn2()])
    .then(function(result) {
        console.log('成功', result);
    }, function(reason) {
        console.log('失败', reason);
    });       
//成功 



版权声明:本文为aaahuahua原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。