Promise

Promise

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

Promise对象有以下两个特点。

(1)对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。
(2)Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。

    //执行的顺序 :new Promise 中的函数 ==>  当前队列中的同步代码  ==>  then中的回调函数
    const promise1 = new Promise(function (resolve, reject) { //异步代码,resolve成功,reject失败  二者之间只能执行一个
        // ... some code
        console.log("promise");

        if ( /* 异步操作成功 */ ) {
            resolve(value);
        } else {
            reject(error);
        }
    });
   //第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。
    promise1.then(function (value) {
        // success
    }, function (error) {
        // failure
    });

Promise.prototype.then()

then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。

异步加载图片的例子
    function loadImageAsync(url) {
        return new Promise(function (resolve, reject) {
            const image = new Image();
            image.onload = function () {
                resolve(image);
            };
            image.onerror = function () {
                reject(new Error('Could not load image at ' + url));
            };
            image.src = url;
        });
    }
    loadImageAsync("http://img4.imgtn.bdimg.com/it/u=2350302849,3323337377&fm=26&gp=0.jpg").then((img)=>{
        box.appendChild(image);//显示在页面上
        console.log("success");
    }),(e)=>{
        console.log(e);
    }
Promise对象实现的 Ajax 操作的例子
	const getJSON = function(url) {
	  const promise = new Promise(function(resolve, reject){
	    const handler = function() {
	      if (this.readyState !== 4) {
	        return;
	      }
	      if (this.status === 200) {
	        resolve(this.response);
	      } else {
	        reject(new Error(this.statusText));
	      }
	    };
	    const client = new XMLHttpRequest();
	    client.open("GET", url);
	    client.onreadystatechange = handler;
	    client.responseType = "json";
	    client.setRequestHeader("Accept", "application/json");
	    client.send();
	  });
	  return promise;
	};
	
	getJSON("/posts.json").then(function(json) {
	  console.log('Contents: ' + json);
	}, function(error) {
	  console.error('出错了', error);
	});

Promise.prototype.catch()

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

	getJSON('/posts.json').then(function(posts) {
	  // ...
	}).catch(function(error) {
	  // 处理 getJSON 和 前一个回调函数运行时发生的错误
	  console.log('发生错误!', error);
	});

getJSON方法返回一个 Promise 对象,如果该对象状态变为resolved,则会调用then方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch方法指定的回调函数,处理这个错误。
另外,then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获

如果 Promise 状态已经变成resolved,再抛出错误是无效的。

	const promise = new Promise(function(resolve, reject) {
	  resolve('ok');
	  throw new Error('test');
	});
	promise
	  .then(function(value) { console.log(value) })
	  .catch(function(error) { console.log(error) });
	// ok
	//Promise 的状态一旦改变,就永久保持该状态,不会再变了。

Promise 对象后面要跟catch方法,这样可以处理 Promise 内部发生的错误。catch方法返回的还是一个 Promise 对象,因此后面还可以接着调用then方法。

	const someAsyncThing = function() {
	  return new Promise(function(resolve, reject) {
	    // 下面一行会报错,因为x没有声明
	    resolve(x + 2);
	  });
	};
	
	someAsyncThing()
	.catch(function(error) {
	  console.log('oh no', error);
	})
	.then(function() {
	  console.log('carry on');
	});
	// oh no [ReferenceError: x is not defined]
	// carry on

Promise.all()

Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。

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

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

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

    let p1 = new Promise((resolve,reject)=>{
        resolve("p1 ok");
    });
    let p2 = new Promise((resolve,reject)=>{
        //reject("error"); //1.
        //resolve("p2 ok"); //2.
    });
    let p3 = new Promise((resolve,reject)=>{
        resolve("p3 ok");
    });

    let pAll = Promise.all([p1,p2,p3]);
    pAll.then((res)=>{
        console.log(res);//1. ["p1 ok", "p2 ok", "p3 ok"]
        //如果其中一个变成reject,则最后为失败  2. error
    }).catch((e)=>{
        console.log(e);
    })

如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。

	const p1 = new Promise((resolve, reject) => {
	  resolve('hello');
	})
	.then(result => result)
	.catch(e => e);
	
	const p2 = new Promise((resolve, reject) => {
	  throw new Error('报错了');
	})
	.then(result => result)
	.catch(e => e);
	
	Promise.all([p1, p2])
	.then(result => console.log(result))
	.catch(e => console.log(e));
	// ["hello", Error: 报错了]

p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。

如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。

	const p1 = new Promise((resolve, reject) => {
	  resolve('hello');
	})
	.then(result => result);
	
	const p2 = new Promise((resolve, reject) => {
	  throw new Error('报错了');
	})
	.then(result => result);
	
	Promise.all([p1, p2])
	.then(result => console.log(result))
	.catch(e => console.log(e));
	// Error: 报错了

Promise.race()

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

	const p = Promise.race([p1, p2, p3]);
    let p1 = new Promise((resolve,reject)=>{
        resolve("p1 ok");//首先进行
    });
    let p2 = new Promise((resolve,reject)=>{
        reject("error"); 
    });
    let pAll = Promise.race([p1,p2]);
    pAll.then((res)=>{
        console.log(res);//p1 ok
    }).catch((e)=>{
        console.log(e);
    })
    let p1 = new Promise((resolve,reject)=>{
        reject("error");
    });
    let p2 = new Promise((resolve,reject)=>{
        resolve("p2 ok");
    });
    let pAll = Promise.race([p1,p2]);
    pAll.then((res)=>{
        console.log(res);//error
    }).catch((e)=>{
        console.log(e);
    })
    let p1 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve("JS");
        },2000);
    });
    let p2 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            resolve("ES6");
        },1000);
    });
    let p3 = new Promise((resolve, reject) => {
        setTimeout(()=>{
            reject("111");//最快进行
        },100);
    });
    let pAll = Promise.race([p1, p2, p3]);
    pAll.then((res) => {
        console.log(res);//111
    }).catch((e) => {
        console.log(e);
    })
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值