Promise 对象用于处理异步请求,保存一个异步操作最终完成(或失败)的结果

语法

new Promise(
/* executor */
function(resolve, reject) {...}
); /*
来自谷歌翻译
promise:承诺,约定
resolve:解决,决定,下决心
reject:拒绝,驳回,抵制
*/

参数:

promise 构造函数接受一个 executor 函数作为参数,该函数的两个参数分别是 resolve 和 reject,它们是两个函数(executor 函数 在 Promise 构造函数返回新对象之前被调用)。

resolve 函数被调用时,将 promise 对象从 “未完成” 变为 “成功” (即 pending --> fulfilled)

reject 函数被调用时,将 promise 对象从 “未完成” 变为 “失败” (即 pending --> rejected)

描述

promise 对象是一个代理对象(代理一个值),被代理的值在 promise 对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法,使得异步方法可以像同步方法那样返回值,但不是立即返回最终执行结果,而是一个能代表未来出现的结果的 promise 对象。

上面提到过,一个 promise 对象有三个状态:

• pending:初始状态,不是成功或失败状态

• fulfilled:成功完成

• rejected:失败

pending 状态可能触发 fulfilled 状态并传递一个值给相应的状态处理方法,也可能触发 rejected 状态并传递失败信息。当其中任一种情况发生时,promise 对象的 then 方法绑定的处理方法就会被调用。

(then 方法包含两个参数:onfulfilled 和 onrejected,也都是函数。当 promise 对象的状态为 fulfilled 时调用,调用 then 的 onfulfilled 方法;反之,调用 onrejected 方法。所以异步操作的完成和绑定处理方法之间不存在竞争)

then 方法的使用语法:

promise.then(function(value) {
// onfulfilled
}, function(error) { // 第二个参数是可选的,不一定要提供
// onrejected
});

示例:

    let myFirstPromise = new Promise(function(resolve, reject){
// 当异步代码执行成功时,调用resolve()方法;失败时,调用reject()方法
// 此处,使用定时器来模拟异步代码,实际编码可能是XHR请求或HTML5的一些API方法
setTimeout(function(){
//resolve('成功!') //代码执行成功,调用resolve()方法
resolve('成功!')
}, 2000)
}) myFirstPromise.then(function(successMessage){
// successMessage 是上面调用resolve()方法传入的值
// successMessage 参数不一定非要是字符串类型,这里只是举个例子
console.log('Yay!'+successMessage)
}) console.log('看看我的位置在哪里?')

运行结果:

了解Promise的基本用法以后,通过一个小栗子来了解Promise的应用场景

  // 日常开发中,可能会遇到一个函数的参数依赖于其它函数的返回值,如果其它函数的返回值不能先于执行该函数前返回,就不会得到我们预期的结果
// 此例中,执行add函数时,传入的getValueX方法直接返回2,而getValueY方法存在1秒钟的延时,当前拿不到返回值,最终导致求和失败
function add(valueX, valueY) {
console.log(valueX + valueY)
} add(getValueX(), getValueY()) // NaN (valueX -> 2, valueY -> undefined) function getValueX() {
return 2
} // 模仿一个异步请求,1秒后返回数字3
function getValueY() {
setTimeout(() => {
return 3
}, 1000)
}
 
通过 Promise对象来实现类似的求和方法
  function add(promiseX, promiseY) {
return Promise.all([promiseX, promiseY]).then(values => {
return values[0] + values[1]
})
}
console.log('2秒以后查看x+y求和的结果')
add(fetchX(), fetchY()).then(sum => {
console.log('x + y 的和为:' + sum) // x + y 的和为:3
}) function fetchX() {
return new Promise(resolve => {
resolve(1)
}).then(res => {
return res
})
} function fetchY() {
return new Promise(resolve => {
setTimeout(resolve, 2000, 2)
}).then(res => {
return res
})
}

对比之下,有了Promise对象,就可以清晰地将异步操作以同步操作的流程表达出来

注意:

1、Promise 新建后就会立即执行
  let promise = new Promise((resolve, reject) => {
console.log('作出承诺:"将来"一定会执行!')
resolve('resolved')
}) promise.then(res => {
console.log(res)
}) console.log('test') // 作出承诺:"将来"一定会执行!
// test
// resolved
示例中,Promise 新建后立即执行,输出 "作出承诺:"将来"一定会执行!",当前脚本所有同步任务执行完以后再执行 then 方法
 
2、Promise 的状态一旦改变,就永久保持该状态,不会再变了
  let promise  = new Promise((resolve, reject) => {
resolve('ok')
throw new Error('error')
}) promise.then(res => console.log(res))
.catch(err => console.log(err))
// ok

此例中,Promise 在 resolve语句后面再抛出错误,由于此时Promise状态已经变成 resolved,再抛出错误就无效了

 
3、resolve和reject函数的参数会被分别传递给回调函数,reject函数的参数通常是Error对象的实例,表示抛出错误;resolve函数的参数除了正常值以外,还可能是另一个Promise实例
  let p1 = new Promise(reject => {
reject(new Error('P1 fail... ...'))
})
let p2 = new Promise(resolve => {
resolve(p1)
}) p2.then(res => console.log(res))
.catch(err => console.log(err)) // Error: P1 fail... ...

