标题
实现JavaScript异步编程方式:回调函数、事件监听、发布/订阅、Promise对象
详细的介绍点击这个链接
回调函数
回调函数是所有异步编程方案的根基。
function foo (callback) {
setTimeout(function () {
callback()
}, 3000)
}
foo(function () {
console.log('这个就是一个回调函数');
console.log('调用者定义这个函数,执行者执行这个函数');
console.log('其实就是调用者告诉执行者异步任务结束后应该做什么');
})
promise
const promise = new Promise(function (resolve, reject) {
// 这里用于兑现承诺 。这个函数会在构造promise的过程中同步执行。
// 承诺一旦执行;不管是失败还是达成;都无法再次改变
// resolve(100) // 承诺达成 可以把pending状态改为fulfilled
console.log('start');
reject(new Error('promise rejecced')) // 承诺失败
})
promise.then(function (val) {
console.log(val, '这个是承诺达成的结果');
}, function (error) {
console.log(error);
})
console.log('end');
// 执行顺序: start end error/100
Promise封装Ajax
// Promise 方式的AJAX
function ajax (url) {
return new Promise(function (resolve, reject) {
var XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest;
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
// 相应类型为json;html5引入的新特性
xhr.responseType = 'json'
// 设置请求头
xhr.setRequestHeader('app_device', '1');
// html5中提供的新事件 请求完成过后;也就是传统的readystate==4的状态才会执行
xhr.onload = function () {
if (this.status == 200) {
// 请求成功
resolve(this.responseText)
} else {
reject(new Error(this.statusText))
}
}
// 开始执行这个异步请求(发送http请求)
xhr.send()
})
}
url = '这里是需要请求的网址'
ajax(url).then(function (res) {
console.log(res, '这个是返回结果');
}, function (error) {
console.log(error);
})
Promise的链式调用
// Promise对象的then方法会返回一个全新的Promise对象
// 后面的then方法就是在为上一个then返回的Promise注册回调
// 前面then方法中回调函数的返回值会作为后面的then方法回调的参数
// 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束。
.catch可以获取全部then里面的异常;不用在每个then里面写reject函数了。
实现Promise
// 1 Promise 就是一个类;需要传递一个参数,参数是一个回调函数(执行器)立即执行。
/*
2、Promise中有三个状态 分别为成功 fulfiled、失败 rejected、等待 pending
一旦状态确定就不可以更改;
3、resolve和rejected是用来更改状态的
4、then方法内部做的事情就判断状态;如果状态是成功,调用成功地回调函数 如果状态是失败;就调用失败的回调函数
5、then成功回调有一个参数表示成功之后的值;then失败回调失败之后会有一个原因
6、同一个promise对象下面的 then方法是可以被调用多次的。
7/ then方法是可以被链式调用的,后面then方法的回调函数拿到的值就是上一个then方法的回调函数的返回值
*/
// myPromsie类
const PENDING = 'pending' // 状态是等待
const FULFILED = 'fulfiled' // 成功
const REGECTED = 'rejected' // 失败
class MyPromise {
// 构造函数
constructor (executor) {
// 捕获执行器错误
try {
// executor叫做执行器 ;也就是promise对象中的回调函数;立即执行
executor(this.resolve, this.reject)
} catch (e) { this.reject(e) }
}
// 类的实例属性
// promise状态
status = PENDING;
// 成功之后的值
value = undefined;
// 失败之后的值
reason = undefined;
// 成功回调
successCallback = [];
// 失败回调
filCallback = [];
resolve = (value) => {
// 如果状态不是pending 就不用管了
if (this.status !== PENDING) return
// 将状态改为成功
this.status = FULFILED
// 保存成功之后的值
this.value = value
// 判断成功回调是否存在;存在就调用 只适用于同步then来调用
// this.successCallback && this.successCallback(this.value)
// 异步调用的时候(就是有定时器之类的;然后同事调用多次promise)
while (this.successCallback.length) this.successCallback.shift()()
}
reject = (reason) => {
if (this.status !== PENDING) return
this.status = REGECTED
// 保存失败之后的值
this.reason = reason
// 判断失败回调是否存在;存在就调用
// this.filCallback && this.filCallback(this.reason)
while (this.filCallback.length) this.filCallback.shift()()
}
then (successCallback, filCallback) {
// 可以实现当then里面不传递回调函数;就会把参数传递给下一个then
successCallback = successCallback ? successCallback : value => value
filCallback = filCallback ? filCallback : reason => { throw reason }
let promise2 = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILED) {
// 把下面的代码变为异步代码;就能够使用promise2
setTimeout(() => {
try {
let x = successCallback(this.value)
// 判断x是普通值还是promise对象
// 如果是普通值;直接调用resolve
// 如果是promise对象 查看promise返回的结果
// 再根据promise对象返回的结果 决定调用resolve还是调用reject
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REGECTED) {
setTimeout(() => {
try {
let x = filCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else {
// 处于等待
// 把成功后的回调和失败的回调存储起来
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
});
this.filCallback.push(() => {
setTimeout(() => {
try {
let x = filCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
});
}
});
return promise2
}
finally (callback) {
// 获取当前promise的状态
return this.then((value) => {
// 不管是普通值还是promise对象;我们都把它转成promise对象;这样就可以等待异步promise对象的完成。
return MyPromise.resolve(callback()).then(() => value)
}, (reason) => {
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
catch (failCallback) {
return this.then(undefined, failCallback)
}
static all (array) {
let result = []
let index = 0
return new MyPromise((resolve, reject) => {
function addData (key, value) {
result[key] = value
index++;
// 通过判断长度;可以等待异步操作的结果都完成之后在调用resolve成功回调
if (index === array.length) {
resolve(result)
}
}
// for循环是一瞬间完成的;但是在执行的时候有异步操作;要等待所有的异步完成之后才能调用resolve
for (let i = 0; i < array.length; i++) {
let current = array[i]
// 判断当前参数是否是myPromise的实例对象
if (current instanceof MyPromise) {
// promise对象
current.then((val) => addData(i, val), reason => reject(reason))
} else {
// 普通值
addData(i, array[i])
}
}
})
}
// resolve方法实现
static resolve (value) {
if (value instanceof MyPromise) return value
return new Promise(resolve => {
resolve(value)
})
}
}
function resolvePromise (promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// 如何判断是否是promise对象;就看x是不是myPromise 对象的实例
if (x instanceof MyPromise) {
// promise对象
// 需要查看当前promise的状态
// x.then((value) => resolve(value), (reason) => reject(reason))
x.then(resolve, reject)
} else {
// 普通值
resolve(x)
}
}```
// 导出这个类
module.exports = MyPromise