Promise 的含义
Promise是一个异步编程的解决方案,简单来讲,Promise类似一个盒子,里面保存着在未来某个时间点才会结束的事件。
三种状态:
- pending:进行中
- fulfilled :已经成功
- rejected :已经失败
状态改变,只能从pending变成fulfilled或者rejected,状态不可逆。
基本用法
一个最简单的:
new Promise((resolve,reject) =>{
if (condition){
resolve();
} else {
reject();
}
})
这是Promise的构造方法,参数是一个函数
function fn(num) {
return new Promise((resolve, reject)=> {
console.log("参入参数 num===",num);
num === 1 ? resolve():reject();
}).then(function() {
console.log('参数是---1');
}, function() {
console.log('参数不是---1');
})
}
fn(1);
console.log("主线加载完成");
参入参数 num=== 1
主线加载完成
参数是---1
通过log可以分析,Promise的构造函数是一个同步执行的,由于构造函数是同步的,then方法是在js引擎加载的时候注册的,而执行的时候是在resolve之后
异步耗时操作处理
function fn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => { //耗时操作在promise构造函数中,即同步执行
resolve(num);
}, 1000)
})
}
fn(1).then(data => { //在resolve或者reject之后 then方法注册的才能被调用
console.log(data); //1
}
);
这样我们就可以将多个异步封装成多个promise,串行,当然也可以用promise.all 或者race 并行。
实现一个简单的Promise
1.promise的构造同步,参数是一个function, 接受2个参数resolve,reject,此时这2个参数也是一个function,支持一个参数
function Promise(fn) {
function resolve(value) {
}
function reject(value) {
}
fn (resolve,reject);
}
Promise的构造应该是如此,才能符合我们上面的预期
2.promise最重要的一个方法是then,我们需要实现then方法,then方法接受的也是2个function,一个是成功的回调,一个是失败的回调
function Promise(fn) {
var value = null, succallbacks = [], failcallbacks = [];
this.then = function (fulfilled, rejected) {
succallbacks.push(fulfilled);
failcallbacks.push(rejected);
}
function resolve(value) {
succallbacks.forEach((callback) => {
callback(value);
})
}
function reject(value) {
failcallbacks.forEach((callback) => {
callback(value);
})
}
fn(resolve, reject);
}
function fn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num); //1 去掉time 则不会执行
}, 1000)
})
}
fn(1).then(data => {
console.log(data);
}
);
then方法在js引擎执行的时候注册,注册2个回调,通过代码可以看出,then注册一定是在 resolve或reject之前,
上面一个简单的promise就完成了,然而,then方法一定要在resolve之前,如果 promise是同步的(将settimeout去掉),
则在resolve的时候,succallbacks为null,所以需要加一个time保证then在resolve之前,
也就是将resolve或者reject 放到队列的末端,参考(macro task 与 micro task) js 的eventloop;
同时我们知道promise是可以链式调用,所以then方法返回的还是一个promise
3.加如链式调用,以及延时
function Promise(fn) {
var succallbacks = [], failcallbacks = [];
this.then = function (fulfilled, rejected) {
succallbacks.push(fulfilled);
failcallbacks.push(rejected);
return this; //加入链式调用,注意bluebird 或者原生promise中是返回一个新的promise,这样只是为了方便,
}
function resolve(value) {
setTimeout(function() { //加入延时
succallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
function reject(value) {
setTimeout(function() {
failcallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
fn(resolve, reject);
}
function fn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => { //此时去掉time 也能执行
resolve(num);
}, 1000)
})
}
fn(1).then(data => { //可以链式调用
console.log(data);
}
).then(data=>{
console.log(data)
});
这样一个简单的promise就完成了,然后给他添加一个 方法 api 就可以了,此时这个promise在一些特定的情况下是不合理的。不了解 js的eventLoop 建议先看 js的eventLoop。再js的事件循环中,timeout是放在Macor task中的,Promise是放在
Micor task 中的,意思是promise会先执行。
4.并行一个timeout 为0 的 定时器
setTimeout(function () {
console.log("time");
},0)
function Promise(fn) {
var succallbacks = [], failcallbacks = [];
this.then = function (fulfilled, rejected) {
succallbacks.push(fulfilled);
failcallbacks.push(rejected);
return this;
}
function resolve(value) {
setTimeout(function() {
succallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
function reject(value) {
setTimeout(function() {
failcallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
fn(resolve, reject);
}
function fn(num) {
return new Promise((resolve, reject) => {
// setTimeout(() => {
resolve(num);
// }, 1000)
})
}
fn(1).then(data => {
console.log(data);
}
);
输出
time
1
由于是同步的promise,理论上应该是promise中的现执行,再去执行time中的,所以说基于同步的实现还是有问题;
基于浏览器可以用 MutationObserver 这个api 去保证 promise 时序问题
在node 中可以将promise中的time改成 process.nextTick
function resolve(value) {
process.nextTick(function () {
succallbacks.forEach((callback) => {
callback(value);
})
});
}
function reject(value) {
process.nextTick(function () {
failcallbacks.forEach((callback) => {
callback(value);
})
});
}
这样输出就是
1
time
加入状态
function Promise(fn) {
var data = undefined, reason = undefined;
var succallbacks = [];
var failcallbacks = [];
var status = "pending"; // 加入promise 3种状态
this.then = function (fulfilled, rejected) {
if (status === "pending") {
succallbacks.push(fulfilled);
failcallbacks.push(rejected);
return this; //加入链式调用,注意bluebird 或者原生promise中是返回一个新的promise,这样只是为了方便,
} else if (status == "fulfilled") {
fulfilled(data);
} else {
rejected(reason);
}
}
function resolve(value) {
setTimeout(function () { //加入延时
status = "fulfilled";
data = value;
succallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
function reject(value) {
setTimeout(function () {
status = "rejected";
reason = value;
failcallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
fn(resolve, reject);
}
function fn(num) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num);
}, 1000)
})
}
fn(1).then(data => {
console.log(data);
}
);
修改then方法返回一个新的Promise,能保证 then(f1).then(f2)
function Promise(fn) {
var data = undefined, reason = undefined;
var succallbacks = [];
var failcallbacks = [];
var status = "pending";
this.then = function (fulfilled, rejected) {
return new Promise(function(resolve,reject) { //返回一个新的promise
function suc(value) { //成功
var ret = typeof fulfilled === 'function' && fulfilled(value) || value;
if( ret && typeof ret ['then'] == 'function'){ //判断 then中的 返回的是否是promise对象,如果是注册then方法
ret.then(function(value){
resolve(value);
});
} else {
resolve(ret);
}
}
function errback(reason) { //失败
reason = typeof rejected === 'function' && rejected(reason) || reason;
reject(reason);
}
if (status === 'pending') {
succallbacks.push(suc);
failcallbacks.push(errback);
} else if(status === 'fulfilled'){
suc(data);
} else {
errback(reason);
}
})
}
function resolve(value) {
setTimeout(function () { //加入延时
status = "fulfilled";
data = value;
succallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
function reject(value) {
setTimeout(function () {
status = "rejected";
reason = value;
failcallbacks.forEach((callback) => {
callback(value);
})
}, 0)
}
fn(resolve, reject);
}
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(1);
}, 1000)
}) ;
p.then(data =>{
console.log(data);
return new Promise((resolve,reject) => { //then 方法返回的是一个promise对象,故执行 promise中的then注册该结果,在resolve
setTimeout(() => { resolve(2);},1000)})
}).then(data =>{
console.log(data);
})
这样一个比较完整的promise就实现了。只需要实现常用的 all,race 等api即可