1.13Promise 对象

概述

Promise 是一个对象,从它可以获取异步操作的消息。是异步编程的一种解决方案。

Promise 状态

状态的特点

Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态。

Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)。

const p1 = new Promise(function(resolve,reject){
    resolve('success1');
    resolve('success2');
}); 
const p2 = new Promise(function(resolve,reject){  
    resolve('success3'); 
    reject('reject');
});

p1.then(function(value){  
    console.log(value); // success1
});
p2.then(function(value){ 
    console.log(value); // success3
});

状态的缺点

无法取消 Promise ,一旦新建它就会立即执行,无法中途取消。

如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。

当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

then 方法

then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。

then 方法的特点

在 JavaScript 事件队列的当前运行完成之前,回调函数永远不会被调用。

const p = new Promise(function(resolve,reject){
  resolve('success');
});
 
p.then(function(value){
  console.log(value);
});
 
console.log('first');
// first
// success

通过 .then 形式添加的回调函数,不论什么时候,都会被调用。

通过多次调用.then

可以添加多个回调函数,它们会按照插入顺序并且独立运行。

const p = new Promise(function(resolve,reject){
  resolve(1);
}).then(function(value){ // 第一个then // 1
  console.log(value);
  return value * 2;
}).then(function(value){ // 第二个then // 2
  console.log(value);
}).then(function(value){ // 第三个then // undefined
  console.log(value);
  return Promise.resolve('resolve'); 
}).then(function(value){ // 第四个then // resolve
  console.log(value);
  return Promise.reject('reject'); 
}).then(function(value){ // 第五个then //reject:reject
  console.log('resolve:' + value);
}, function(err) {
  console.log('reject:' + err);
});

then 方法返回一个 resolved 或 rejected 状态的 Promise 对象,因此可以进行链式调用,且 Promise 对象的值就是这个返回值。 这也是promise可以解决异步编程回调地狱的原因

then 方法注意点

简便的 Promise 链式编程最好保持扁平化,不要嵌套 Promise。

注意总是返回或终止 Promise 链。

const p1 = new Promise(function(resolve,reject){
  resolve(1);
}).then(function(result) {
  p2(result).then(newResult => p3(newResult));
}).then(() => p4());

创建新 Promise 但忘记返回它时,对应链条被打破,导致 p4 会与 p2 和 p3 同时进行。

大多数浏览器中不能终止的 Promise 链里的 rejection,建议后面都跟上 .catch(error => console.log(error));


注意:then返回的promise对象p1的状态是由then内部回调函数的执行结果来决定的,不取决于p的状态,不取决于你调用的是p的成功或者失败的回调,也就是p1的状态只看回调函数的执行结果。

首先实例化一个promise对象。promise对象身上有then方法,可用来指定回调,对成功和失败的结果进行处理。它接受两个回调函数,一个是resolve成功的回调,一个是reject失败的回调。

回调函数的执行结果有几种情况:

1. 回调函数的返回结果是 非promise类型的 属性,则then方法返回的promise对象p1的状态为成功fulfilled,同时返回的结果就是promise对象p1成功的值11112222,如下图。

接收p成功的回调

接收p失败的回调

 

需要注意的是,如果你不写return,因为函数内部如果不写return默认返回结果是undefined,又undefined也是非promise类型,所以p1状态还是成功fulfilled,返回的promise成功值为undefined。 

2、如果回调函数的返回结果是promise对象,则p1的状态就取决于return返回的这个promise对象内部的状态,内部为resolve, 则p1状态为fulfilled,内部为reject,则p1状态为rejected

 

3.第三种情况为抛出错误,则p1状态为rejected,返回的结果就是你抛出的值 

 

 改变promise对象的状态(非then方法中)

 实例化一个promise对象,接受一个函数类型的值,里面可以封装异步操作。状态的改变只有两条路,进行中变为成功resolved,进行中变为失败rejected,而且只会改变一次,不可能从成功变为失败或者失败变为成功。

