Promise

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。

所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。

Promise对象代表一个异步操作,有三种状态:

pending(进行中)、fulfilled(已成功)和rejected(已失败)。

只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。

回顾ES5中若要实现以下异步编程逻辑,将会形成回调地狱(回调不断嵌套回调)

setTimeout(() => {
console.log("事件A");
setTimeout(() => {
console.log("事件B");
setTimeout(() => {
console.log("事件C");
}, Math.random()*1000);
}, Math.random()*1000);
}, Math.random()*1000);

ES6中使用Promise:

let p = new Promise((resolve,reject)=>{
//一些异步操作
settimeout(()=>{
console.log("123")
resolve("abc");
},0)
})
.then(function(data){
//resolve状态
console.log(data)
},function(err){
//reject状态
console.log(err)
})
//'123'
//'abc'

Promise对象接受一个函数,其两个参数分别表示resolve状态和reject状态,函数中执行的异步操作结果可以通过调用形参名字的方法来分别表示resolve状态和reject状态并将异步结果进行传参,resolve()和reject()的参数会传递到.then中相应状态的回调函数的形参中。

以下来源:https://www.cnblogs.com/sweeeper/p/8442613.html

then()方法

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

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

//做饭
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;
}

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

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);
});

运行结果如下:

开始做饭。
做饭完毕!
开始吃饭:鸡蛋炒饭
吃饭完毕!
开始洗碗:一块碗和一双筷子
洗碗完毕;
干净的碗筷

在then方法中,可以直接return数据而不是Promise对象,在后面的then中也能接收到数据。或者更可取的方法是使用Promise.resolve()方法return一个promise对象以便后续可以继续使用then方法。

reject()方法

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

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

//做饭
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 + '没法吃!');
})

运行结果:

开始做饭。
做饭失败!
烧焦的米饭没法吃!

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:米饭被打翻了!

Promise.all()方法

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

它的状态由参数中的各个promise对象决定,分成两种情况。

只有所有参数的Promise的状态都变成fulfilled,它的状态才会变成fulfilled。 此时每一个Promise的返回值组成一个数组,传递给它的回调函数。

只要有一个被rejected,它的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给它的回调函数。

//切菜
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);
}); //执行结果
开始切菜。
开始烧水。
切菜完毕!
烧水完毕!
准备工作完毕:
["切好的菜", "烧好的水"]

Promise.race()方法

race 按字面解释,就是赛跑的意思。race 的用法与 all 一样,只不过 all 是等所有异步操作都执行完毕后才执行 then 回调。而 race 的话只要有一个异步操作执行完毕,就立刻执行 then 回调。

注意:其它没有执行完毕的异步操作仍然会继续执行,而不是停止。

这里我们将上面样例的 all 改成 race

Promise
.race([cutUp(), boil()])
.then(function(results){
console.log("准备工作完毕:");
console.log(results);
}); //执行结果
开始切菜。
开始烧水。
切菜完毕!
准备工作完毕:
切好的菜
烧水完毕!

race 使用场景很多。比如我们可以用 race 给某个异步请求设置超时时间,并且在超时后执行相应的操作。

//请求某个图片资源
function requestImg(){
var p = new Promise(function(resolve, reject){
var img = new Image();
img.onload = function(){
resolve(img);
}
img.src = 'xxxxxx';
});
return p;
} //延时函数,用于给请求计时
function timeout(){
var p = new Promise(function(resolve, reject){
setTimeout(function(){
reject('图片请求超时');
}, 5000);
});
return p;
} Promise
.race([requestImg(), timeout()])
.then(function(results){
console.log(results);
})
.catch(function(reason){
console.log(reason);
});

上面代码 requestImg 函数异步请求一张图片,timeout 函数是一个延时 5 秒的异步操作。我们将它们一起放在 race 中赛跑。

  • 如果 5 秒内图片请求成功那么便进入 then 方法,执行正常的流程。
  • 如果 5 秒钟图片还未成功返回,那么则进入 catch,报“图片请求超时”的信息。

Promise.resolve()方法

将现有对象转为 Promise 对象。

Promise.resolve('123')
// 等价于
new Promise(resolve => resolve('123'))

根据参数不同分成四种情况:

  1. 参数是一个 Promise 实例

    如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。

  2. 参数是一个thenable对象

    thenable对象指的是具有then方法的对象,比如下面这个对象。

    let thenable = {
    then: function(resolve, reject) {
    resolve(42);
    }
    };

    Promise.resolve方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法。

    let thenable = {
    then: function(resolve, reject) {
    resolve(42);
    }
    }; let p1 = Promise.resolve(thenable);
    p1.then(function(value) {
    console.log(value); // 42
    });
  3. 参数不是具有then方法的对象,或根本就不是对象

    如果参数是一个原始值,或者是一个不具有then方法的对象,则Promise.resolve方法返回一个新的 Promise 对象,状态为resolved。

    const p = Promise.resolve('Hello');
    
    p.then(function (s){
    console.log(s)
    });
    // Hello
  4. 不带有任何参数

    Promise.resolve方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。

    需要注意的是,立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

    setTimeout(function () {
    console.log('three');
    }, 0); Promise.resolve().then(function () {
    console.log('two');
    }); console.log('one'); // one
    // two
    // three

    上面代码中,setTimeout(fn, 0)在下一轮“事件循环”开始时执行,Promise.resolve()在本轮“事件循环”结束时执行,console.log('one')则是立即执行,因此最先输出。

