js异步编程二:promise链式调用,异常处理,静态方法,并行和执行时序

相比传统的回调函数的方式,Promise最大的优势是可以链式调用,可以最大程度的避免回调嵌套。

  • Promise对象的then方法返回的是一个全新的Promise对象。
  • 后面的then方法就是在为上一个then返回的Promise注册回调。
  • 前面then方法中回调函数的返回值会作为后面then方法回调的参数。
  • 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束。
var promise = ajax("user.json");
var promise2 = promise.then(
  function onFulfilled(value) {
    console.log("onFulfilled", value);
  },
  function onRejected(error) {
    console.log("onRejected", error);
  }
);
console.log(promise == promise2);

在这里插入图片描述
then的内部也会返回一个Promise对象,但不等于原来的对象,所以说这里的链式调用并不是常见的在方法内部去返回this的方式实现的

Promise异常处理
Promise调用结果一旦失败就会在调用在then方法中调用onRejected回调函数,如果在执行中出现了异常或者手动抛出异常,也会调 用onRejected回调函数

function ajax(url) {
  return new Promise(function(resolve, reject) {
    throw new Error();//手动抛出一个异常
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.responseType = "json";
    xhr.onload = function() {
      if (this.status == 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    xhr.send();
  });
}


ajax("user.json").then(
   function onFulfilled(value) {
    console.log("onFulfilled", value);
  },
  function onRejected(error) {
    console.log("onRejected", error);
  }
);

在这里插入图片描述
可以用catch方法去注册onRejected回调,其实就是then方法的一个别名

因为每个then方法都会返回一个全新的Promise对象,通过链式调用的方式调用的catch实际上在给前面then方法返回的Promise对象指定失败的回调,并不是直接给第一个Promise对象所指定的,只不过因为这是同一个Promise的链条,前面Promise的异常会一直往后传递,所以在上面例子catch里才能够捕获到第一个Promise当中的异常。catch其实是then的第二个参数

ajax("user11.json")//访问一个不存在的地址也会捕获到上面手写的异常
  .then(function onFulfilled(value) {
    console.log("onFulfilled", value);
  })
  .catch(function onRejected(error) {
    console.log("onRejected", error);
  });

在这里插入图片描述
除次之外还可以在全局对象上注册一个unhandledrejection事情处理一些代码中没有被手动捕获的promise异常
在这里插入图片描述

这是在全局中注册的捕获异常的方法,不推荐使用,还是要在代码中明确捕获每一个可能的异常

Promise静态方法
Promise.resolve():快速的把一个值转成promise对象,比如

Promise.resolve('foo').then(function(value){
  console.log(value);
});

会直接返回一个状态是foo的成功的promise对象。等价于

new Promise(function(resolve,reject){
  resolve("foo");
});

Promise.reject():快速状态一个一定是失败的的Promise对象,不管传入什么样的数据都是Promise失败的原因

Promise.reject(new Error('rejected')).catch(function(error){
  console.log(error);
});

Promise并行执行
如果在一个页面中经常要请求一个接口的情况,如果这些请求相互之间没有什么依赖,最好的选择是同时去请求它们,这样避免一个个依次去请求会消耗更多的时间。
如何知道所有的请求任务都结束了呢?传统的方法会有一个计数器,每调用成功一个就累加一下。这种方法比较麻烦,还要考虑出现异常的情况。
Promise的all接收的是一个数组,数组里每一个都是promise对象。all方法会返回一个全新的promise对象,当所有的请求都完成后,这个promise对象才会完成,then方法里返回一个数组,这个数组里包含着每个异步任务执行的结果

var promise = Promise.all([ajax("users.json"), ajax("users1.json")]);

promise
  .then(function(values) {
    console.log(values);
  })
  .catch(function(error) {
    console.log(error);
  });

只有当这两个请求任务都成功结束了,这个新的promise才会成功结束,若其中一个任务失败,这个promise就会失败。

Promise.race()同样可以把多个promise对象组合成一个全新的promise对象。
Promise.all()是等待所有任务结束才会结束,而race()只会等待第一个结束的任务一起结束
在这里插入图片描述
Promise的执行时序/宏任务vs微任务

console.log("global start");
setTimeout(() => {
  console.log("setTimeout");
}, 0);
Promise.resolve()
  .then(() => {
    console.log("promise1");
  })
  .then(() => {
    console.log("promise2");
  })
  .then(() => {
    console.log("promise3");
  });

console.log("global end");

在这里插入图片描述
先打印了promise再打印了settimeout,因为promise异步执行时序会有点特殊。promise的回调会作为微任务执行。
宏任务和微任务的区别
回调队列中的任务称之为“宏任务”,宏任务执行过程中可以临时加上一些额外需求,可以选择作为一个新的宏任务进到队列中排队,也可以作为当前任务的“微任务”是指直接在当前任务结束过后立即执行,而不是到整个队伍的末尾重新排队。
微任务是为了提高整体的响应能力。目前绝大多数异步调用都是作为宏任务执行的,而promise&MutationObserver对象,还有node端有一个process.nextTick是微任务,直接在本轮调用的末尾就执行了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值