1 pending 等待态
2 fulfilled 已成功
3 rejected 已失败
只有异步操做的结果,能够决定当前是哪个状态,任何外部的操做都没法改变这个状态
复制代码
在JavaScript的世界中,全部代码都是单线程执行的;因为这个"缺陷",以致于JavaScript的全部网络操做、浏览器事件等都必须异步执行; 异步意味着在将来的某个时刻获得结果; 在promise以前,咱们写的ajax应用(前一个函数的执行结果做为下一个函数的参数),就面临着大量的回调函数的窘境,回调函数的多层嵌套成为咱们绕不开的噩梦;es6
ES6规定,Promise对象是一个构造函数,用来生成Promise实例ajax
Promise接收一个函数(executor:执行者)做为参数,该函数有两个参数:编程
1 resolve(Function) -> 将Promise对象的状态从"未完成pending"变为"成功resolved",在异步操做成时调用,并将异步操做的结果,做为参数传递出去(供then方法的成功回调接收)json
2 reject(Function) -> 将Promise对象的状态从"未完成pending"变为"rejected",在异步失败时调用,并将异步操做的错误或失败的缘由,做为参数传递出去(供then方法的失败回调接收)数组
const promise = new Promise(function(resolve, reject){
if(/*异步操做成*/){
resolve(value); // 成功时调用它会将Promise的状态从"pending"变为"resolved"
}else{
reject(err); // 失败时调用它会将Promise的状态从"pending"变为"rejected"
}
});
复制代码
Promise实例生成后,能够用then方法分别指定resolved(参数是成功的结果)状态和rejected(参数是失败的缘由)状态的回调函数; 即then方法接收两个回调函数做为参数:promise
1 第一个函数,是Promise对象的状态变为resolved时调用(接收成功的结果做为参数)浏览器
2 第二个函数,是Promise对象的状态变为rejected时调用可选bash
promise.then((value)=>{
// value是成功的结果
}, (err)=>{
// 失败的缘由
});
// 示例: demo/1.建立promise实例.js
复制代码
const promise = new Promise((resolve, reject)=>{
console.log('Promise');
resolve();
});
promise.then((value)=>{
console.log('Success')
});
console.log('Hi!');
// => Promie Hi! Success
// 上面代码,Promise新建后会当即执行,因此会先输出'Promise', 而后咱们为then方法指定了回调函数,由于then方法是异步的,因此它会等待同步代码都执行完以后才执行,因此接下来输出的是'Hi!',当主栈中的同步代码执行完毕以后, 开始执行异步任务(then是个微任务), 所以promise状态改变后成功的回调输出'Success'
// 示例: demo/2.promise建立会当即执行
复制代码
// 异步加载图片示例
function loadImageAsync(url){
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = function(){
resolve(image); // 若是图片加载成则调用该方法, 将promise的状态改成resolved
};
image.onerror = function(){
reject('建立失败'); // 若是图片加载失败, 则调用该方法, 将promise的状态改成rejected
};
image.src = url;
});
}
loadImageAsync('./timg2.jpg').then((value)=>{
// 若是状态变为成功态,则将图片添加到页面
console.log(value);
document.querySelector('body').appendChild(value);
}, (err)=>{
// 状态变为失败态,则将提示错误
console.log('Error:', err);
});
// 示例: demo/3.异步加载图片
复制代码
// Promise对象实现Ajax示例
let getJSON = function(){
return new Promise((resolve, reject)=>{
$.getJSON('./test.json').then((value)=>{
console.log(value);
resolve(value)
}, (err)=>{
// console.log('失败回调:',err)
reject(err);
});
});
};
getJSON().then((data)=>{
console.log(data)
},(err)=>{
console.log('My-Error:', err);
});
// 若是调用resolve函数和reject函数时带有参数,那么它们的参数被被传递给回调函数(then的成功回调和失败回调)
复制代码
new Promise((resolve,reject)=>{
throw new Error('错误');
}).then((data)=>{
console.log(data)
},(err) => {
console.log('Err ', err); //Err Error: 错误....
return err;
})
复制代码
resolve函数的参数除了正常的值之外,还能是另外一个Promise实例网络
const p1 = new Promise(function (resolve, reject) {
// ...
});
const p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})
上面代码中,p1和p2都是 Promise 的实例,可是p2的resolve方法将p1做为参数,即一个异步操做的结果是返回另外一个异步操做
注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。若是p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;若是p1的状态已是resolved或者rejected,那么p2的回调函数将会马上执行
复制代码
const p1 = new Promise(function (resolve, reject) {
setTimeout(() => reject(new Error('fail')), 3000)
})
const p2 = new Promise(function (resolve, reject) {
setTimeout(() => resolve(p1), 1000)
})
p2
.then(result => console.log(result))
.catch(error => console.log(error))
// Error: fail
//上面代码中,p1是一个 Promise,3 秒以后变为rejected。p2的状态在 1 秒以后改变,resolve方法返回的是p1。因为p2返回的是另外一个 Promise,致使p2本身的状态无效了,由p1的状态决定p2的状态。因此,后面的then语句都变成针对后者(p1)。又过了 2 秒,p1变为rejected,致使触发catch方法指定的回调函数
// 一言以蔽之: "传递的promise都要执行,直到执行后的结果是普通值(非promise)或抛出异常, 再传递到下一个then中, 执行对应的回调"
复制代码
new Promise((resolve,reject)=>{
resolve('success');
console.log('Hello')
}).then(data=>{
console.log(data)
});
// => 'Hello' 'success'
// 通常来讲, 调用resolve和reject之后,Promise的使命就完成了,后续的操做应该放到then方法里面,而不该该直接写在resolve和reject的后面; 因此,最好在它们前面加上return语句;
复制代码
new Promise((resolve,reject)=>{
return resolve('success');
console.log('Hello')
}).then(data=>{
console.log(data)
});
// 此时只输出success
复制代码
一、 then链式调用, 第一个then回调的返回结果会做为第二个then回调的参数app
new Promise((resolve,reject)=>{
return resolve('success'); // 将状态改变为成功态
}).then((data)=>{
console.log(data) // success
return '成功' + data;
},(err) => {
console.log('Err', err);
return err;
}).then((data) => {
console.log(data) // 成功success
}, (err) =>{
console.log("Fail", err)
});
// 上面代码使用then方法, 依次执行两个then的回调函数. 第一个回调完成后,会将返回结果做为参数,传入到第二个回调函数;
复制代码
二、 then的reject回调函数中返回错误,会继续传递到下一个then的成功(resolve)回调 切记
new Promise((resolve,reject)=>{
return reject('fail'); // 执行失败回调
}).then((data)=>{
console.log(data);
return '成功';
},(err) => {
console.log('Err', err); // Err fail
return err;
}).then((data) => {
console.log('hello',data) // hello fail
}, (err) =>{
console.log("Fail", err)
});
复制代码
三、then()会多层传递
new Promise((resolve,reject)=>{
resolve('ABC');
}).then().then().then((data)=>{
console.log(data)
},(err)=>{
console.log(err)
});
// 输出 "ABC"
复制代码
new Promise((resolve,reject)=>{
throw new Error('错误');
}).catch((err)=>{
console.log('Error:', err); // Error: Error: 错误
});
等同于
new Promise((resolve,reject)=>{
throw new Error('错误');
}).then(null, (err)=>{
console.log('Error:', err); // Error: Error: 错误
});
复制代码
new Promise((resolve,reject)=>{
throw new Error('错误');
}).catch((err)=>{
console.log('Error:', err); // Error: Error: 错误
});
复制代码
new Promise((resolve,reject)=>{
resolve('ABC'); // 将状态改变为成功态
}).then((data)=>{
console.log(test) // 在then的成功回调中执行,输出一个未定义的变量,此时会抛出错误
},(err) => {
console.log('Err ', err);
}).catch((err)=>{
console.log('Catch ', err); // 在这里被捕获 => Catch ReferenceError: test is not defined ....
});
复制代码
new Promise((resolve,reject)=>{
resolve('ABC');
throw new Error('错误');
}).then((data)=>{
console.log(data) // 输出ABC
},(err) => {
console.log('Err ', err);
}).catch((err)=>{
console.log('Catch ', err);
});
// 上面代码执行输出了"ABC",说明在状态改变后抛出错误,对结果无影响
// 上面代码中,Promise在resolve语句后面抛出错误,没有被捕获,至关于没有抛出错误;由于Promise的状态一旦改变,就永远保持该状态,不会再变了;
复制代码
new Promise((resolve,reject)=>{
reject('ABC');
}).catch((err)=>{
console.log('Catch ', err);
});
// 输出: "Catch ABC"
等同于
new Promise((resolve,reject)=>{
try{
console.log('a')
throw new Error('test');
}catch(e){
console.log('b')
reject(e)
}
}).catch((err)=>{
console.log('Catch ', err);
});
// => a b Catch Error: test
复制代码
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(100);
}, 2000);
});
let p2 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve('Hello');
}, 3000);
});
let p3 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(true);
}, 2000);
});
Promise.all([p1, p2, p3]).then((data)=>{
console.log(data); // 等数组中的promise实例都执行完成后,才将状态改变为fulfilled => [ 100, 'Hello', true ]
}, (err)=>{
console.log(err)
});
// => [ 100, 'Hello', true ]
复制代码
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(100);
}, 2000);
});
let p2 = new Promise((resolve,reject)=>{
throw Error('错误啦');
});
let p3 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(true);
}, 2000);
});
Promise.all([p1, p2, p3]).then((data)=>{
console.log(data)
}).catch(err=>{
console.log('Promise.all Error:', err)
});
// => Promise.all Error: Error: 错误啦....
// 在p2执行时抛出了异常,那么整个Promise.all()执行状态被改变为rejected, 错误被catch捕获
复制代码
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(100);
}, 2000);
});
let p2 = new Promise((resolve,reject)=>{
throw Error('错误啦');
}).catch(err=>{
console.log('p2.Error', err); // p2.Error Error: 错误啦
});
Promise.all([p1, p2]).then((data)=>{
console.log(data); // [ 100, undefined ]
}).catch(err=>{
console.log('Promise.all Error:', err)
});
// 上例中,p1在2秒后状态改变为resolve; p2执行时抛出错误,此时p2的状态改变为rejected, 由于它有本身的catch,在执行完catch方法后,状态也变成了resolve, 所以会调用then的指定的回调, 而不会调用catch方法指定的回调函数; 因此,最终打印出: [ 100, undefined ]
复制代码
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(100);
}, 2000);
});
let p3 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(true);
}, 2500);
});
Promise.race([p1, p3]).then((data)=>{
console.log(data) // 100
}).catch(err=>{
console.log('Promise.all Error:', err)
});
复制代码
let p1 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(100);
}, 2000);
});
let p3 = new Promise((resolve,reject)=>{
setTimeout(() => {
resolve(true);
}, 2500);
});
Promise.race([p1, p3, 10086]).then((data)=>{
console.log(data) // 10086
}).catch(err=>{
console.log('Promise.all Error:', err)
});
// => 10086; 由于咱们最终要使用的是普通值或普通对象,而非promsie,全部的实例最终的目的都是要返回普通值, 所以遇到普通值会立马返回
复制代码
Promise.resolve()可用于将现有对象转换为Promise对象
Promise.resolve('foo')
等价于new Promise(resolve=>resolve('foo'))
Promise.resolve方法的参数分红四种状况: 一、参数是一个 Promise 实例
二、参数是一个thenable对象(thenable对象指的是具备then方法的对象)
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
// thenable对象的then方法执行后,对象p1的状态就变为resolved,从而当即执行最后那个then方法指定的回调函数,输出 42
复制代码
三、参数不是具备then方法的对象,或根本就不是对象
const p = Promise.resolve('Hello');
p.then(function (s){
console.log(s)
});
// Hello
// 上面代码生成一个新的 Promise 对象的实例p。因为字符串Hello不属于异步操做(判断方法是字符串对象不具备 then 方法),返回 Promise 实例的状态从一辈子成就是resolved,因此回调函数会当即执行。Promise.resolve方法的参数,会同时传给回调函数
复制代码
四、不带有任何参数
const p = Promise.reject('出错了');
// 等同于
const p = new Promise((resolve, reject) => reject('出错了'))
p.then(null, function (s) {
console.log(s)
});
// 出错了
//上面代码生成一个Promise对象的实例p,状态为rejected,回调函数会当即执行
复制代码
const thenable = {
then(resolve, reject) {
reject('出错了');
}
};
Promise.reject(thenable)
.catch(e => {
console.log(e === thenable)
})
// true
// 上面代码中,Promise.reject方法的参数是一个thenable对象,执行之后,后面catch方法的参数不是reject抛出的"出错了"这个字符串,而是thenable对象
复制代码