痛下心来整理一下Promise
Promise会用,说原理吧,好像懂好像有不懂,还是记录自己整理的思路吧,算是面试复习
以下场景是我们最常用的一个异步请求
function getUserId() {
return new Promise(function (resolve) {
//异步请求
http.get(url, function (results) {
resolve(results.id);
});
});
}
getUserId().then(function (id) {
//一些处理
});
分析特点
1、创建Promise
实例时传入的函数会被赋予一个函数类型的参数,即resolve
,它接收一个参数value,代表异步操作返回的结果,当一步操作执行成功后,用户会调用resolve
方法;
2、调用then
方法,参数也是一个(暂且只考虑成功)方法,该方法的参数是我们想要的结果;
resolve 的的参数,是 then 参数函数的参数,这样我们可以考虑把 then 的参数函数在promise 中做暂存,然后再resolve 中取出执行,考虑是异步,且我们了解 then 可以多次链式调用,返回的是一个 Promise,然后我们知道 promise 的状态一旦确定就不会在逆转,那么我们考虑可能是这样的情况
function Promise (fn) {
let value = null;
const callbacks = [];
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
return this;
};
function resolve (value) {
setTimeout(function () {
callbacks.forEach(function (callback) {
callback(value);
});
}, 0)
}
fn(resolve);
}
这样好像还存在一个问题,如果Promise
异步操作已经成功,这时,在异步操作成功之前注册的回调都会执行,但是在Promise
异步操作成功这之后调用的then
注册的回调就再也不会执行了,这显然不是我们想要的。
我们可以在 then 中做一个判断如果是 pending 则执行注册逻辑,否则直接执行回调,是不是可以解决这个问题
加入状态
function Promise (fn) {
let state = 'pending'
let value = null
const callbacks = []
this.then = function (onFulfilled) {
if (state === 'pending') {
callbacks.push(onFulfilled);
return this;
}
onFulfilled(value);
return this;
};
function resolve (newValue) {
value = newValue;
state = 'fulfilled';
setTimeout(function () {
callbacks.forEach(function (callback) {
callback(value);
});
}, 0);
}
fn(resolve);
}
链式Promise
链式Promise
是指在当前promise
达到fulfilled
状态后,即开始进行下一个promise
(后邻promise
)。那么我们如何衔接当前promise
和后邻promise
呢?
我们可以先在 then 返回一个 promise 看看效果
function Promise (fn) {
let state = 'pending'
let value = null
const callbacks = []
this.then = function (onFulfilled) {
return new Promise(function (resolve) {
handle({
onFulfilled: onFulfilled || null,
resolve: resolve
});
});
};
function handle (callback) {
if (state === 'pending') {
callbacks.push(callback);
return;
}
//如果then中没有传递任何东西
if (!callback.onFulfilled) {
callback.resolve(value);
return;
}
var ret = callback.onFulfilled(value);
callback.resolve(ret);
}
function resolve (newValue) {
if (newValue && (typeof newValue === 'object'
|| typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
then.call(newValue, resolve);
return;
}
}
state = 'fulfilled';
value = newValue;
setTimeout(function () {
callbacks.forEach(function (callback) {
handle(callback);
});
}, 0);
}
fn(resolve);
}
注意
handle
方法是promise
内部的方法。then
方法传入的形参onFulfilled
以及创建新Promise
实例时传入的resolve
均被push
到当前promise
的callbacks
队列中,这是衔接当前promise
和后邻promise
的关键所在(这里一定要好好的分析下handle的作用)。
示例
getUserId()
.then(getUserJobById)
.then(function (job) {
// 对job的处理
});
function getUserJobById (id) {
return new Promise(function (resolve) {
http.get(baseUrl + id, function (job) {
resolve(job);
});
});
}
这里比较绕,我大概梳理一下,首先 getUserId 直接执行并返回了 promise对象(Ap)。在Ap then 的过程把 getUserJobById 作为回调注册,然后 Ap 的 reslove 执行,即 getUserJobById 执行,这样 Ap resolve 的 value 作为入参 传入 getUserJobById 生产返回新的 promise(Bp),接下来是就是操作 Bp 的的过程了。
then 的过程是返回了新的 promise ,至于如何保证顺序我觉得是 父级回调的注册执行生成子级 promise,行成了闭包。
接下来我们在加上 reject 的状态管理
function Promise (fn) {
let state = 'pending';
let value = null;
const callbacks = [];
this.then = function (onFulfilled, onRejected) {
return new Promise(function (resolve, reject) {
handle({
onFulfilled: onFulfilled || null,
onRejected: onRejected || null,
resolve: resolve,
reject: reject,
});
});
};
function handle (callback) {
if (state === 'pending') {
callbacks.push(callback);
return;
}
let cb = state === 'fulfilled' ? callback.onFulfilled : callback.onRejected,
if (cb === null) {
cb = state === 'fulfilled' ? callback.resolve : callback.reject;
cb(value);
return;
}
let ret = cb(value);
callback.resolve(ret);
}
function resolve (newValue) {
if ( newValue &&
(typeof newValue === 'object' || typeof newValue === 'function')) {
var then = newValue.then;
if (typeof then === 'function') {
then.call(newValue, resolve, reject);
return;
}
}
state = 'fulfilled';
value = newValue;
execute();
}
function reject (reason) {
state = 'rejected';
value = reason;
execute();
}
function execute () {
setTimeout(function () {
callbacks.forEach(function (callback) {
handle(callback);
});
}, 0);
}
fn(resolve, reject);
}
转载自:https://juejin.cn/post/7208329902373814309