4、调用 resolve 或 reject 并不会终结 Promise 的参数函数的执行

  new Promise((resolve, reject) => {
resolve(1)
console.log(2)
}).then(res => {
console.log(res)
}) //
//
示例中,调用resolve(1)以后,后面的console.log(2)还是执行了,并且会先执行。resolved 回调函数是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务
通常,调用 resolve 或 reject以后,Promise的使命就完成了,后续操作应该放在then方法里面,而不要直接写在resolve或reject的后面
  // 在resolve或reject前面加上return
new Promise((resolve, reject) => {
return resolve(1)
console.log(2)
}).then(res => {
console.log(res)
})
// // 后续操作放在then方法里
new Promise((resolve, reject) => {
resolve(2)
}).then(res => {
console.log(res)
console.log(1)
}) //
//

通过Promise异步加载图片的示例:

   function loadImageAsync(url) {
return new Promise((resolve, reject) => {
let image = new Image() image.onload = function() {
resolve(url)
} image.onerror = function() {
reject(new Error(`can't find the image: ${url}`))
} image.src = url
document.body.appendChild(image) })
} loadImageAsync('https://www.baidu.com/img/xinshouye_c9d9de2ff40fa160f807f75f34db4ad0.gif')

 Promise.prototype.then()

它的作用是为 Promise 实例添加状态改变时的回调函数,then 方法的第一个参数是 resolved 状态的回调函数,第二个参数可选,是 rejected 状态的回调函数

  promise.then(function(res) {
// success
}, function(err) {
// error
})

尽管then 方法可以接受第二个参数,但一般不建议在 then 方法里定义第二个参数(rejected 状态的回调函数),建议使用 catch 方法

Promise.prototype.catch()

它的作用是指定发生错误时的回调函数,相当于 then 方法的第二个参数 promise.then(null, rejection)

catch 方法不仅可以处理异步操作抛出的错误,还可以捕获then 方法在运行中抛出的错误。而且在语义结构上更加接近同步的写法(try /catch)

{
// 捕获 promise 实例状态从 pending 变为 rejected 的错误
let promise = new Promise((resolve, reject) => {
reject(new Error('test error'))
}) promise.then(res => console.log(res))
.catch(err => console.log(err))
// Error: test error
} {
// 捕获 then 方法中运行时抛出的错误
let promise = new Promise(resolve => {
resolve(x / 0)
}) promise.then(res => console.log(res))
.catch(err => console.log(err))
// ReferenceError: x is not defined
}

Promise.prototype.finally()

finally 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。

finally 方法的回调函数不接受任何参数,因此,也就不知道 Promise 的状态是 fulfield 还是 rejected,表明 finally 方法不依赖于 Promise 的执行结果,与状态无关

  let promise = new Promise((resolve, reject) => {
if(5 > 3) {
resolve('计算正确')
} else{
reject(new Error('计算出错了'))
}
}) promise.then(res => console.log(res))
.catch(err => console.log(err))
.finally(() => console.log('不管计算对错,都要执行fianlly')) // 计算正确
// 不管计算对错,都要执行fianlly

Promise.all()

Promise.all 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

const p = Promise.all([p1, p2, p3]);

all 方法接受一个数组作为参数,参数必须是 Promise 实例

p 的状态由 p1、p2、p3 决定,分成两种情况

(1)、p1、p2、p3 的状态都变成 fulfilled,p 的状态才会变成 fulfilled,此时 p1、p2、p3 的返回值组成一个数组,传递给 p 的回调函数

(2)、p1、p2、p3 之中有一个被 rejected,p 的状态就会变成 rejected,此时第一个被 rejected 的实例的返回值,会传递给 p 的回调函数

应用场景:要求页面同时加载3张图片,只要有一个加载失败就会报错

  function loadImgAsync(src) {
return new Promise((resolve, reject) => {
let img=document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img);
}
img.onerror=function(err){
reject(err);
}
})
} function showImgs(imgs) {
imgs.forEach(function(img){
document.body.appendChild(img);
})
} Promise.all([
loadImgAsync('http://www.tietuku.com/static/image/icon3.png'),
loadImgAsync('http://www.tietuku.com/static/image/icon2.png'),
loadImgAsync('http://www.tietuku.com/static/image/icon1.png')
]).then(showImgs)

Promise.race()

Promise.race 方法同样用于将多个 Promise 实例,包装成一个新的 Promise 实例

const p = Promise.race([p1, p2, p3]);

Promise.all 方法看起来像是 逻辑与 的运算,只有数组中的 Promise 实例对象全部执行成功,新的 Promise 实例对象才会执行 resolved 回调函数

Promise.race 方法则像是 逻辑或 的运算,就像 race 的中文意思:竞赛。只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p的回调函数

