Promise是JS中进行异步编程的新解决方案,Promise本质是构造函数。
- 优点
可以对异步任务进行封装,可以获取异步任务中的结果值
支持链式调用,可以解决回调地狱问题
指定回调函数更加灵活
异步编程方式
- fs 文件操作
require('fs').readFile('file.txt', 'utf8', function (err, data) {
if (err) {
return console.log(err);
}
console.log(data);
});
-
数据库操作
-
AJAX
$.get('http://www.baidu.com', function (data) {
console.log(data);
});
- 定时器
settimeout(function () {
console.log('Hello');
}, 3000);
Promise
Promise的参数excutor是一个有两个参数的函数(resolve reject)
then函数有2个参数,第一个成功的回调函数,第二个失败的回调函数
- 对异步任务的封装
new Promise(function (resolve, reject) {
// 异步操作
setTimeout(function () {
let a = 10;
if(a > 5){
resolve();
}else{
reject();
}
}, 3000);
}).then(function () {
console.log('成功了');
},function(){
console.log('失败了');
});
- 获取异步任务中的数据
new Promise(function (resolve, reject) {
// 异步操作
setTimeout(function () {
let a = 10;
if(a > 5){
resolve(a);
}else{
reject('值太大');
}
}, 3000);
}).then(function (data) {
console.log(data);
},function(err){
console.log(err);
}
promise风格util.promisify(original)
const util = require('util')
const fs = require('fs')
let mineReadFileAsync = util.promisify(fs.readFile)
mineReadFileAsync('test.txt', 'utf8').then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
Promise执行流程
未命名文件(1).jpgPromise的属性
-
Promise的状态改变
PromiseStatus
-
pending
等待态:pending状态的promise既不会被执行resolve()
也不会被reject()
-
fulfilled
成功态: 执行resolve()
会改变状态为 fulfilled 状态 -
rejected
失败态:执行reject()
会改变状态为 rejected 状态
Promise的状态只有2种改变,而且只能改变一次。1. pending 变为 fulfilled 2. pending 变为 rejected。
-
-
Promise对象的值
PromiseResult
PromiseResult保存异步任务 成功 | 失败 的结果值
Promise API
- Promise构造函数
Promise(excutor)
excutor是执行器
Promise构造函数传递的执行器函数内部是同步调用
的,该函数不会进入队列
new Promise((resolve, reject) => {
// 同步调用
console.log('1')
})
console.log('2')
// 执行结果: 1 2
-
Promise.prototype.then
返回一个新的Promise对象 -
Promise.prototype.catch
只能指定失败的回调,不能指定成功的回调
catch函数做了独立的封装,内部也是调用Promise.prototype.then
实现的 -
Promise.resolve
返回一个成功的promise对象
,作用是为了快速得到一个promise对象
4.1 如果参数传递是一个非Promise对象
,则返回的结果为成功的promise对象
Promise.resolve(1).then(function(value){
console.log(value)// 1
})
4.2 如果参数传递是一个Promise对象
,这个参数对象的结果决定了Promise的结果是失败还是成功
let promise1 = new Promise((resolve,reject)=>{
resolve('OK')// 返回成功
});
// promise2 是一个成功的promise对象,promise2的结果由 promise1的成功与失败结果 决定
let promise2 = Promise.resolve(promise1);
-
Promise.reject
快速返回一个失败的promise对象,无论传入什么参数,他的结果始终都是失败的
-
Promise.all
参数是一个promise对象的【数组】,返回一个新的promise对象
等待所有promise对象都成功才会成功,只要有一个promise对象返回失败
,整个数组的promise都会失败 -
Promise.race
参数传递【数组】
返回一个新的promise,第一个
完成的promise的结果状态就是最终的结果状态
常见问题
-
如何修改promise的状态
1.1 调用resolve函数,将promise的状态从pending变为fulfilled
1.2 调用reject函数,将promise的状态从pending变为rejected
1.3 抛出错误 throw ‘Error’,将promise的状态从pending变为rejected -
指定多个then回调函数,这些回调都会调用吗
当Promise状态改变的时候,对应的回调函数都会调用
new Promise((resolve, reject) => {
resolve('OK')
}).then(function (value) {
console.log(value)//这里会执行
}).then(function (value) {
console.log(value)// 这里会执行
})
- 改变promise状态和指定回调函数谁先谁后?
都有可能,正常情况先指定回调再改变状态,但也可以先改变状态再指定回调。
3.1 先改变状态再指定回调,then执行时就会调用回调函数
let promise = new Promise((resolve, reject) => {
// 同步任务
resolve('OK')
})
promise.then(function (value) {
console.log(value)
})
3.2 先指定回调再改变状态,状态改变后才会执行then中的回调函数
let promise = new Promise((resolve, reject) => {
// 异步任务
settimeout(() => {
resolve('OK')
}, 1000)
})
promise.then(function (value) {
console.log(value)
})
- then函数返回新的promise对象的状态由什么来决定?
由then()指定的回电函数执行的结果决定。
(1) 回调函数抛出错误throw,结果是失败状态
(2) 回调函数返回结果是非Promise类型对象,结果是成功状态
(3) 回调函数返回的是Promise对象,结果就是这个返回的Promise对象的状态
let promise = new Promise((resolve, reject) => {
resolve('OK')
})
let result = promise.then(function (value) {
throw new Error('Error')
}).then(value =>{
// 1. 抛出错误
// throw '出错';
// 2. 返回非Promise对象
// return 100;// result的状态为成功,值为100
// 3. 返回Promise对象
return new Promise((resolve,reject)=>{
// resolve(200); // result的状态为成功,值为200
reject('出错了'); // result的状态为失败,值为出错了
})
},reason =>{
console.log(reason)
})
- 如何串联多个任务?链式调用
new Promise((resolve, reject) => {
resolve('OK')
}).then(function (value) {
return new Promise((resolve, reject) => {
resolve('success')
})
}).then(function (value) {
// value 的结果由第一个then的结果决定
console.log(value)// value is success
}).then(function (value) {
// value 的结果由第二个then的结果决定,第二个then没有写,则返回值就是undefined,是非promise类型.
// 所以第二个then的结果是成功状态的Promise,值是undefined
console.log(value)// value is undefined
})
-
异常穿透 catch
在最后指定失败的回调,前面任何操作出异常,都会穿透到最后一个失败的回调 -
如何中断promise链
在中间中断,不会调用后面的回调函数;只有返回一个pending状态的promise对象,才会中断执行后面的回调函数
new Promise((resolve, reject) => {
resolve('OK')
}).then(function (value) {
return new Promise(()=>{}); // 中断promise链
}).then(function (value) {
console.log(value)// 不会执行,只有第一个then的结果状态改变才会执行
}).then(function (value) {
console.log(value)// 不会执行
})
模拟实现Promise
// 自定义封装
function Promise(excutor) {
// 添加属性
this.PromiseStatus = 'pending';
this.PromiseResult = null;
// 保存实例对象的this的值
const self = this;
// 保存then的回调函数的参数,便于异步任务改变状态调用回调
this.callbacks = [];// 类型为对象时,指定多个then回调,会覆盖,无法实现链式调用,需要使用数组
// 改变状态、设置对象结果值
function resolve(data) {
// 保证状态只能修改一次
if(self.PromiseStatus !== 'pending'){
return;
}
// 1. 修改状态 (PromiseStatus)
self.PromiseStatus = 'fulfilled';
// 2. 设置对象结果值 (PromiseResult)
self.PromiseResult = data;
setTimeout(() => {
// 3. 触发回调函数
self.callbacks.forEach(callback => {
callback.onResolved && callback.onResolved(data);
});
});
}
function reject(data){
if(self.PromiseStatus !== 'pending'){
return;
}
// 1. 修改状态 (PromiseStatus)
self.PromiseStatus = 'rejected';
// 2. 设置对象结果值 (PromiseResult)
self.PromiseResult = data;
setTimeout(()=>{
// 3. 触发回调函数
callback.onRejected && callback.onRejected(data);
});
}
// 处理抛出异常改变状态 throw error
try {
// 同步调用执行器函数
excutor(resolve, reject);
} catch (error) {
// 修改promise对象状态为失败
reject(error);
}
}
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
// 异常穿透 判断回调参数 onRejected 没传 默认返回值
if (typeof onRejected !== 'function') {
onRejected = function (value) {
return value;
}
}
// 不传就默认返回
if (typeof onResolved !== 'function') {
onResolved = function (value) {
return value;
}
}
// then需要返回一个Promise对象
return new Promise((resolve, reject) => {
function callback(type){
try {
let result = type(self.PromiseResult);
// 根据then的返回结果的状态进行不同的处理
if(result instanceof Promise){
result.then(data => {
resolve(data);
}, error => {
reject(error);
})
}else{
// 结果的对象状态为成功
resolve(result);
}
} catch (e) {
reject(e);
}
}
// this指向实例对象,因为是实例对象在调用这个方法
if(this.PromiseStatus === 'fulfilled'){
// 保证then的回调是异步执行
setTimeout(() => {
callback(onResolved);
});
}else if(this.PromiseStatus ==='rejected'){
setTimeout(() => {
callback(onRejected);
});
}else if(this.PromiseStatus ==='pending'){
// pending状态 异步任务 延时执行改变状态
// 保存回调函数 在状态改变时进行调用
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
}
})
}
})
}
// 添加捕获错误方法
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
}
// 添加resolve方法
Promise.resolve = function (value) {
return new Promise(function (resolve,reject) {
if(value instanceof Promise) {
value.then(v=>resolve(v),e=>reject(e))
}else {
resolve(value)
}
})
}
// 添加reject方法
Promise.reject = function (reason) {
return new Promise(function (resolve,reject) {
reject(reason)
})
}
// 添加all方法
Promise.all = function (promises) {
return new Promise(function (resolve,reject) {
let result = []
let count = 0
for(let i = 0;i<promises.length;i++) {
promises[i].then(function (value) {
// 这里可以得知对象的状态是成功
result[i] = value // 结果的顺序是按照promise的顺序来的
count++
if(count === promises.length) {
resolve(result)
}
})
.catch(function (reason) {
reject(reason)
})
}
})
}
// 添加trace方法
Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
for(let i = 0; i < promises.length; i++) {
promises[i].then(function (value) {
resolve(value) // 第一个成功的promise执行resolve 决定race的结果
})
.catch(function (reason) {
reject(reason)
})
}
})
}
async 与 await
async函数
【async函数】返回一个 Promise 对象
,可以使用 then 方法添加回调函数。Promise的对象结果是由async函数的返回值来决定的
async function main() {
// 返回一个非 Promise类型的数据,main函数的返回值是一个成功的Promise对象
return 1;
// 返回一个 Promise 对象,main函数的返回值由Promise.resolve()方法返回的Promise对象决定状态
return Promise.resolve(1);
}
await
await右侧是一个Promise对象,await 返回的是Promise成功的值。
await右侧是其他值,直接将此值作为wait的返回值。
await必须写在async函数内部,但是async内部可以没有await。
await 右侧的promise是一个失败的promise,那么await会抛出这个错误。需要使用try...catch来捕获异常。
async function main() {
// 1. 右侧为Promise的情况
let res = await Promise.resolve('OK');// OK
// 2. 右侧为其他类型
let res2 = await 123; // 123
// 3. 右侧为失败的Promise
try {
let res3 = await Promise.reject('error');
}catch(e){
console.log(e);// error
}
}
网友评论