1.什么是Promise?
Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一
2.对于几种常见异步编程方案
- 回调函数
- 事件监听
- 发布/订阅
- Promise对象
这里就拿回调函数说说
1.对于回调函数 我们用Jquery的ajax获取数据时 都是以回调函数方式获取的数据
$.get(url, (data) => {
console.log(data)
)
2.如果说 当我们需要发送多个异步请求 并且每个请求之间需要相互依赖 那这时 我们只能 以嵌套方式来解决 形成 “回调地狱”
$.get(url, data1 => {
console.log(data1)
$.get(data1.url, data2 => {
console.log(data1)
})
})
这样一来,在处理越多的异步逻辑时,就需要越深的回调嵌套,这种编码模式的问题主要有以下几个:
- 代码逻辑书写顺序与执行顺序不一致,不利于阅读与维护。
- 异步操作的顺序变更时,需要大规模的代码重构。
- 回调函数基本都是匿名函数,bug 追踪困难。
- 回调函数是被第三方库代码(如上例中的 ajax )而非自己的业务代码所调用的,造成了 IoC 控制反转。
Promise 处理多个相互关联的异步请求
1.而我们Promise 可以更直观的方式 来解决 “回调地狱”
const request = url => {
return new Promise((resolve, reject) => {
$.get(url, data => {
resolve(data)
});
})
};
// 请求data1
request(url).then(data1 => {
return request(data1.url);
}).then(data2 => {
return request(data2.url);
}).then(data3 => {
console.log(data3);
}).catch(err => throw new Error(err));
2.相信大家在 vue/react 都是用axios fetch 请求数据 也都支持 Promise API
import axios from 'axios';
axios.get(url).then(data => {
console.log(data)
})
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
3.Promise使用
1.Promise 是一个构造函数, new Promise 返回一个 promise对象 接收一个excutor执行函数作为参数, excutor有两个函数类型形参resolve reject
const promise = new Promise((resolve, reject) => {
// 异步处理
// 处理结束后、调用resolve 或 reject
});
2.promise相当于一个状态机
promise的三种状态
- pending
- fulfilled
- rejected
1.promise 对象初始化状态为 pending
const promise = new Promise;
2.当调用resolve(成功),会由pending => fulfilled
3.当调用reject(失败),会由pending => rejected
注意promsie状态 只能由 pending => fulfilled/rejected, 一旦修改就不能再变
3.promise对象方法
1.then方法注册 当resolve(成功)/reject(失败)的回调函数
// onFulfilled 是用来接收promise成功的值
// onRejected 是用来接收promise失败的原因
promise.then(onFulfilled, onRejected);
then方法是异步执行的
2.resolve(成功) onFulfilled会被调用
const promise = new Promise((resolve, reject) => {
resolve('fulfilled'); // 状态由 pending => fulfilled
});
promise.then(result => { // onFulfilled
console.log(result); // 'fulfilled'
}, reason => { // onRejected 不会被调用
})
3.reject(失败) onRejected会被调用
const promise = new Promise((resolve, reject) => {
reject('rejected'); // 状态由 pending => rejected
});
promise.then(result => { // onFulfilled 不会被调用
}, reason => { // onRejected
console.log(rejected); // 'rejected'
})
4.promise.catch
在链式写法中可以捕获前面then中发送的异常,
promise.catch(onRejected)
相当于
promise.then(null, onRrejected);
// 注意
// onRejected 不能捕获当前onFulfilled中的异常
promise.then(onFulfilled, onRrejected);
// 可以写成:
promise.then(onFulfilled)
.catch(onRrejected);
4.promise chain
promise.then方法每次调用 都返回一个新的promise对象 所以可以链式写法
function taskA() {
console.log("Task A");
}
function taskB() {
console.log("Task B");
}
function onRejected(error) {
console.log("Catch Error: A or B", error);
}
var promise = Promise.resolve();
promise
.then(taskA)
.then(taskB)
.catch(onRejected) // 捕获前面then方法中的异常
5.Promise的静态方法
1.Promise.resolve 返回一个fulfilled状态的promise对象
Promise.resolve('hello').then(function(value){
console.log(value);
});
Promise.resolve('hello');
// 相当于
const promise = new Promise(resolve => {
resolve('hello');
});
2.Promise.reject 返回一个rejected状态的promise对象
Promise.reject(24);
new Promise((resolve, reject) => {
reject(24);
});
3.Promise.all 接收一个promise对象数组为参数
只有全部为resolve才会调用 通常会用来处理 多个并行异步操作
const p1 = new Promise((resolve, reject) => {
resolve(1);
});
const p2 = new Promise((resolve, reject) => {
resolve(2);
});
const p3 = new Promise((resolve, reject) => {
reject(3);
});
Promise.all([p1, p2, p3]).then(data => {
console.log(data); // [1, 2, 3] 结果顺序和promise实例数组顺序是一致的
}, err => {
console.log(err);
});
4.Promise.race 接收一个promise对象数组为参数
Promise.race 只要有一个promise对象进入 FulFilled 或者 Rejected 状态的话,就会继续进行后面的处理。
function timerPromisefy(delay) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(delay);
}, delay);
});
}
var startDate = Date.now();
Promise.race([
timerPromisefy(10),
timerPromisefy(20),
timerPromisefy(30)
]).then(function (values) {
console.log(values); // 10
});
4. Promise 代码实现
// 定义三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function Promise(executor) {
let that = this; // 缓存当前promise实例
that.status = PENDING; // 设置初始状态
// 定义存放成功的回调的数组
that.onResolvedCallbacks = [];
// 定义存放失败回调的数组
that.onRejectedCallbacks = [];
// resolve被调用 promise 状态会由 pending => fulfilled
function resolve(value) {
if (value != null && value.then && typeof value.then == 'function') { /
return value.then(resolve, reject);
}
// 只能由pending状态转换为fulfilled 并将成功态结果传递给onFulfilled
setTimeout(function() {
if (that.status == PENDING) {
that.status = FULFILLED;
that.value = value; // 成功后会得到一个值,这个值不能改
// 调用所有成功的回调
that.onResolvedCallbacks.forEach(cb => cb(that.value));
}
})
}
// resolve被调用 promise 状态会由 pending => ejected 并将拒绝原因传递给onRejected
function reject(reason) {
setTimeout(function() {
// 只能由pending状态转换为rejected
if (that.status == PENDING) {
that.status = REJECTED;
that.value = reason; //失败的原因给了value
that.onRejectedCallbacks.forEach(cb => cb(that.value));
}
});
}
try {
// executor函数执行可能会异常,所以需要捕获
executor(resolve, reject);
} catch (e) { // 如果异常则修改promise状态为rejected 并将异常信息传递进去
reject(e);
};
}
// onFulfilled的返回值几种情况
// 1.普通值
// 2.thenable对象
// 3.函数
// 4.promsie对象
// onFulfilled 的返回值情况处理函数
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('循环引用'));
}
let called = false; // promise2是否已经resolve 或reject了
if (x instanceof Promise) {
if (x.status == PENDING) {
x.then(function(y) { // 继续解析这个x的onFulfilled返回值
resolvePromise(promise2, y, resolve, reject);
}, reject);
} else {
x.then(resolve, reject);
}
// x是一个thenable对象或函数,只要有then方法的对象,
} else if (x != null && ((typeof x == 'object') || (typeof x == 'function'))) {
// 当我们的promise和别的promise进行交互,编写这段代码的时候尽量的考虑兼容性,允许别人瞎写
try {
let then = x.then;
if (typeof then == 'function') {
// 有些promise会同时执行成功和失败的回调
then.call(x, function(y) {
// 如果promise2已经成功或失败了,则不会再处理了
if (called)
return;
called = true;
resolvePromise(promise2, y, resolve, reject)
}, function(err) {
if (called)
return;
called = true;
reject(err);
});
} else {
// 如果x是一个普通对象直接resolve
resolve(x);
}
} catch (e) {
if (called)return;
called = true;
reject(e);
}
} else {
// 如果X是一个普通 的值,则用x的值去resolve promise2
resolve(x);
}
}
// onFulfilled 是用来接收promise成功的值或者失败的原因
// then方法是异步的 每次调用都会返回一个新的promise 从而实现方法链
Promise.prototype.then = function(onFulfilled, onRejected) {
// 如果成功和失败的回调没有传,则表示这个then没有任何逻辑,只会把值往后抛
onFulfilled = typeof onFulfilled == 'function'
? onFulfilled
: function(value) {
return value
};
onRejected = typeof onRejected == 'function'
? onRejected
: reason => {
throw reason
};
// 如果当前promise状态已经是成功态了,onFulfilled直接取值
let that = this;
let promise2;
if (that.status == FULFILLED) {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() { // 异步调用
try {
let x = onFulfilled(that.value);
// 如果获取到了返回值x,会走解析promise的过程
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
//如果执行成功的回调过程中出错了,用错误原因把promise2 reject
reject(e);
}
})
});
}
if (that.status == REJECTED) {
return promise2 = new Promise(function(resolve, reject) {
setTimeout(function() { // 异步调用
try {
let x = onRejected(that.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
}
if (that.status == PENDING) { // 异步调用
return promise2 = new Promise(function(resolve, reject) {
that.onResolvedCallbacks.push(function() {
try {
let x = onFulfilled(that.value);
// 如果获取到了返回值x,会走解析promise的过程
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
that.onRejectedCallbacks.push(function() {
try {
let x = onRejected(that.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
}
//catch原理就是只传失败的回调
Promise.prototype.catch = function(onRejected) {
this.then(null, onRejected);
}
// Deferred 延迟对象
// Deferred 拥有 Promise
// Deferred 具备对 Promise的状态进行操作的特权方法
// 想了解 可以看看 jQuery.Deferred
Promise.deferred = Promise.defer = function() {
let defer = {};
defer.promise = new Promise(function(resolve, reject) {
defer.resolve = resolve;
defer.reject = reject;
});
return defer;
}
function gen(times, cb) {
let result = [],
count = 0;
return function(i, data) {
result[i] = data;
if (++count == times) {
cb(result);
}
}
}
// all 方法实现
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);
}
});
}
// race 方法实现
Promise.race = function(promises) {
return new Promise(function(resolve, reject) {
for (let i = 0; i < promises.length; i++) {
promises[i].then(resolve, reject);
}
});
}
// 返回一个立刻成功的promise
// 别人提供 给你一个方法,需要你传入一个promise,但你只有一个普通的值,你就可以通过这个方法把这个普通的值(string number object)转成一个promise对象
Promise.resolve = function(value) {
return new Promise(function(resolve) {
resolve(value);
});
}
// 返回一个立刻失败的promise
Promise.reject = function(reason) {
return new Promise(function(resolve, reject) {
reject(reason);
});
}
module.exports = Promise;
Promise测试
npm i -g promises-aplus-tests
promises-aplus-tests Promise.js
相关知识参考资料
- [ES6-promise](ECMAScript 6入门)
- Promises/A+规范-英文
- [Promises/A+规范-翻译](人类身份验证 - SegmentFault)
- [Javascript异步编程的4种方法](Javascript异步编程的4种方法 - 阮一峰的网络日志)
- Lwenli_blog