promise概念:
Promise对象是一个构造函数,用来生成promise实例。
Promise代表一个异步操作,有三种状态pending,resolved(异步操作成功由pending转为resolved)rejected(异步操作失败由pending转为rejected),一旦变成 resolve 或 reject两种状态后不会再更改。
resolve函数在异步操作成功后调用,将pending状态变为resolve,并将它的参数传递给回调函数;reject函数在异步操作失败时调用,将pending状态改为rejected,并将参数传递给回调函数。
注意:promise状态只能由pending=>fulfilled/rejected,一旦修改就不能再变。
Promise构造函数的原型有一个then方法,他接受两个函数作为参数,分别为resolved状态和rejected状态的回调函数,而这两个回调函数接受的参数分别是Promise实例中resolve和reject函数中的参数。
链式调用:
Promise实例在生成后会立即执行,而then方法只有在所有同步任务执行完成之后才会执行:
const promise=new Promise((resolve,reject)=>{
console.log('async task begins!')
setTimeout(()=>{
resolve('done,pending->resolved!')
},1000)
})
promise.then(value=>{
console.log(value)
})
console.log('1.please wait');
console.log('2.please wait');
console.log('3.please wait');
打印结果:
// async task begins!
// 1.please wait
// 2.please wait
// 3.please wait
// done, pending -> resolved!
解析:
Promise实例生成后立即执行,首先输出‘async task begins!’
遇到1秒后执行的setTimeout,无需等待,向下执行
then方法指定的回调函数要在所有同步任务执行完毕之后才执行,所以先输出3个‘please wait’
最后输出‘done,pending->resolved!’(then打印的是resolve返回的值)
链式调用then方法:(then返回一个新的Promise实例):
.then 方法会返回一个新的 Promise 实例,可以分两种情况来看:
- 指定返回值是新的 Promise 对象,如return new Promise(...),这种情况没啥好说的,由于返回的是 Promise,后面显然可以继续调用then方法。
- 返回值不是Promise, 如:return 1 这种情况还是会返回一个 Promise,并且这个Promise 立即执行回调 resolve(1)。所以仍然可以链式调用then方法。(注:如果没有指定return语句,相当于返回了undefined)
示例:两秒钟打一次招呼
function sayHi(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(name);
}, 2000)
})
}
sayHi('张三')
.then(name => {
console.log(`你好, ${name}`);
return sayHi('李四'); // 最终 resolved 函数中的参数将作为值传递给下一个then
})
// name 是上一个then传递出来的参数
.then(name => {
console.log(`你好, ${name}`);
return sayHi('王二麻子');
})
.then(name => {
console.log(`你好, ${name}`);
})
// 你好, 张三
// 你好, 李四
// 你好, 王二麻子
Promise可以在有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
串行执行任务:
// 0.5秒后返回input*input的计算结果:
function multiply(input) {
return new Promise(function (resolve, reject) {
log('calculating ' + input + ' x ' + input + '...');
setTimeout(resolve, 500, input * input);
});
}
// 0.5秒后返回input+input的计算结果:
function add(input) {
return new Promise(function (resolve, reject) {
log('calculating ' + input + ' + ' + input + '...');
setTimeout(resolve, 500, input + input);
});
}
var p = new Promise(function (resolve, reject) {
log('start new Promise...');
resolve(123);
});
p.then(multiply)
.then(add)
.then(multiply)
.then(add)
.then(function (result) {
log('Got value: ' + result);
});
并行执行任务:
试想一个页面聊天系统,我们需要从两个不同的URL分别获得用户的个人信息和好友列表,这两个任务是可以并行执行的,用Promise.all()实现如下:
var p1=new Promise(function(resolve,reject){
setTimeout(resolve,500,'P1');
})
var p2=new Promise(function(resolve,reject){
setTimeout(resolve,600,'P2');
})
//同时执行p1和p2,并在他们都完成后执行then:
Promise.all([p1,p2]).then(function(results){
console.log(result);//['P1','P2']
})
有些时候,多个异步任务是为了容错。比如,同时向两个URL读取用户的个人信息,只需要获得先返回的结果即可。这种情况下,用Promise.race()实现:
var p1=new Promise(function(resolve,reject){
setTimeout(resolve,500,'P1');
})
var p2=new Promise(function(resolve,reject){
setTimeout(resolve,600,'P2');
})
Promise.race([p1,p2]).then(function(results){
console.log(result);//['P1'']
})
由于p1执行较快,Promise的then()将获得结果'P1'。p2仍在继续执行,但执行结果将被丢弃。
promise的实现:
实现一个简单的Promise:
function Promise(fn){
var status='pending';
function successNotify(){
status='fulfilled';//状态变为fulfilled
toDoThen.apply(undefined,arguments);//执行回调
}
function failNotify(){
status="rejected";//状态变为rejected
toDoThen.apply(undefined,arguments);
}
function toDoThen(){
setTimeout(()=>{//保证回调是异步执行的
if(status==='fulfilled'){
for(let i=0;i<successArray.length;i++){
successArray[i].apply(undefined,arguments);//执行then里面的回调函数
}
}else if(status==='rejected'){
for(let i=0;i<failArray.length;i++){
failArray[i].apply(undefined,arguments);//执行then里面的回调函数
}
}
})
}
var successArray=[];
var failArray=[];
fn.call(undefined,successNotify,failNotify);
return{
then:function(successFn,failFn){
successArray.push(successFn);
failArray.push(failFn);
return undefined;//此处应该返回一个Promise
}
}
}