博客列表 >promise 详解

promise 详解

程先生的博客
程先生的博客原创
2019年08月24日 15:43:411067浏览

使用promises的优势

1,解决回调地狱(Callback Hell)问题

(1)有时我们要进行一些相互间有依赖关系的异步操作,比如有多个请求,后一个的请求需要上一次请求的返回结果。过去常规做法只能 callback 层层嵌套,但嵌套层数过多的话就会有 callback hell 问题。比如下面代码,可读性和维护性都很差的。

实例

firstAsync(function(data){
    //处理得到的 data 数据
    //....
    secondAsync(function(data2){
        //处理得到的 data2 数据
        //....
        thirdAsync(function(data3){
              //处理得到的 data3 数据
              //....
        });
    });
});

(2)如果使用 promises 的话,代码就会变得扁平且更可读了。前面提到 then 返回了一个 promise,因此我们可以将 then 的调用不停地串连起来。其中 then 返回的 promise 装载了由调用返回的值

实例

firstAsync()
.then(function(data){
    //处理得到的 data 数据
    //....
    return secondAsync();
})
.then(function(data2){
    //处理得到的 data2 数据
    //....
    return thirdAsync();
})
.then(function(data3){
    //处理得到的 data3 数据
    //....
});

2,更好地进行错误捕获 

多重嵌套 callback 除了会造成上面讲的代码缩进问题,更可怕的是可能会造成无法捕获异常或异常捕获不可控。
(1)比如下面代码我们使用 setTimeout 模拟异步操作,在其中抛出了个异常。但由于异步回调中,回调函数的执行栈与原函数分离开,导致外部无法抓住异常。

实例

function fetch(callback) {
    setTimeout(() => {
        throw Error('请求失败')
    }, 2000)
}
 
try {
    fetch(() => {
        console.log('请求处理') // 永远不会执行
    })
} catch (error) {
    console.log('触发异常', error) // 永远不会执行
}
 
// 程序崩溃
// Uncaught Error: 请求失败

(2)如果使用 promises 的话,通过 reject 方法把 Promise 的状态置为 rejected,这样我们在 then 中就能捕捉到,然后执行“失败”情况的回调。

实例

function fetch(callback) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             reject('请求失败');
        }, 2000)
    })
}
 
 
fetch()
.then(
    function(data){
        console.log('请求处理');
        console.log(data);
    },
    function(reason, data){
        console.log('触发异常');
        console.log(reason);
    }
);

当然我们在 catch 方法中处理 reject 回调也是可以的。

实例

function fetch(callback) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             reject('请求失败');
        }, 2000)
    })
}
 
 
fetch()
.then(
    function(data){
        console.log('请求处理');
        console.log(data);
    }
)
.catch(function(reason){
    console.log('触发异常');
    console.log(reason);
});

JS - Promise使用详解2(ES6中的Promise)

2015年6月, ES2015(即 ECMAScript 6、ES6) 正式发布。其中 Promise 被列为正式规范,成为 ES6 中最重要的特性之一。

 

1,then()方法

简单来讲,then 方法就是把原来的回调写法分离出来,在异步操作执行完后,用链式调用的方式执行回调函数。

而 Promise 的优势就在于这个链式调用。我们可以在 then 方法中继续写 Promise 对象并返回,然后继续调用 then 来进行回调操作。

 

(1)下面通过样例作为演示,我们定义做饭、吃饭、洗碗(cook、eat、wash)这三个方法,它们是层层依赖的关系,下一步的的操作需要使用上一部操作的结果。(这里使用 setTimeout 模拟异步操作)

实例

//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭完毕!');
            resolve('鸡蛋炒饭');
        }, 1000);
    });
    return p;
}
 
//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
 
function wash(data){
    console.log('开始洗碗:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('洗碗完毕!');
            resolve('干净的碗筷');
        }, 2000);
    });
    return p;
}

(2)使用 then 链式调用这三个方法:

实例

cook()
.then(function(data){
    return eat(data);
})
.then(function(data){
    return wash(data);
})
.then(function(data){
    console.log(data);
});

运行实例 »

点击 "运行实例" 按钮查看在线实例

实例

cook()
.then(function(data){
    return eat(data);
})
.then(function(data){
    return wash(data);
})
.then(function(data){
    console.log(data);
});

当然上面代码还可以简化成如下:

实例

cook()
.then(eat)
.then(wash)
.then(function(data){
    console.log(data);
});

(3)运行结果如下:

开始做饭;

做饭完毕;

开始吃饭:鸡蛋炒饭    //cook返回的结果数据

吃饭完毕;

开始洗完:一双筷子,一只碗   //eat返回的结果

洗碗完毕;

干净的碗筷

2,reject()方法

上面样例我们通过 resolve 方法把 Promise 的状态置为完成态(Resolved),这时 then 方法就能捕捉到变化,并执行“成功”情况的回调。

而 reject 方法就是把 Promise 的状态置为已失败(Rejected),这时 then 方法执行“失败”情况的回调(then 方法的第二参数)。

 

(1)下面同样使用一个样例做演示

实例

//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭失败!');
            reject('烧焦的米饭');
        }, 1000);
    });
    return p;
}
 
//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
 
cook()
.then(eat, function(data){
  console.log(data + '没法吃!');
})

运行结果如下:

开始做饭

做饭失败!

烧焦的米饭没法吃

(2)如果我们只要处理失败的情况可以使用 then(null, ...),或是使用接下来要讲的 catch 方法。

cook()

.then(null, function(data){

  console.log(data + '没法吃!');

})

注意:then返回promise对象,根据结果执行其中的一个参数(resolve 或reject)

3,catch()方法

(1)它可以和 then 的第二个参数一样,用来指定 reject 的回调

实例

cook()

.then(eat)

.catch(function(data){

    console.log(data + '没法吃!');

});

(2)它的另一个作用是,当执行 resolve 的回调(也就是上面 then 中的第一个参数)时,如果抛出异常了(代码出错了),那么也不会报错卡死 js,而是会进到这个 catch 方法中。

实例

//做饭
function cook(){
    console.log('开始做饭。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('做饭完毕!');
            resolve('鸡蛋炒饭');
        }, 1000);
    });
    return p;
}
 
//吃饭
function eat(data){
    console.log('开始吃饭:' + data);
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('吃饭完毕!');
            resolve('一块碗和一双筷子');
        }, 2000);
    });
    return p;
}
 
cook()
.then(function(data){
    throw new Error('米饭被打翻了!');
    eat(data);
})
.catch(function(data){
    console.log(data);
});

运行结果如下:

开始做饭;

做饭完毕;

error: 米饭被打翻了

扩展阅读

4,all()方法

Promise 的 all 方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后才执行回调。

 

(1)比如下面代码,两个个异步操作是并行执行的,等到它们都执行完后才会进到 then 里面。同时 all 会把所有异步操作的结果放进一个数组中传给 then。

实例

//切菜
function cutUp(){
    console.log('开始切菜。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('切菜完毕!');
            resolve('切好的菜');
        }, 1000);
    });
    return p;
}
 
//烧水
function boil(){
    console.log('开始烧水。');
    var p = new Promise(function(resolve, reject){        //做一些异步操作
        setTimeout(function(){
            console.log('烧水完毕!');
            resolve('烧好的水');
        }, 1000);
    });
    return p;
}
 
Promise
.all([cutUp(), boil()])
.then(function(results){
    console.log("准备工作完毕:");
    console.log(results);
});

(2)运行结果如下:

开始切菜;

开始烧水;

切菜完毕;

烧水完毕;

准备工作完毕!

[“切好的菜”,“烧好的水”]




声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议