Promise 是什么?

PromiseES6 提供的一种异步编程解决方案,解决了传统异步处理的回调金字塔问题; Promise 对象是一个构造函数,用来生成 Promise 实例;
Promise 构成:console.dir(Promise);

javascript Profiler面板_数组

可以看出,Promise 这个构造函数自己身上有 resolve(), reject(), all(), race() 这几种常见的方法,原型上有 catch(), then(), finally() 常用的方法,所以 Promise 的实例可以使用 catch(), then() 等方法;

Promise 的用法

  1. Promise 构造函数接收一个函数作为参数,这个函数有两个参数,这两个参数都是函数,由 js引擎提供;
// 传递一个函数作为实例化参数
const promise = new Promise(function(resolve, reject) {
	if (/* 异步操作成功 */) {
        // 改变状态为 fulfilled
		resolve(value);
	} else {
        // 改变状态为 rejected
		reject(error);
	}
});
  1. resolve 函数的作用是将 Promise 对象的状态从 "待定"(pending) 改变为 "成功"(fulfilled), 在异步操作成功的时候调用,并将异步操作的结果作为参数传递出去;
    reject 函数的作用是将 Promise 对象的状态从 "待定"(pending) 改变为 "失败"(rejected), 在异步失败的的时候调用,并将异步操作报的错误作为参数传递出去;
  2. 可以使用 Promise 生成的实例 promise 调用 then() 分别指定 fulfilled状态rejected状态 的回调方法;
/**
 * promise 实例的then方法,接收两个参数,这两个参数都是函数
 * 第一个参数:Promise对象的状态变为 resolved 状态时调用
 * 第二个参数(可选的):Promise对象的状态变为 rejected 状态时调用
*/
promise.then(function(value) {
	// value 为 Promise 对象实例化时调用resolve(...)方法传入的值
	// success code
}, function(error) {
	// error 为 Promise 对象实例化时调用reject(...)方法传入的错误
	// failure code
});

Promise 链式写法

const promise = new Promise(function(resolve, reject) {
	// 获取一个10 以内的正整数
	const num = Math.floor(Math.random()*10);
	if (num > 5) {
		resolve("num 大于 5");
	} else {
		reject("num 小于 5")
	}
});

// 第一个 then
promise.then(function(value) {
	// 状态由 pending 变为 fulfilled 的回调
	// 这里 value 的值为 (num 大于 5)
	return "成功了";
}, function(error) {
	// 状态由 pending 变为 rejected 的回调
	// 这里 error 的值为 (num 小于 5)
})
// 第二个 then
.then(function(value) {
	// 这里 value 的值为 上一个 fulfilled 状态回调的返回值(成功了)
	console.log(value);  // 如果 num > 5 打印 成功了
});

实例化一个 Promise,参数为一个函数,函数体实现随机生成一个10以内的正整数,如果 num > 5Promise 状态改为 fulfilled 状态,并向下传递了一个 "num 大于 5"的字符串,反之,将 Promise 状态改为 rejected 状态,向下传递了一个 "num 小于 5"的字符串;
当第一个 promise 的成功回调里返回 "成功了" 时,第二个 promise 的成功回调的参数就是 "成功了";

由此可以看出,第一个 promise 不管成功回调还是失败回调,他的返回值作为第二个 promise 中的成功时回调函数的参数值;

链式写法能一直then下去的原因:链式调用靠的是返回新的 promise,来保证可以一直走成功或失败;

Promise.resovle

返回一个 Promise 实例,这个实例处于 resolve 状态
根据传入的参数不同有不同返回值:

  1. 值(对象, 数组, 字符串等):作为 resolve 传递出去的值;
  2. Promise 实例:原封不动返回;
// 返回一个立刻成功的promise
// 别人提供 给你一个方法,需要你传入一个promise,但你只有一个普通的值,
// 你就可以通过这个方法把这个普通的值(string number object)转成一个promise对象
Promise.resolve = function(value){
	return new Promise(function(resolve){
		resolve(value);
	});
}

示例:

const promise = Promise.resolve(66);

promise.then(function(resolve) {
	// 值为调用 .resolve() 传入的参数
	console.log(resolve);   // 66
});
// 值为 promise 实例原样返回
console.log(promise === Promise.resolve(promise));  // true

Promise.reject

