在js中,任务可分为两种,同步任务和异步任务。
(1) 同步任务
又叫 非耗时任务,指的是在主线程排队执行的那些任务
只有前一个任务执行完毕,才能执行后一个任务
(2) 异步任务
又叫 耗时任务,异步任务由JavaScript委托给宿主环境进行执行
当异步任务执行完成后,会通知JavaScript主线程执行异步任务的回调函数
当我们打开网站时,像图片的加载,音乐的加载,其实就是一个异步任务
现有a、b和c三个任务,如果其为同步任务,可以很简单地顺序执行,但如果其为异步任务,该如何顺序执行呢?
一、回调函数
function thing(thingName, callback) {
setTimeout(() => {
console.log(`执行${
thingName}任务`)
typeof callback === 'function' && callback()
}, 1000)
}
// 执行a任务
// 执行b任务
// 执行c任务
thing('a', () => {
thing('b', () => {
thing('c')
})
})
优点:简单、方便、实用
缺点:回调函数层层嵌套,不易于阅读和维护,形成回调地狱。
二、promise
1. 使用方式
基本使用
new Promise ((resolve, reject) => {
// 执行代码
}).then(() => {
// 期约兑现
}).catch(() => {
// 期约拒绝
})
详细使用戳这里
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise#%E7%A4%BA%E4%BE%8B
2. 异步任务顺序执行
function thing(thingName) {
return new Promise(resolve => {
setTimeout(() => {
console.log(`执行${
thingName}任务`)
resolve()
}, 1000)
})
}
// 执行a任务
// 执行b任务
// 执行c任务
thing('a')
.then(() => thing('b'))
.then(() => thing('c'))
3. 实现原理
那么如何实现一个promise呢?实现promise之前,先分析下promise的结构
-
promise存在三个状态,pending 待定, fulfilled 兑现, rejected 拒绝,因此需要
(1)定义三个常量 PENDING、FULFILLED、REJECTED 对应三种状态
(2)定义 status 表示期约当前状态
(3)定义 value 表示已兑现期约值、定义 reason 表示已拒绝期约原因
-
在调用promise的实例函数时,我们传入了一个执行器,执行器接收两个函数,其作用分别为将待定期约转化为已兑现期约与已拒绝期约。因此需要定义两个函数 resolve 和 reject
-
已兑现期约、已拒绝期约处理函数 then
已拒绝期约处理函数 catch
最终执行函数 finally
-
静态函数 resolve、reject、 all 及 race 的实现
代码实现基于以下链接调整
https://juejin.cn/post/6945319439772434469#heading-30
3.1 promise简易实现
// MyPromise.js
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class MyPromise {
// 期约状态, 初始值为pending
status = PENDING
// 已兑现期约值
value = null
// 已拒绝期约原因
reason = null
constructor(executor){
executor(this.resolve, this.reject)
}
// 将待定期约转化为已兑现期约
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
}
}
// 将待定期约转化为已拒绝期约
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
}
}
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
}
}
}
module.exports = MyPromise
同目录下新建 test.js 文件用于测试
// test.js
// 引入我们的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise1 = new MyPromise((resolve, reject) => {
resolve('resolve')
})
const promise2 = new MyPromise((resolve, reject) => {
reject('reject')
})
promise1.then(value => {
console.log('promise1 then', value)
}, reason => {
console.log('promise1 catch', reason)
})
promise2.then(value => {
console.log('promise2 then', value)
}, reason => {
console.log('promise2 catch', reason)
})
// 执行结果
// promise1 then resolve
// promise2 catch reject
3.2 加入异步逻辑
继续测试,发现异步执行resolve函数时,会存在问题。因此,我们需对异步逻辑进行处理。
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('resolve'), 0)
})
promise.then(value => {
console.log('promise then', value)
}, reason => {
console.log('promise catch', reason)
})
// 期望输出 promise then resolve
// 实际无输出
(1) 缓存兑现与拒绝回调
// 存储兑现回调函数
onFulfilledCallback = null
// 存储拒绝回调函数
onRejectedCallback = null
(2) then 方法中新增待定期约处理
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.onFulfilledCallback = onFulfilled
this.onRejectedCallback = onRejected
}
}
(3) resolve 与 reject 中调用回调函数
// 将待定期约转化为已兑现期约
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 兑现回调函数存在则执行
this.onFulfilledCallback && this.onFulfilledCallback(value)
}
}
// 将待定期约转化为已拒绝期约
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
// 拒绝回调函数存在则执行
this.onRejectedCallback && this.onRejectedCallback(reason)
}
}
使用以下代码再次验证,异步问题解决。
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => resolve('resolve'), 0)
})
promise.then(value => {
console.log('promise then', value)
}, reason => {
console.log('promise catch', reason)
})
// 执行结果: promise then resolve
3.3 实现 then 方法多次调用添加多个处理函数
Promise支持添加多个处理函数,来测试下自定义Promise是否满足。
// test.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
promise.then(value => {
console.log(1)
console.log('resolve', value)
})
promise.then(value => {
console.log(2)
console.log('resolve', value)
})
promise.then(value => {
console.log(3)
console.log('resolve', value)
})
// 3
// resolve success
经测试,自定义Promise并不能添加多个处理函数,继续修改。
(1) 新增兑现与拒绝回调数组
// 存储兑现回调函数数组
onFulfilledCallbacks = []
// 存储拒绝回调函数数组
onRejectedCallbacks = []
(2) then方法中存储回调文章来源:https://www.toymoban.com/news/detail-489142.html
then (onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
} else if (this.status === REJECTED) {
onRejected(this.reason)
} else if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
}
(3) resolve 与 reject 中循环调用回调函数文章来源地址https://www.toymoban.com/news/detail-489142.html
// 将待定期约转化为已兑现期约
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
// 兑现回调函数存在则执行
while (this.onFulfilledCallbacks.length) {
到了这里,关于js中如何顺序执行异步任务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!