只有三种方法改变promise对象的状态,resolve/ reject/ throw抛出错误,如果在promise对象中不去改变他的状态,那么状态永远都是pending,也不会去执行回调函数

注意:return并不能改变他的状态,这不是在then方法中,then方法有自己的一套东西

注意点

1、promise对象里面的代码是同步执行的,只是回调函数才是异步执行的,因为你不改变状态就不会去执行回调。而且状态改变后,后续的代码继续执行。

 2、指定多个回调都会被执行

 

3、假设promise对象,状态变为失败,但是你的then每次只写成功的回调,那就找不到失败的回调,那么他会顺着链一直往下传递,直到找到失败的回调。这就是异常穿透。同理,你的promise对象,状态变为成功,但是你的链只写catch,那就找不到成功的回调,那么他会顺着链一直往下传递,直到找到成功的回调。
 


Promise 对象有以下两个特点: 

1、对象的状态不受外界影响。有三种状态

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

只有异步操作的结果,可以决定当前是哪一种状态

2、一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 Pending 变为 Resolved 和从 Pending 变为 Rejected

Promise 优缺点

可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise 对象提供统一的接口,使得控制异步操作更加容易。

首先,无法取消 Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。第三,当处于 Pending 状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)

Promise 创建

使用 new 来调用 Promise 的构造器来进行实例化。

Promise 构造函数包含一个参数和一个带有 resolve(解析)和 reject(拒绝)两个参数的回调。在回调中执行一些操作(例如异步),如果一切都正常,则调用 resolve,否则调用 reject。

 

已经实例化过 promise 对象可以调用 promise.then() 方法,传递 resolve 和 reject 方法作为回调。

promise.then() 是 promise 最为常用的方法

promise简化了对error的处理

Promise Ajax

上面代码中,resolve 方法和 reject 方法调用时,都带有参数。它们的参数会被传递给回调函数。reject 方法的参数通常是 Error 对象的实例,而 resolve 方法的参数除了正常的值以外,还可能是另一个 Promise 实例 

p1 和 p2 都是 Promise 的实例,但是 p2 的 resolve 方法将 p1 作为参数,这时 p1 的状态就会传递给 p2。如果调用的时候,p1 的状态是 pending,那么 p2 的回调函数就会等待 p1 的状态改变;如果 p1 的状态已经是 fulfilled 或者 rejected,那么 p2 的回调函数将会立刻执行。

Promise.prototype.then方法:链式操作

Promise.prototype.then 方法返回的是一个新的 Promise 对象,因此可以采用链式写法。

使用 then 方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数。

这种设计使得嵌套的异步操作,可以被很容易得改写,从回调函数的"横向发展"改为"向下发展"。 

 Promise.prototype.catch方法:捕捉错误

Promise.prototype.catch 方法是 Promise.prototype.then(null, rejection) 的别名,用于指定发生错误时的回调函数。

 Promise 对象的错误具有"冒泡"性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个 catch 语句捕获。

Promise.all方法,Promise.race方法 

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

