Promise学习笔记

172 阅读3分钟

异步编程的一种解决方案,解决回调函数多层嵌套的问题,即callback问题。 ES6将其写入了语言标准,提供了Promise对象。

三种状态

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

特点

  1. 对象的状态不受外界影响,这也就是Promise起名的来源;
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。

缺点

  1. 无法取消Promise,一旦新建它就会立即执行,无法中途取消;
  2. 如果不设置回调函数,不会抛出Promise的内部错误;
  3. 当处于pending状态时,无法得知目前进展到那个阶段。

基本用法

Promise对象是一个构造函数,用来生成Promise实例。

生成实例

const promise = new Promise(function(resolve, reject){
    // 一些操作
    if(/*异步操作成功*/){
        resolve(value);
    } else {
        reject(error);
    }
});
/*箭头函数写法*/
const promise = new Promise((resolve, reject) => {
    // 一些操作
    if(/*异步操作成功*/){
        resolve(value);
    } else {
        reject(error);
    }
});

Promise构造函数接受一个函数作为参数,这个函数又有两个参数resolve和reject,这两个参数也是函数,由JS引擎提供。 reslove是异步操作调用成功时调用,并将操作结果作为参数传递出去; reject是异步操作失败时调用,并将错误作为参数传递出去。

实例调用

let promise = new Promise((resolve, reject) => {
    console.log('Promise');
    resolve();
});
promise.then(()=>{
    console.log('resolve');
},()=>{
    console.log('reject');
});
console.log('Hi');

// 执行结果:
// Promise
// Hi
// resolve

Promise方法

then

then方法的第一个参数是resolved状态的回调函数,第二个参数(可选)是rejected状态的回调函数。 then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。

catch

Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。 Promise对象的错误具有‘冒泡’性质,会一直向后传递,直到被捕获为止。

getJSON('/post/1.json').then(function(post) {
  return getJSON(post.commentURL);
}).then(function(comments) {
  // some code
}).catch(function(error) {
  // 处理前面三个Promise产生的错误
});

建议:不要在then中处理Reject状态的回调函数,使用catch方法处理。

// bad
promise
  .then(function(data) {
    // success
  }, function(err) {
    // error
  });

// good
promise
  .then(function(data) {
    // success
  })
  .catch(function(err) {
    // error
  });

finally

不管promise最后的状态,执行完then或catch指定的回调函数之后,肯定会调用finally指定的回调函数。

all

将多个Promise实例包装成一个新的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的回调函数。

race

将多个Promise实例包装成一个新的Promise实例。

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

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

allSettled

将多个Promise实例包装成一个新的Promise实例。等到所有参数实例都返回结果(无论resloved还是rejected),才会结束。

reslove

将现有对象转换成Promise对象。

reject

返回一个rejected状态的Promise实例。

Promise应用

  • 优化层层嵌套的回调写法
// 回调嵌套写法
function test (callback){
  callback('111');
} 
test((value)=>{
  console.log('test'+value)
});

// Promise写法
var promise = new Promise((resolve)=>{
  resolve('222')
});
promise.then((value)=>{
  console.log('promise'+value)
});

// 执行结果:
//"test111"
//"promise222"
  • 实现Ajax
//request处理,错误会reject回去,业务请求中需要处理失败结果用catch方式
function reuqest(url, options = {}) {
  //带上AppStoken参数
	url = _stitchUrlParam(url, 'app_stoken=' + getAppStoken());
	return new Promise((resolve, reject) => {
		wx.request({
			url: url,
			header: options.headers,
			data: options.body || {},
			method: options.method,
			success: function (res) {
				res = _parseData(res) || {};
				const statusCode = res.statusCode,
					code = res.data.code,
					msg = statusCode != 200 ? constant.NETWORKERROR : res.data.msg
				/* 不在正确码、特殊码范围内报错*/
				if (statusCode != 200 || (!specialCode.includes(code))) {
				    //根据code做一些去登录页之类的处理
					_handelErrorByCode(code, msg) 
					reject(res.data)
				} else { //正确结果
					resolve(res)
				}
			},
			fail: function (res) {
				res = _parseData(res) || {}
				wx.showToast({title: constant.NETWORKERROR, type: 'warn'});
				reject(res);
			}
		});
	});
}