Promise.reject()方法

Promise.reject(reason)方法也会返回一个新的 Promise 实例,该实例的状态为rejected。

注意,Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数。这一点与Promise.resolve方法不一致。

前端知识点回顾之重点篇——ES6的Promise对象的更多相关文章

  1. 前端知识点回顾之重点篇——ES6的async函数和module

    async函数 ES2017 标准引入了 async 函数,使得异步操作变得更加方便. async 函数是 Generator 函数的语法糖 什么是语法糖? 意指那些没有给计算机语言添加新功能,而只是 ...

  2. 前端知识点回顾之重点篇——ES6的Iterator和Generator

    Iterator 迭代器是一种接口.是一种机制. 为各种不同的数据结构提供统一的访问机制.任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员). Iter ...

  3. 前端知识点回顾之重点篇——CSS中vertical align属性

    来源:https://www.cnblogs.com/shuiyi/p/5597187.html 行框的概念 红色(line-height)为行框的顶部和底部,绿色(font-size)为字体的高度, ...

  4. 前端知识点回顾之重点篇——CSS中flex布局

    flex布局 来源: http://www.ruanyifeng.com/blog/2015/07/flex-grammar.html?utm_source=tuicool 采用 Flex 布局的元素 ...

  5. 前端知识点回顾之重点篇——jQuery实现的原理

    jQuery jQuery的实现原理 参考:https://blog.csdn.net/zhouziyu2011/article/details/70256659 外层沙箱和命名空间$ 为了避免声明了 ...

  6. 前端知识点回顾之重点篇——CORS

    CORS(cross origin resource sharing)跨域资源共享 来源:http://www.ruanyifeng.com/blog/2016/04/cors.html 它允许浏览器 ...

  7. 前端知识点回顾之重点篇——AJAX

    Ajax(Asynchronous JavaScript and XML) 这种技术就是无须刷新页面即可从服务器中取得数据,但不一定是XML数据.在原生方法上,Ajax技术的核心是XMLHttpReq ...

  8. 前端知识点回顾之重点篇——JavaScript异步机制

    JavaScript异步机制 来源:https://www.cnblogs.com/zhaodongyu/p/3922961.html JavaScript是单线程异步执行的,单线程意味着代码在任务队 ...

  9. 前端知识点回顾之重点篇——CSS中的BFC

    BFC布局(Block Formatting Contexts) 来源:https://www.cnblogs.com/lzbk/p/6057097.html 块级格式化上下文是页面中的一块渲染区域, ...

随机推荐

  1. Python学习记录5-面向对象

    OOP 思想 以模块化思想解决工程问题 面向过程 vs 面向对象 由面向过程转向面向对象 常用名词 OO:面向对象 ooa:分析 ood:设计 oop:编程 ooI:实现 ooa -> ood ...

  2. 【Day4】2.详解Http请求协议

    Http请求协议

  3. Kubernetes的初始化容器initContainers

    initContainers是一种专用的容器,在应用程序容器启动之前运行,可以包括一些应用程序镜像中不存在的实用工具和安装脚本,可以完成应用的必要数据初始化等工作.总的来说就是在正式的容器启动之前做一 ...

  4. day01_人类社会货币的演变

    1.货币的自然演变 1.1:从实物货币(贝壳.金银等一般等价物的稀有性等价于被交换物品的价值)---纸质货币(国家信用背书,使得一文不值的纸币可以兑换价值百元的商品)---记账货币(微信.二维码.银行 ...

  5. Hadoop_01_Apache Hadoop概述

    一:Hadoop(Hadoop Distributed File System)概述:对海量数据分析处理的工具 1. Hadoop是Apache旗下的一个用java语言实现开源软件框架,是一个开发和运 ...

  6. [Abp vNext微服务实践] - 业务开发

    前几篇分别介绍了abp vNext微服务框架.开发环境搭建和vue element admin前端框架接入,在vue element admin中实现用户角色管理基本功能后就可以开始进行业务开发了,本 ...

  7. JSONObject fromObject() 需要引入的包

    1. maven项目 在pom.xml中添加以下依赖: <dependency> <groupId>net.sf.json-lib</groupId> <ar ...

  8. 微信小程序 base64ToArrayBuffer

    base64ToArrayBuffer 将 base64 的字符串转化为 ArrayBuffer 对象 示例代码: 使用位置:在 JS文件的任意函数中使用 const base64 = 'CxYh'; ...

  9. jmeter-post请求自动变成get,提示请求方式错误,修改协议即可

    修改协议: http  改为  https  或反之

  10. POJ1961 Period && POJ2604 Power Strings 字符串循环节

    两道题都是求循环节的...但是一道是学哈希时做的,另一道是学$KMP$时做的 POJ2604 用的哈希...枚举长度的因数作为循环节的长度,然后暴力算出所有循环节位置的哈希值,看看是否相等. #inc ...