由于JavaScript是一本单线程语言 (这个主要看场景,因为浏览器是多线程的,或者用WebWorker也可以多线程,但是由于JS在DOM上渲染的时候为了不冲突只能单线程的形式),那么在执行的时候,就容易出现前面的等待执行代码阻塞了后面的代码,严重影响了性能。对于这种情况,异步就是一种使用非阻塞的模式,将原来延迟的代码先放到异步队列,先将所有同步代码全部执行完成,然后通过事件循环(Event Loop)来调用需要被执行异步代码。
Promise就是ES6提出的一种异步解决方案。
可以去学习ES7的新异步解决方案——async/await,实质由promise和Generator写成以同步代码形式书写的语法糖
了解Promise的生命周期:
- 进行中(pending):操作还未开始
- 已处理(settled):异步操作执行结束
- 结束后进入以下两种状态中的一种:
1:成功(Fulfilled):操作成功
2:失败(Rejected):由于程序出错或别的原因,未能成功
- 结束后进入以下两种状态中的一种:
所有的Promise都有then方法,该方法有两个可选参数,前者为成功时调用的函数,后者是失败调用的函数
let promise = new Promise((resolve, reject) => {
resolve('success');
reject('error');
});
//两个参数
promise.then(function (data) {
console.log(data); //返回成功的数据
}, function (err) {
console.log(err); //返回失败的数据
})
//只有成功参数
promise.then(function (data) {
console.log(data); //返回成功的数据
})
//只有失败参数,使用null替代前一个参数
promise.then(null,function (error) {
console.log(error); //返回失败的数据
})
Promise还有catch()方法接受失败的数据,更加清晰的表示,then来处理成功的,catch来处理失败的
promise.catch(function (error) {
console.log(error); //返回失败的数据
})
相当于没有成功参数表示:
promise.then(null,function (error) {
console.log(error); //返回失败的数据
})
创建未完成的Promise可以根据Promise构造函数来创建新的Promise,只有一个函数作为参数,而该函数有两个参数,分别为resolve()函数和reject()函数,成功执行resolve函数,失败执行reject()函数
let promise = new Promise((resolve, reject) => {
resolve('success');
reject('error');
});
创建已处理的Promise
let success= Promise.resolve('success');
success.then(function (data) {
console.log(data); //返回成功的数据
})
let fail= Promise.reject('error');
fail.catch(function (err) {
console.log(err); //返回失败的数据
})
Promise的resolve()和reject()方法都可以接受非Promise的Thenable对象作为参数
let thenable = {
then: function(resolve, reject) {
resolve('success');
}
}
let promise = Promise.resolve(thenable);
promise.then(function(data) {
console.log(data);
})
执行器错误:当执行器内部中抛出错误时,失败处理程序会被调用
let promise = new Promise((resolve, reject) => {
throw new Error('error');
});
promise.then((error) => {
console.log(error.message);
})
串行Promise:当前者被解决了,后者才会处理程序
promise.then((success) => {
console.log(success);
}).then(() => {
console.log('hello');
})
promise.then((success) => {
console.log(success);
}).catch((err) => {
console.log(err);
})
封装一个promise异步的ajax请求
var getJSON = function(url) {
var promise = new Promise((resolve, reject) => {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open('GET',url);
xmlHttp.onreadystatechange = handler;
xmlHttp.responseType = 'json';
xmlHttp.setRequestHeader("Accept","application/json");
xmlHttp.send();
function handler() {
if(this.readyState === this.DONE) {
if(this.status === 200) {
resolve(this.response);
} else {
reject(this);
}
}
}
});
return promise;
};
getJSON('/get.json').then(function(data) {
console.log(data);
}, function(err){
console.log(err);
})
了解了如何使用之后,我们不妨来看下Promise的源码!!!
function Promise(fn) {
var state = 'pending';
var value;
var deferred = null;
function resolve(newValue) {
if(newValue && typeof newValue.then === 'function') {
newValue.then(resolve, reject);
return;
}
state = 'resolved';
value = newValue;
if(deferred) {
handle(deferred);
}
}
function reject(reason) {
state = 'rejected';
value = reason;
if(deferred) {
handle(deferred);
}
}
function handle(handler) {
if(state === 'pending') {
deferred = handler;
return;
}
var handlerCallback;
if(state === 'resolved') {
handlerCallback = handler.onResolved;
} else {
handlerCallback = handler.onRejected;
}
if(!handlerCallback) {
if(state === 'resolved') {
handler.resolve(value);
} else {
handler.reject(value);
}
return;
}
var ret = handlerCallback(value);
handler.resolve(ret);
}
this.then = function(onResolved, onRejected) {
return new Promise(function(resolve, reject) {
handle({
onResolved: onResolved,
onRejected: onRejected,
resolve: resolve,
reject: reject
});
});
};
fn(resolve, reject);
}
一个一个的看:
- 首先是定义了3个局部变量,除了第一个state,可以看出是我们之前说的pending,resolved和rejected3个状态,别的两个都暂时不知道干啥,继续看…
var state = 'pending';
var value;
var deferred = null;
- 熟悉的两个单词来了——resolve和reject,两个方法都是接受一个参数,由于这里调用了then和handle,所以也先简单看下handle和then,发现有递归的模样,而且确实满足递归的要素,所以做好准备
- 递归的三大要素
- 明确你这个函数想要干什么
- 寻找递归结束条件
- 找出函数的等价关系式
- 递归的三大要素
function resolve(newValue) {
// 先判断传入的值是否存在以及后面是否存在then方法,如果成立继续调用then方法,否则改变当前状态,将新值赋给旧值
if (newValue && typeof newValue.then === 'function') {
newValue.then(resolve, reject);
return;
}
state = 'resolved';
value = newValue;
if (deferred) {
handle(deferred);
}
}
function reject(reason) {
state = 'rejected';
value = reason;
if (deferred) {
handle(deferred);
}
}
待续。。。