promise的作用
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数更强大,避免了层层回调。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,现在原生提供Promise对象!
Promise使用:
// ... some code
const promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
- 我们可以看到,promise需要使用new操作符来生成实例,因此Promise是一个构造函数。
- 这个promise初始化的时候需要传入一个函数做为参数,并且这个函数的两个参数分别为:resolve和reject。
- resolve和reject是两个函数,由 JavaScript 引擎提供,不用自己部署。
- resolve函数的作用:将Promise对象状态从pending 变为 fulfilled。
- reject 函数的作用:将Promise对象状态从pending 变为 reject。
现在让我们看一下promise的原理
Promise 是一个状态工具,他有三个状态:pending, fulfilled, reject,因此我们先定义三个状态。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value or error once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers attached by calling .then or .done
var handlers = [];
}
Promise 在执行完异步操作后,会转变状态,所以代码变为这样。
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED; // 状态改变了
value = result;
}
function reject(error) {
state = REJECTED; // 状态改变了
value = error;
}
}
上面fulfill是一个比较low level的转变状态方法,但是有一个higher-level的转变状态方法:resolve
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise() {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
}
function reject(error) {
state = REJECTED;
value = error;
}
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
}
可以看到resolve先调用了方法getThen(),这个方法是判断result是否是promise,如果是的话,调用这个promise的then方法(使用doResolve()方法),如果不是的话,调用fulfill()方法。
/**
* Check if a value is a Promise and, if it is,
* return the `then` method of that promise.
*
* @param {Promise|Any} value
* @return {Function|Null}
*/
function getThen(value) {
var t = typeof value;
if (value && (t === 'object' || t === 'function')) {
var then = value.then;
if (typeof then === 'function') {
return then;
}
}
return null;
}
/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*
* @param {Function} fn A resolver function that may not be trusted
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
function doResolve(fn, onFulfilled, onRejected) {
var done = false;
try {
fn(function (value) {
if (done) return
done = true
onFulfilled(value)
}, function (reason) {
if (done) return
done = true
onRejected(reason)
})
} catch (ex) {
if (done) return
done = true
onRejected(ex)
}
}
这里可以看到,什么情况会reject:catch到的错误会reject, 到现在为止,我们完成了内部状态机,可是介绍resolving这个promise的方法:
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise(fn) {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
}
function reject(error) {
state = REJECTED;
value = error;
}
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
doResolve(fn, resolve, reject);
}
只添加了最后一句代码: 我们re-use了doResolve()方法!
现在我们已经完成了状态机,可是我们仍然无法监听变化,我们的最终目标是实现.then(), 但是.done()这个更简单,因此,让我们先实现.done()吧! 所以我们的目标是实现promise.done(onFulfilled, onRejected), 他有以下特点
- 只调用 onFulfilled or onRejected 中的一个
- 只调用一次
var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;
function Promise(fn) {
// store state which can be PENDING, FULFILLED or REJECTED
var state = PENDING;
// store value once FULFILLED or REJECTED
var value = null;
// store sucess & failure handlers
var handlers = [];
function fulfill(result) {
state = FULFILLED;
value = result;
handlers.forEach(handle);
handlers = null;
}
function reject(error) {
state = REJECTED;
value = error;
handlers.forEach(handle);
handlers = null;
}
function resolve(result) {
try {
var then = getThen(result);
if (then) {
doResolve(then.bind(result), resolve, reject)
return
}
fulfill(result);
} catch (e) {
reject(e);
}
}
function handle(handler) {
if (state === PENDING) {
handlers.push(handler);
} else {
if (state === FULFILLED &&
typeof handler.onFulfilled === 'function') {
handler.onFulfilled(value);
}
if (state === REJECTED &&
typeof handler.onRejected === 'function') {
handler.onRejected(value);
}
}
}
this.done = function (onFulfilled, onRejected) {
// ensure we are always asynchronous
setTimeout(function () {
handle({
onFulfilled: onFulfilled,
onRejected: onRejected
});
}, 0);
}
doResolve(fn, resolve, reject);
}
this.done方法做的事情:执行了handle方法,并传入参数,其中参数就是第一个是成功时候回调函数,第二个是reject时候的回调函数。
现在让我们实现.then吧~
this.then = function (onFulfilled, onRejected) {
var self = this;
return new Promise(function (resolve, reject) {
return self.done(function (result) {
if (typeof onFulfilled === 'function') {
try {
return resolve(onFulfilled(result));
} catch (ex) {
return reject(ex);
}
} else {
return resolve(result);
}
}, function (error) {
if (typeof onRejected === 'function') {
try {
return resolve(onRejected(error));
} catch (ex) {
return reject(ex);
}
} else {
return reject(error);
}
});
});
}
- .then 和.done一样,接受两个参数,第一个是成功时候回调函数onFulfilled,第二个是失败时候回调函数onRejected。
- .then 能实现链式调用,就是因为其返回了一个promise。
最后我自己实现了一个简易版的promise,可以在控制台执行,点击这里:DiPromise