首先看一段代码
setTimeout(function(){
console.log(1)
}, 3000)
setTimeout(function(){
console.log(2)
}, 2000)
setTimeout(function(){
console.log(3)
}, 1000)
此时会输出 3 2 1, 原本我们是想输出 1 2 3 的,但是在异步的情况下,我们没办法改变异步的顺序,这是我们可以用回调函数来控制顺序,但是又有一个扎心的问题 -- 回调地狱
这时我们的promise就出场啦,代码改为:
new Promise(function(resolve, reject){
setTimeout(function(){
console.log(1)
resolve()
}, 3000)
})
.then(function(data){
return new Promise(function(resolve, reject){
setTimeout(function(){
console.log(2)
resolve()
}, 2000)
})
})
.then(function(data){
return new Promise(function(resolve, reject){
setTimeout(function () {
console.log(3)
resolve()
}, 1000)
})
})
在浏览器预览: 隔3秒输出1,再隔2秒输出2,再隔1秒输出3
这样就符合我们预期的想法了
来看看代码, 先new一下 证明我们第一步应该创建构造函数 Promise(callback) ,接着后面有 then(fn) ,于是我们可以断定 Promise.prototype.then = fn() {} , 于是根据执行情况,我们可以把执行顺序捋一捋
Promise -> 接收的函数立即执行 -> then(fn) (保存参数函数) -> resolve() -> then内部的回调函数
我们再来看看,promomise里面有resolve和reject 那就可以看出promise有两种状态,但这两种只是判断成功或者失败,所以我们还需要一个初始状态。 故: pending / fulfilled / rejected 这三种状态
接着看代码,看着注释,就可以大致明白啦
var PENDING = 'PENDING';
var FULFILLED = 'FULFILLED';
var REJECTED = 'REJECTED';
// 1: 构造函数Promise
function Promise(fn) {
// 2. 构造函数内初始 状态Pending 和 value
this.status = PENDING; // 状态是待发状态
this.value = null; // 初始值
this.deffered = []; // 下一个 要执行的Promise是谁,子promise
// 3.构造函数内调用函数(apply参数是数组,call参数是一个个,调用函数改变this指向, bind不会立即调用,只是改变this)
fn.call(this, this.resolve.bind(this), this.reject.bind(this));
}
// 4. 结束回调函数, 执行then Promise.prototype.then 是函数
// 5. then函数内不需要保存起成果或者失败的函数
Promise.prototype = {
constructor: Promise, // 改变回来原型链
then: function(onfulfilled, onrejected) {
// 保存该函数
var obj = {
onfulfilled: onfulfilled,
onrejected: onrejected
}
// 新来一个Promise对象,让其存储这些
// 并且能根据不同的Promise去then
obj.promise = new this.constructor(function(){});
// 保存起接下来的promise
// console.log(this)
// console.log(obj.promise)
// 建立上一个与下一个primise之间的关系
if(this.status === PENDING) {
this.deffered.push(obj);
}
// 保证不报错, 未来不能return自己 需要换人
return obj.promise; // 下一个then的哥们
},
// 定义成功和失败的回调函数, 改变状态, 记录数据结果, 执行后续的行为
resolve: function(data) {
this.status = FULFILLED;
this.value = data;
// 执行后续的行为
this.done();
},
reject: function(err) {
this.status = REJECTED;
this.value = err;
// 执行后续的行为
this.done();
},
// 执行后续的行为
done: function() {
// 让这些this.deffered(子promise得到执行)
this.deffered.forEach(task => this.handler(task));
},
handler: function(task) {
// 判断当前执行的状态是怎样, 调用对应的函数
var status = this.status;
var value = this.value;
var p;
switch(status) {
case FULFILLED:
p = task.onfulfilled(value);
break;
case REJECTED:
p = task.onrejected(value);
break;
}
// 如果 p是一个promise的话,我们需要让他们继续执行
// 把后续(task.promise)的deffer 交给这个p
if(p && p.constructor === Promise) {
// 是一个promise
// 把下一个作为then链接的deffer 移交给deffered
p.deffered = task.promise.deffered;
}
},
}
我们按照思路先写一个demo
var PENDING = 'PENDING'
var FULFILLED = 'FULFILLED'
var REJECTED = 'REJECTED'
// 1 构造函数Promise
function Promise(fn) {
this.status = PENDING; // 初始化状态
// 2 构造函数内调用函数
this.value = null; // 初始值
this.deffered = []; // 下一个执行的Promise执行是谁
// 3 构造函数内初始 状态Pending 和 value
fn()
}
// 4 结束回调函数后执行then -> Promise.prototype.then 是函数
// 5 then函数内部需要保存起成功或者失败的函数
Promise.protope = {
// 定义成功和失败的回调函数,改变状态,记录数据结果, 执行后续的行为
resolve: function(data) {
this.status = FULFILLED;
this.value = dat
},
constructor: Promise, // 改变回来原型链
then: function() {
}
}