Promise: ES6 新增的语法,是异步问题同步化解决方案 ,同时解决了回调地狱的问题;
Promise解决:
通过.then的方式,拿到Promise内部的异步操作的结果,并且不阻塞 和Promise不相关的 任何程序,让它们同步执行;
then 函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。因为 Promise 规范规定除了 pending 状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个 then 调用就失去意义了。 对于 then 来说,本质上可以把它看成是 flatMap;Promise的状态(生命周期):
padding:进行中
fulfilled:已完成
rejected:已失败异步任务的完成与否 取决于当前 Promise的状态
1.异步任务完成 调用resolve()成功回调 状态:padding -> fulfilled
2.异步任务失败 调用reject()失败回调 状态:padding -> rejectedPromise的特点:
1.Promise的状态不受外界的影响;
因为Promise代表的是异步操作,只有异步操作成功或者或者失败,才会改变* Promise的状态;
2.Promise的状态一旦改变就无法更改;
一旦状态固化,返回的结果在任何地方都调用的到;Promise的执行方式:
微任务的方式执行Promise注册上回调函数,不管是成功还是失败都可以;
微任务:相当于高速中的紧急车道,可以让微任务快速排在异步队列的最前方,等待主线程通过事件轮询将其调用;Promise的静态方法:(静态方法是在构造器中绑定的方法)
Promise.resolve():返回一个成功状态态的Promise,通过.then()注册成功的回调函数;
Promse.reject():返回一个失败状态的Promise,通过.catch()注册失败的回调函数;
Promise.all([p1,p2,p3]):只有当中的Promise对象全部成功,才会返回一个结果且是个数组;
Promise.race([p1,p2,p3]):返回其中一个运行最快的结果;
let p = new Promise((resolve,reject) => { //Promise中的回调函数是:执行器函数(executon)===同步执行
console.log('我是Promise的同步回调函数');
//异步任务
$.ajax({
url:'./data.json',
success:function (data) {
// console.log(data)
resolve(data)
},
error:function (err) {
reject(err)
}
})
p.then((res) => { //.then方式注册的是 成功的回调函数
// console.log(res)
// simpleArray(res)
console.log( simpleArray(res))
}).catch((err) => { //.catch方式注册的是 失败的回调函数
console.log(err,'失败')
})
console.log('我是同步代码')
function simpleArray (data) {
return data.map(function (item) {
// console.log(item)
return item.name
})
}
// 我是Promise的同步回调函数
// 我是同步代码
// ["zhangsan", "lisi", "wangwu"]
- 面试考点:theable 对象
1.Promise调用resolve方法传入theable对象会发生什么?
会调用theable对象中的 then方法,然后调用resolve()传出成功结果,或者调用reject()传出失败结果;
2.Promise调用reject方法传入theable对象会发生什么?
Promise只有调用resolve方法传入theable对象才会返回成功或失败的结果,
调用reject()只会返回一个空对象{then:f}
//theable 对象
let obj = {
then(resolve,reject){
// resolve(11);
reject(12);
}
}
let p1 = Promise.resolve(obj);
// let p1 = Promise.reject(obj);//{then:f}
p1.then((data) => {
console.log(data)
}).catch((err) => {
console.log(err)
})
- 案例
//考察:异步队列 事件轮询 微任务
Promise.resolve().then(function(){
console.log('Promise1') //1
setTimeout(() => {
console.log('setTimeOut1') //4
},0)
})
setTimeout(() => {
console.log('setTimeOut2') //2
Promise.resolve().then(function(){
console.log('Promise2') //3
})
},0)
//Promise1
//setTimeOut2
//Promise2
//setTimeOut1
首先看出来,Promise是通过构造函数实例化一个对象,然后通过实例对象上的then方法,来处理异步返回的结果。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
function Promise(executor) {
var _this = this
this.state = PENDING; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败原因
function resolve(value) {}
function reject(reason) {}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
};
module.exports = Promise;
当我们实例化Promise时,构造函数会马上调用传入的执行函数executor,我们可以试一下:
let p = new Promise((resolve, reject) => {
console.log('执行了');
});
因此在Promise中构造函数立马执行,同时将resolve函数和reject函数作为参数传入:
function Promise(executor) {
var _this = this
this.state = PENDING; //状态
this.value = undefined; //成功结果
this.reason = undefined; //失败原因
function resolve(value) {}
function reject(reason) {}
executor(resolve, reject)
}
但是executor也会可能存在异常,因此通过try/catch来捕获一下异常情况:
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
- 手写Promise
function Mypromise(fn) { //构造函数
this.state = 'pending' //状态
this.value = undefined //成功结果
this.reason = undefined //失败原因
/*
那么如何让我们的Promise来支持异步呢?
我们可以参考发布订阅模式,在执行then方法的时候,如果当前还是PENDING状态,
就把回调函数寄存到一个数组中,当状态发生改变时,去数组中取出回调函数;
*/
this.onFulfilled = [];//成功的回调
this.onRejected = []; //失败的回调
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.onFulfilled.forEach(fn => fn(value))
// console.log(this.value)
}
}
let reject = value => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = value
this.onRejected.forEach(fn => fn(value))
console.log(this.reason)
}
}
// 自动执行函数
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
// then
}
/*
在规范中说明了,onFulfilled和onRejected是可选的,因此我们对两个值进行一下类型的判断:
onFulfilled 和 onRejected 都是可选参数。
如果 onFulfilled 不是函数,其必须被忽略。
如果 onRejected 不是函数,其必须被忽略。
*/
Mypromise.prototype.then = function (onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
typeof onFulfilled === 'function' && onFulfilled(this.value)
}
if (this.state === 'rejected') {
typeof onRejected === 'function' && onRejected(this.reason)
}
if (this.state === 'pending') {
typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
typeof onRejected === 'function' && this.onRejected.push(onRejected)
}
}
//Promise:异步问题同步化解决方案
let p = new Mypromise((resolve, reject) => { //Promise中的回调函数是:执行器函数(executon)===同步执行
console.log('我是Promise的同步回调函数');
//异步任务
$.ajax({
url: './data.json',
success: function (data) {
console.log(data)
resolve(data)
},
error: function (err) {
reject(err)
}
})
})
p.then((res) => { //.then方式注册的是 成功的回调函数
console.log(res)
// simpleArray(res)
console.log(simpleArray(res))
})
function simpleArray(data) {
return data.map(function (item) {
// console.log(item)
return item.name
})
}
// 我是Promise的同步回调函数
// 我是同步代码
// ["zhangsan", "lisi", "wangwu"]
手写Promise参考原文:
从零开始手写Promise
实践系列-Promises/A+规范
- 手写Promise(用Class类)
class myPromise {
constructor(fn) {
this.state = 'pending' //状态
this.value = undefined //成功结果
this.reason = undefined //失败原因
this.onFulfilled = [];//成功的回调
this.onRejected = []; //失败的回调
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled'
this.value = value
this.onFulfilled.forEach(fn => fn(value))
// console.log(this.value)
}
}
let reject = value => {
if (this.state === 'pending') {
this.state = 'rejected'
this.reason = value
this.onRejected.forEach(fn => fn(value))
console.log(this.reason)
}
}
// 自动执行函数
try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}
// then
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
typeof onFulfilled === 'function' && onFulfilled(this.value)
}
if (this.state === 'rejected') {
typeof onRejected === 'function' && onRejected(this.reason)
}
if (this.state === 'pending') {
typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
typeof onRejected === 'function' && this.onRejected.push(onRejected)
}
}
}
//Promise:异步问题同步化解决方案
let p = new myPromise((resolve, reject) => { //Promise中的回调函数是:执行器函数(executon)===同步执行
console.log('我是Promise的同步回调函数');
//异步任务
$.ajax({
url: './data.json',
success: function (data) {
console.log(data)
resolve(data)
},
error: function (err) {
reject(err)
}
})
})
p.then((res) => { //.then方式注册的是 成功的回调函数
console.log(res)
// simpleArray(res)
console.log(simpleArray(res))
})
function simpleArray(data) {
return data.map(function (item) {
// console.log(item)
return item.name
})
}
// 我是Promise的同步回调函数
// 我是同步代码
// ["zhangsan", "lisi", "wangwu"]
- async & await:
原理:async 和 await 用了同步的方式去做异步,async 定义的函数的返回值都是 promise,await后面的函数会先执行一遍,然后就会跳出整个 async 函数来执行后面js栈的代码;
主要考察宏任务和微任务,搭配promise,询问一些输出的顺序;