Promise.all 方法接受一个数组作为参数,p1、p2、p3 都是 Promise 对象的实例。(Promise.all 方法的参数不一定是数组,但是必须具有 iterator 接口,且返回的每个成员都是 Promise 实例。

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

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

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

只要p1、p2、p3之中有一个实例率先改变状态,p的状态就跟着改变。那个率先改变的Promise实例的返回值,就传递给p的返回值。

如果Promise.all方法和Promise.race方法的参数,不是Promise实例,就会先调用下面讲到的Promise.resolve方法,将参数转为Promise实例,再进一步处理。

Promise.resolve 方法,Promise.reject 方法

有时需要将现有对象转为Promise对象Promise.resolve方法就起到这个作用。、

将 jQuery 生成 deferred 对象,转为一个新的 ES6 的 Promise 对象。

如果 Promise.resolve 方法的参数,不是具有 then 方法的对象(又称 thenable 对象),则返回一个新的 Promise 对象,且它的状态为fulfilled。

上面代码生成一个新的Promise对象的实例p,它的状态为fulfilled,所以回调函数会立即执行,Promise.resolve方法的参数就是回调函数的参数。

如果Promise.resolve方法的参数是一个Promise对象的实例,则会被原封不动地返回

Promise.reject(reason)方法也会返回一个新的Promise实例,该实例的状态为rejected。Promise.reject方法的参数reason,会被传递给实例的回调函数。

上面代码生成一个Promise对象的实例,状态为rejected,回调函数会立即执行。


回调地域以及解决方法 

回调函数

回调函数是作为参数传给另一个函数的函数,然后通过在外部函数内部调用该回调函数以完成某种操作。

回调函数和异步的关系

  • 回调函数不完全等于异步
  • 本质上说,回调函数是异步的
  • 异步是指JS代码的执行顺序,为了解决JS单线程可能导致阻塞的情况,必须编写异步代码
  • 回调可以理解为一种业务逻辑,回调函数是异步操作的一种基本方法

回调函数的作用

回调函数是异步编程最基本的方法,其优点是简单、容易理解和部署。
回调函数最大的缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling)

回调地狱是什么

回调函数的层层嵌套,就叫做回调地狱。造成代码可复用性不强,可阅读性差,可维护性(迭代性差),扩展性差等问题。
回调地狱的原因是,当人们试图以一种从上到下的视觉方式执行JS的方式编写JS,期望第1行发生的任何事情都会在第2行的代码开始运行之前完成,而代码的实际执行则事与愿违。
回调地狱的本质:①嵌套函数存在严重的耦合,牵一发而动全身。②错误处理比较艰难,不能使用try catch 和不能直接return。

怎样避免回调地狱

1.保持代码简短简洁,例如函数命名清晰

2.模块化

3.Promise

a.基本概念
Promise本身只是一个容器,真正异步的是它的两个回调resolve()和reject()
Promise本质 不是控制 异步代码的执行顺序(无法控制) , 而是控制异步代码结果处理的顺序
Promise对象有三个状态:pending(进行中),fulfilled(已成功),rejected(已失败)

b.使用Promise解决回调地狱
(1)promise创建时,里面的代码还是异步无序操作
(2)promise的原理是,利用then方法将异步操作的结果,按照顺序执行,catch方法用来接收处理失败时相应的数据。在上一个promise的then方法中,返回下一个promise对象
总结:不要在创建promise的时候去处理异步操作结果,而应该通过 then() 方法来处理

封装一个promise

要求:顺序读取a,b,c

 

c.Promise的优缺点
优点

(1)避免了回调地狱,用同步的方式写异步的代码
(2)控制异步操作更容易,Promise对象提供了统一的接口
(3)链式操作,可以在then中继续写Promise对象并返回,然后继续调用then来进行回调操作
缺点

(1)then的链式调⽤也会带来额外的阅读负担,不易读
(2)Promise对象一旦新建就会立即执行,无法中途取消
(3)若不设置回调函数,Promise内部会抛出错误,不会流到外部
(4)当处于pending状态时,无法得知当前处于哪一阶段

4.async/await
a.基本概念
async/await是 Generator 函数的语法糖,也就是处理异步操作的另一种高级写法
async/await是基于Promise实现的,它不能用于普通的回调函数
b.使用async/await解决回调地狱
async声明function是一个异步函数,返回一个promise对象,可以使用 then 方法添加回调函数。
async函数内部return语句返回的值,会成为then方法回调函数的参数。

 

c.async/awit的优缺点
优点

(1)内置执行器, Generator 函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器,也就是说,async 函数的执行,与普通函数一模一样,只要一行
(2)语义更清晰,与* 和 yield相比,async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果
(3)适用性更广,co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
缺点
滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性


promise.then返回结果几种情况_码完就打球的博客-CSDN博客_promise 返回结果

https://www.runoob.com/w3cnote/javascript-promise-object.html

回调函数与回调地狱及其解决方法 | JavaScript_风筝风的博客-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值