返回一个 Promise 实例,这个实例处于 reject 状态。
参数一般就是抛出的错误信息;

//返回一个立刻失败的promise
Promise.reject = function(reason){
	return new Promise(function(resolve,reject){
		reject(reason);
	});
}

示例:

const promise = Promise.reject("出错啦");
promise.then(null, function(error) {
    // 值为调用 .reject() 传入的参数
    console.log(error);     // 出错啦
});

Promise.catch

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

//catch原理就是只传失败的回调
Promise.prototype.catch = function(onRejected){
	this.then(null,onRejected);
}

示例:

const promise = Promise.reject("出错啦");
// 和 then() 的第二个参数一样,用来指定 reject 的回调
promise.catch(function(catchError) {
    // 值为调用 .reject() 传入的参数
    console.log(catchError);    // 出错啦
});

// 另一种用法:在执行 resolve 的回调(then 中的第一个参数)时,
// 如果抛出异常了(代码出错了),并不会报错卡死 js,而是会进到这个 catch 方法中
const exceptionPromise = new Promise(function(resolve, reject) {
    resolve("成功了");
});

exceptionPromise.then(function(value) {
    console.log(value);
    // exception 在当前位置未定义
    return exception;
}).catch(function(catchError) {
    // 在执行 resolve 的回调时,代码中存在语法错误,
    // 此时 catchError 值为抛出的异常信息
    console.log(catchError);    // ReferenceError: exception is not defined
});
// 同理 reject 回调也是如此;

Promise.all

参数:接受一个iterable(Array,Map,Set),iterable内都是Promise实例
返回值:返回一个 Promise 实例,这个 Promise 实例的状态转移取决于参数的 Promise 实例的状态变化。当参数中所有的实例都处于 resolve 状态时,返回的 Promise 实例会变为 resolve 状态。如果参数中任意一个实例处于 reject 状态,返回的 Promise 实例变为 reject 状态;

Promise.all = function(promises){
	return new Promise(function(resolve,reject){
		let done = gen(promises.length,resolve);
		for(let i=0;i<promises.length;i++){
			promises[i].then(function(data){
				done(i,data);
			},reject);
		}
	});
}

示例:

const promise1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise1 success")
    }, 1000);
});

const promise2 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise2 success")
    }, 2000);
});

const promise3 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise3 success")
    }, 3000);
});

// 传入由三个 promise 组成的数组
Promise.all([promise1, promise2, promise3])
.then(function(resolves) {
    // 三秒后输出以下结果(数组中的Promise全部完成,由最慢的决定)
    // ['promise1 success', 'promise2 success', 'promise3 success']
    console.log(resolves);
});

Promise.race

参数:接受一个iterable(Array,Map,Set),iterable内都是 Promise 实例
返回值:返回一个 Promise 实例,这个 Promise 实例的状态转移取决于参数的 Promise 实例的状态变化。当参数中任何一个实例处于 resolve 状态时,返回的 Promise 实例会变为 resolve 状态。如果参数中任意一个实例处于 reject 状态,返回的 Promise 实例变为 reject 状态;

Promise.race = function(promises){
	return new Promise(function(resolve,reject){
		for(let i=0;i<promises.length;i++){
			promises[i].then(resolve,reject);
		}
	});
}

示例:

const promise1 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise1 success")
    }, 1000);
});

const promise2 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise2 success")
    }, 2000);
});

const promise3 = new Promise(function(resolve, reject) {
    setTimeout(function() {
        resolve("promise3 success")
    }, 3000);
});

// 传入由三个 promise 组成的数组
Promise.race([promise1, promise2, promise3])
.then(function(resolves) {
    // 1秒后输出以下结果(谁先完成结果就是谁,由最快的决定)
    // promise1 success
    console.log(resolves);
});

总结

Promise 对象有三种状态,并且不受外界影响,Promise 的状态一旦改变就不会再变,并且状态不可逆,只能从 pending(待定) 改变成 fulfilled(成功)pending(待定) 改变成 rejected(失败);

  1. pending(待定)
  2. fulfilled(成功)
  3. rejected(失败)

正是因为这些特点导致 Promise 有三个缺点:

  1. 无法取消 Promise,一旦新建就会立即执行,中途无法取消;
  2. 如果没有设置回调函数,Promise 内部抛出的错误,不会反映到外部;
  3. Promise 处于 pending 状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将完成;