同步与异步
JavaScript的执行环境是「单线程」,同步模式,即上述所说的单线程模式,一次只能执行一个任务,异步模式,可以一起执行多个任务,函数调用后不会立即返回执行的结果,如果任务A需要等待,可先执行任务B,等到任务A结果返回后再继续回调。
回调函数
常见的异步回调即setTimeout,ajax请求。可理解为(执行完)回(来)调(用)的函数。
Promise
Promise对象代表一个未完成、但预计将来会完成的操作。 它有以下三种状态: pending:初始值,不是fulfilled,也不是rejected fulfilled:代表操作成功 rejected:代表操作失败 Promise有两种状态改变的方式,既可以从pending转变为fulfilled,也可以从pending转变为rejected。一旦状态改变,就不能再变了,会一直保持这个状态。当状态发生变化,promise.then绑定的函数就会被调用。 注意:Promise一旦新建就会「立即执行」,无法取消。这也是它的缺点之一。
下面来看一个最简单的promise栗子
var promise = new Promise(function (resolve, reject) {
if (/* 异步操作成功 */) {
resolve(data);
} else {
/* 异步操作失败 */
reject(error);
}
});
Promise接受一个「函数」作为参数,该函数的两个参数分别是resolve和reject。这两个函数就是就是「回调函数」,由JavaScript引擎提供。
resolve函数的作用:在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用:在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
了解完这些基础知识后,可以直接通过代码来深入了解了。
下面就是很多栗子...
例一:Promise 三种状态
var p1 = new Promise(function(resolve,reject){
resolve(1);
});
var p2 = new Promise(function(resolve,reject){
setTimeout(function(){
resolve(2);
}, 500);
});
var p3 = new Promise(function(resolve,reject){
setTimeout(function(){
reject(3);
}, 500);
});
console.log(p1);
console.log(p2);
console.log(p3);
setTimeout(function(){
console.log(p2);
}, 1000);
setTimeout(function(){
console.log(p3);
}, 1000);
p1.then(function(value){
console.log(value);
});
p2.then(function(value){
console.log(value);
});
p3.catch(function(err){
console.log(err);
});
控制台:

解析:p1执行的是同步代码,所以直接执行,输出p1是resolved状态,值为 1。p2,p3中有异步所以会先处于pending状态。接着我们通过settimeout函数再延迟1s后输出,此时p2、p3已经执行完成,状态分别变成resolved和rejected。
第二个栗子 Promise 状态的不可逆性
var p1 = new Promise(function(resolve, reject){
resolve("success1");
resolve("success2");
});
var p2 = new Promise(function(resolve, reject){
resolve("success3");
reject("reject1");
});
p1.then(function(value){
console.log(value);
});
p2.then(function(value){
console.log(value);
});
console中的结果:

链式调用(非常重要,通过此例可以理解then返回对象)
var p = new Promise(function(resolve, reject){
resolve(1);
});
p.then(function(value){ //第一个then
console.log(value); //1
return value*2; //返回状态为resolved的promise对象,值是2
}).then(function(value){ //第二个then
console.log(value); //所以值是2
}).then(function(value){ //第三个then
console.log(value); //因为第二个then中无返回值,所以输出undefined
return Promise.resolve('resolve');
}).then(function(value){ //第四个then
console.log(value); //打印出resolve 因为第三个then返回了resolved状态的Promise对象,Promise对象的值就是这个返回值。
return Promise.reject('reject');
}).then(function(value){ //第五个then
//console.log('resolve: '+ value); //同上 因为返回的是reject 所以打印出reject
}, function(err){
console.log('reject: ' + err);
})
console的结果:

解析:Promise对象的then方法返回一个新的Promise对象,因此可以通过链式调用then方法。 then方法接收两个函数作为参数,第一个参数是Promise执行成功时的回调,第二个参数是Promise执行失败时的回调。两个函数只会有一个被调用,函数的返回值将被用作创建then返回的Promise对象。
这两个参数的返回值可以是以下三种情况中的一种:
return 一个同步的值 ,或者 undefined(当前一个then没有返回一个有效值时,默认返回undefined),then方法将返回一个resolved状态的Promise对象,Promise对象的值就是这个返回值。
return 另一个 Promise,then方法将根据这个Promise的状态和值创建一个新的Promise对象返回。
throw 一个同步异常,then方法将返回一个rejected状态的Promise, 值是该异常。
具体分析见代码中注释部分。
Promise 中的异常
var p1 = new Promise( function(resolve,reject){
foo.bar(); //最先执行,但undefined
resolve( 1 );
});
p1.then(
function(value){
console.log('p1 then value: ' + value);
},
function(err){
console.log('p1 then err: ' + err); //step1:有错所以执行err,打印出异常信息
}
).then(
function(value){
console.log('p1 then then value: '+value); //step3
},
function(err){
console.log('p1 then then err: ' + err);
}
);
var p2 = new Promise(function(resolve,reject){
resolve( 2 );
});
p2.then(
function(value){
console.log('p2 then value: ' + value); //step2:p1的异常得到处理,可以正常执行了
foo.bar();
},
function(err){
console.log('p2 then err: ' + err);
}
).then(
function(value){
console.log('p2 then then value: ' + value);
},
function(err){
console.log('p2 then then err: ' + err);
return 1;
}
).then(
function(value){
console.log('p2 then then then value: ' + value);
},
function(err){
console.log('p2 then then then err: ' + err);
}
);
console结果:

Promise.resolve()
var p1 = Promise.resolve( 1 );
var p2 = Promise.resolve( p1 );
var p3 = new Promise(function(resolve, reject){
resolve(1);
});
var p4 = new Promise(function(resolve, reject){
resolve(p1);
});
console.log(p1 === p2);
console.log(p1 === p3);
console.log(p1 === p4);
console.log(p3 === p4);
p4.then(function(value){
console.log('p4=' + value);
});
p2.then(function(value){
console.log('p2=' + value);
})
p1.then(function(value){
console.log('p1=' + value);
})
console结果:

总结!!
首先,Promise是一个对象,代表了未来某时间才会知道结果的时间,不受外界因素的印象。Promise一旦触发,其状态只能变为fulfilled或者rejected,并且已经改变不可逆转。Promise的构造函数接受一个函数作为参数,该参数函数的两个参数分别为resolve和reject,其作用分别是将Promise的状态由pending转化为fulfilled或者rejected,并且将成功或者失败的返回值传递出去。then有两个函数作为Promise状态改变时的回调函数,当Promise状态改变时接受传递来的参数并调用相应的函数。then中的回调的过程为异步操作。
catch方法是对.then(null,rejectFn)的封装(语法糖),用于指定发生错误时的回调函数。一般来说,不要再then中定义rejected状态的回调函数,应该使用catch方法代替。all和race都是竞速函数,all结束的时间取决于最慢的那个,其作为参数的Promise函数一旦有一个状态为rejected,则总的Promise的状态就为rejected;而race结束的时间取决于最快的那个,一旦最快的那个Promise状态发生改变,那个其总的Promise的状态就变成相应的状态,其余的参数Promise还是会继续进行的。
另外:关于promise then回调函数异步性这部分,我没有写出来,但是这部分很重要。可以直接去看js事件执行机制,把这一块放一起了解会更好。
代码例子参考链接:juejin.cn/post/684490…