将上例需求稍作更改,只要有一个图片加载成功,即可加载到页面中,这个时候就要把all 改成 race 了

  function loadImgAsync(src) {
return new Promise((resolve, reject) => {
let img=document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img);
}
img.onerror=function(err){
reject(err);
}
})
} function showImgs(img){
let p=document.createElement('p');
p.appendChild(img);
document.body.appendChild(p)
} Promise.race([
loadImgAsync('http://www.tietuku.com/static/image/icon3.png'),
loadImgAsync('http://www.tietuku.com/static/image/icon2.png'),
loadImgAsync('http://www.tietuku.com/static/image/icon1.png')
]).then(showImgs)

Promise 对象的更多相关文章

  1. angular学习笔记(二十八-附2)-$http,$resource中的promise对象

    下面这种promise的用法,我从第一篇$http笔记到$resource笔记中,一直都有用到: HttpREST.factory('cardResource',function($resource) ...

  2. ES6深入学习记录(二)promise对象相关

    1.Promise的含义 Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件更合理和强大.ES6将其写进了语言标准,统一了用法,原生提供了promise对象. 所谓Promis ...

  3. es6中的promise对象

    Promise是异步里面的一种解决方案,解决了回调嵌套的问题,es6将其进行了语言标准,同意了用法,提供了`promise`对象, promise对象有三种状态:pending(进行中) .Resol ...

  4. ES6的promise对象应该这样用

    ES6修补了一位Js修真者诸多的遗憾. 曾几何时,我这个小白从js非阻塞特性的坑中爬出来,当我经历了一些回调丑陋的写法和优化的尝试之后,我深深觉得js对于多线程阻塞式的开发语言而言,可能有着其太明显的 ...

  5. Angularjs promise对象解析

    1.先来看一段Demo,看完这个demo你可以思考下如果使用$.ajax如何处理同样的逻辑,使用ng的promise有何优势? var ngApp=angular.module('ngApp',[]) ...

  6. JavaScript异步编程(1)- ECMAScript 6的Promise对象

    JavaScript的Callback机制深入人心.而ECMAScript的世界同样充斥的各种异步操作(异步IO.setTimeout等).异步和Callback的搭载很容易就衍生"回调金字 ...

  7. Promise对象

    1.Promise思想:每一个异步任务立刻返回一个Promise对象,由于是立刻返回,所以可以采用同步操作的流程.这个Promises对象有一个then方法,允许指定回调函数,在异步任务完成后调用. ...

  8. angularJS中的Promise对象($q)的深入理解

    原文链接:a better way to learn AngularJS - promises AngularJS通过内置的$q服务提供Promise编程模式.通过将异步函数注册到promise对象, ...

  9. 通过一道笔试题浅谈javascript中的promise对象

    因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...

  10. ECMAScript6的Promise对象

    1. 概念 Promise对象用于异步(asynchronouss)计算,一个Promise对象代表着一个还未完成,但预期完成的操作. 2. 出现原因: 1)  如果你需要通过ajax发送多次请求,而 ...

随机推荐

  1. Spring Boot-------项目搭建及注解

    Spring Boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发人员不再需 ...

  2. spring报错NoClassDefFoundError等与第三方jar包导入问题

    今天配置spring,遇到各种报错的问题,做一个小小总结. 1.刚开始我忘了引入commons-logging,报错.--解决方式:下载并引入该jar包 2.spring以及commons-loggi ...

  3. 团队作业8——第二次项目冲刺(Beta阶段)--5.23 third day

    团队作业8--第二次项目冲刺(Beta阶段)--5.23 third day Day three: 会议照片 项目进展 今天是beta冲刺的第三天,组长回到了队伍当中,正式开始改进alpha中存在的功 ...

  4. 展示博客(Beta阶段)

    展示博客 0x00 团队成员 成员 博客地址 简介 黄建英 http://www.cnblogs.com/smilehjy/ beta阶段的新成员,负责前端界面调整 谢晓萍 http://www.cn ...

  5. 201521123044 《Java程序设计》第7周学习总结

    1. 本章学习总结 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 源代码: //contains public boolean contain ...

  6. 201521123045 《Java程序设计》第7周学习总结

    Java 第七周总结 1. 本周学习总结 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代码 public boolean contains(Obj ...

  7. 201521123008《Java程序设计》第五周实验总结

    1.本章学习总结 2.书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改正该错误.并分析输出结果. 不能.Sy ...

  8. 201521123025《java程序设计》第11周学习总结

    1. 本周学习总结 2. 书面作业 Q1.互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用synchronized修饰方法实现互斥同步访问,还有什么办法实现互斥同步 ...

  9. JAVA课程设计 学生成绩管理

    学生成绩管理 可实现功能: 添加学生功能:姓名.学号.性别.出生年月日.(学号自动生成且唯一) 添加学生成绩功能:每个人都有数学.Java与体育四门课,可分课程输入成绩. 根据学生学号查找学生成绩功能 ...

  10. 201521123031 《Java程序设计》第9周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己 ...