第一步:雏形
function Promise(fn) {
var value = null,
callbacks = []; //callbacks为数组,因为可能同时有很多个回调
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
};
function resolve(value) {
callbacks.forEach(function (callback) {
callback(value);
});
}
fn(resolve);
}
let p = new Promise((resolve) => {
resolve(1111); // 此处可以改成异步执行函数,例如进行ajax请求
}).then((data) => {
console.log(data);
});
打断点,根据顺序来看
先走fn()函数——>然后理解执行resolve——->然后走源码里面的.then()函数====无打印内容
第二步:使用setTimeOut执行resolve函数
Promises/A+规范明确要求回调需要通过异步方式执行,用以保证一致可靠的执行顺序
function Promise(fn) {
var value = null,
callbacks = []; //callbacks为数组,因为可能同时有很多个回调
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
};
function resolve(value) {
setTimeout(() => {
callbacks.forEach(function (callback) {
callback(value);
});
});
}
fn(resolve);
}
做到resolve之前,then函数已经注册回调了
第三步:then函数链式调用
给then函数里面注册回调函数的同时,返回一个新的promise,这样就是链式了
this.then = function (onFulfilled) {
callbacks.push(onFulfilled);
return this;
};
还存在一个问题:如果Promise异步操作已经成功,这时,在异步操作成功之前注册的回调都会执行,但是在Promise异步操作成功这之后调用的then注册的回调就再也不会执行了,也就是永远只执行第一个fn
第四步:加入执行状态
Promises/A+规范中的2.1Promise States中明确规定了,pending可以转化为fulfilled或rejected并且只能转化一次,也就是说如果pending转化到fulfilled状态,那么就不能再转化到rejected。并且fulfilled和rejected状态只能由pending转化而来,两者之间不能互相转换。
function Promise(fn) {
var state = 'pending';
var value = null;
var 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);
}
let p = new Promise((resolve) => {
resolve(1111);
}).then((data) => {
console.log(data);
}).then((data) => {
console.log(data);
});
第五步:连通当前promise和后邻promise
- then函数里面,传了一个回调函数,这个函数被当作参数
- 执行then()方法,会返回一个promise,立即执行,重新走一遍promise构造函数,会先走fn(resolve)方法
- 下面函数就会被执行了
let count = 0;
function PromiseFn(fn) {
count++;
let recordCount = count;
let state = 'pending';
let value = null;
// 执行队列
let callbacks = [];
this.then = function(onFulfilled) {
return new PromiseFn((resolve, reject) => {
// 桥梁,将新 Promise 的 resolve 方法,放到前一个 promise 的回调对象中
handle({ onFulfilled, resolve });
});
};
function handle(callback) {
console.log(recordCount)
// 判断如果状态为未完成,则加入到队列中
if (state === 'pending') {
callbacks.push(callback);
return;
}
if (state === 'fulfilled') {
// 如果then中没有回调函数,则结束
if (!callback.onFulfilled) {
callback.resolve(value);
return;
}
// 处理回调
const ret = callback.onFulfilled(value)
// 处理下一个 promise 的resolve
callback.resolve(ret)
}
}
function resolve(newValue) {
const fn = () => {
console.log(state, recordCount, callbacks);
if(state !== 'pending') return;
state = 'fulfilled';
value = newValue
handelCb()
}
// 基于 PromiseA+ 规范
setTimeout(fn, 0)
}
function handelCb() {
while(callbacks.length) {
const fulfiledFn = callbacks.shift();
handle(fulfiledFn);
};
}
fn(resolve)
}
// 如果没有添加then函数,则只是运行了一下函数
// let p = new PromiseFn(this.test);
let p2 = new PromiseFn(this.test).then((data) => {
console.log(data)
// return 'resolve again'
}).then((data) => {
console.log(data)
});
我们常用的链式调用,是用在异步回调中,以解决”回调地狱”的问题,看如下代码,打印出来的东西跟promise不一样
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ test: 1 })
}, 1000)
}).then((data) => {
console.log('result1', data)
//dosomething
return test()
}).then((data) => {
console.log('result2', data)
})
function test(id) {
return new Promise(((resolve) => {
setTimeout(() => {
resolve({ test: 2 })
}, 5000)
}))
}
//基于第一个 Promise 模型,执行后的输出
//result1 { test: 1 }
//result2 Promise {then: ƒ}
需要给resolve函数进行判断,自动执行promise函数
function resolve(newValue){
const fn = ()=>{
if(state !== 'pending')return
if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){
const {then} = newValue
if(typeof then === 'function'){
// newValue 为新产生的 Promise,此时resolve为上个 promise 的resolve
//相当于调用了新产生 Promise 的then方法,注入了上个 promise 的resolve 为其回调
then.call(newValue,resolve)
return
}
}
state = 'fulfilled';
value = newValue
handelCb()
}
setTimeout(fn,0)
}