本文主要介绍了我的对promise的一些粗浅理解,若有不正确的地方,还请指正。css
从JS语法层面上讲,Promise是一个函数,能够经过new关键字进行调用而后生成一个对象,这个对象被成为promise对象。promise对象有三种状态,为pedding、resolved、rejected,这是promise的重要机制。 从功能的角度来说,Promise是一个容器,它里面包含着一个将来才会获得的(一般是异步)结果。 Promise帮助调用者拿回了调用回调函数的主动权,而不是把主动权交给第三方函数。前端
如下关于callback函数的执行有几种信任问题。vue
function getData(url, callback) {
let req = new XMLHttpRequest()
req.open('GET', url, true)
req.onload = function () {
if (req.status === 200) {
// 使用回调处理会存在几种潜在的问题
// 1. 过早或者过晚调用
// 2. 干脆不调用
// 3. 调用了不少次
// 4. 没有给回调函数传入指定的参数
callback(req.responseText)
} else {
console.log(new Error(req.statusText))
}
}
req.onerror = function () {
console.log(new Error(req.statusText))
}
req.send()
}
function callback(text) {
console.log(text)
}
let url = 'http://api.myjson.com/bins/16hvos'
getData(url, callback)
复制代码
function getData(url) {
return new Promise(function (resolve, reject) {
let req = new XMLHttpRequest()
req.open('GET', url, true)
req.onload = function () {
if (req.status === 200) {
resolve(req.responseText)
} else {
reject(new Error(req.statusText))
}
}
req.onerror = function () {
reject(new Error(req.statusText))
}
req.send()
})
}
let url = 'http://api.myjson.com/bins/16hvos'
getData(url).then(function onFullfilled(value) {
console.log(value)
}).catch(function onRejected(value) {
console.log(value)
})
复制代码
回调地狱会致使代码晦涩难懂,不易维护,错误处理复杂。ios
// 先执行taskA 获得符合预期结果; 执行taskB, 获得预期结果,执行taskC, 获得预期结果,接着处理。。。
function taskA(callback) {
let result = 1
setTimeout(() => {
callback(result)
}, 2000)
}
function taskB(callback) {
let result = 2
setTimeout(() => {
callback(result)
}, 2000)
}
function taskC(callback) {
let result = 3
setTimeout(() => {
callback(result)
}, 2000)
}
taskA(function (res) {
if (res === 1) {
taskB(function (res) {
if (res === 2) {
taskC(function (res) {
if (res === 3) {
console.log(res)
}
})
}
})
}
})
复制代码
能够看出每执行一个函数都须要给其一个回调函数,并且代码末尾有不少括号的嵌套,虽然可使用必定方法能够改善这种嵌套的方法,可是依然代码依然不够易读。好比采用以下方法抽离一部分代码git
function a(res) {
if (res === 1) {
taskB(b)
}
}
function b (res) {
if (res === 2) {
taskC(c)
}
}
function c(res) {
if (res === 3) {
console.log(res)
}
}
taskA(a) // 3
复制代码
即便采用以上方式处理,阅读此代码仍然让人头大。es6
// taskA执行,拿到预期结果,返回一个resolved的promise对象
function taskA() {
let result = 1
return new Promise(function (resolve, reject) {
setTimeout(() => {
if (result === 1) {
resolve(result)
} else {
reject(new Error('fail'))
}
}, 2000)
})
}
// 一个resolved状态的promise对象能够在其then方法中拿到异步处理的结果
// 在then方法中的回调函数中使用return会新生成一个resolved状态的promise对象
taskA().then(function (result) {
return result
}).then(function taskB() {
let result = 2
return new Promise(resolve => {
setTimeout(() => {
resolve(result)
}, 2000)
})
}).then(function taskC() {
let result = 3
return new Promise(resolve => {
setTimeout(() => {
resolve(result)
}, 2000)
})
}).then(function (result) {
console.log(result)
})
复制代码
Promise函数接受一个函数做为参数,这个函数有两个参数,resolve和reject, 用来改变所生成的promise对象的状态。这个函数参数会当即执行。github
let promise = new Promise(function (resolve, reject) {
setTimeout(() => {
resolve(42)
}, 2000)
})
promise.then(function (value) {
console.log(value) // 42
})
Object.getPrototypeOf(promise) === Promise.prototype // true
复制代码
Promise.resolve() 直接返回一个已解析状态的promise对象。vuex
var promise = Promise.resolve(42)
// 至关于
var promise = new Promise(function (resolve, reject) {
resolve(42)
})
复制代码
Promise.reject 直接返回一个已拒绝状态的promise对象。json
var promise = Promise.reject(new Error('ok'))
// 至关于
var promise = new Promise(function (resolve, reject) {
reject(new Error('fail'))
})
复制代码
(1) 每个promise对象都有then方法,当这个promise对象的状态变为resolved时,会执行then中注册的回调函数。axios
let promise = Promise.resolve(42)
promise.then(function (value) {
console.log(value) //42
})
复制代码
(2) promise对象的then方法会返回一个新的promise对象,所以咱们能够在新生成的promise对象中继续使用then方法。
let promise = Promise.resolve(42)
promise.then(function (value) {
console.log(value)
}).then(function (value) {
console.log('ok')
})
复制代码
根据then方法的特性能够实现promise对象的链式调用。
let promise = Promise.resolve()
function taskA() {
console.log('taskA')
}
function taskB() {
console.log('taskB')
}
function onRejected(error) {
console.log(error)
}
promise
.then(taskA)
.then(taskB)
.catch(onRejected)
// taskA taskB
复制代码
以上例子中,实现了promise的链式调用。当taskA和taskB中没有抛出错误时,程序会一直执行下去,其中catch是为了捕获taskA或taskB出现的异常。若是taskA或者taskB中出现了错误,那么catch中的回调函数就会执行。以下:
let promise = Promise.resolve()
function taskA() {
throw new Error('fail')
}
function taskB() {
console.log('taskB')
}
function onRejected(error) {
console.log(error)
}
promise
.then(taskA)
.then(taskB)
.catch(onRejected)
// Error fail
复制代码
若是taskA出现了一个错误,那么taskB将不会执行,会执行调用catch中的回调函数。 3). 链式调用传值 想要实现链式调用的传值,只须要在then中的回调函数给出返回值,Promise就会自动将这个返回值解析为一个promise对象。
let promise = Promise.resolve(10)
function taskA(value) {
return value + 10
}
function taskB(value) {
return value + 10
}
function taskC(value) {
console.log(value)
}
promise
.then(taskA)
.then(taskB)
.then(taskC) // 30
复制代码
当一个promise的状态为rejected时,那么它的catch方法中的回调函数将会被执行。catch方法其实就是then方法中第二个回调函数。
let promise = Promise.reject('fail')
promise.catch(function (error) {
console.log(error) // fail
})
// 至关于
promise.then(undefined, function (error) {
console.log(error) // fail
})
复制代码
catch也会返回一个promise对象。
Promise.all接受一个由promise对象组成的数组参数,当每一个promise的状态都变成resoved或rejected时,Promise.all返回的promise对象的状态才会改变(resolved或者rejected)。
// getData函数返回一个promise, 而且函数体内的Promise函数会当即执行,即当即执行函数体内的异步任务
function getData(url) {
return new Promise(function (resolve, reject) {
var req = new XMLHttpRequest()
req.open('GET', url, true)
req.onload = function () {
if (req.status === 200) {
return req.responseText
} else {
return new Error(req.statusText)
}
}
req.onerror = function () {
reject(new Error(req.statusText))
}
req.send()
})
}
// 错误写法
// getData函数前加了async关键字,所以它也返回一个promise对象,可是函数体内的请求时异步的,
// getData会当即执行,而后再去执行异步任务,所以getData返回的promise永远是resolved undefined
async function getData(url) {
var req = new XMLHttpRequest()
req.send()
req.open('GET', url, true)
req.onload = function () {
if (req.status === 200) {
console.log('ok')
return req.responseText
} else {
return new Error(req.statusText)
}
}
req.onerror = function () {
reject(new Error(req.statusText))
}
}
Promise.all([
getData('http://azu.github.io/promises-book/json/comment.json'),
getData('http://azu.github.io/promises-book/json/people.json')
]).then(res => {
console.log(res)
})
复制代码
Promise.race也接受一个由promise对象组成的数组参数,当其中的一个promise对象的状态变为resolved或是rejected时,Promise.race返回的promise对象才会改变(resolved或者rejected)。
function asyncPromise () {
return new Promise(resolve => {
resolve(3)
})
}
function test() {
asyncPromise().then(function (value) {
console.log(value)
})
console.log(1)
}
test()
console.log(2)
// 输出顺序为 1 2 3
复制代码
能够把async当作是一个返回值为promise对象的函数的语法糖。
async function test() {
return 1
}
test() // Promise {<resolved>: 1} google浏览器的打印结果
// 至关于
function test() {
return Promise.resolve(1)
}
test() // Promise {<resolved>: 1} google浏览器的打印结果
复制代码
await 让异步代码变为了同步(同步执行)。
function asyncFunction () {
return new Promise(resolve => {
resolve(2)
})
}
async function test() {
let value = await asyncFunction()
console.log(value)
console.log(3)
}
test()
console.log(1)
// 打印结果为 1 2 3
复制代码
采用两种方式模拟一个通过vuex获取数据的过程。 (1) 直接返回promise对象的方式
// src/People.vue
created () {
this.$store.dispatch('GetPeople', { page: 1, size: 20 }).then(response => {
console.log(response) // [{ id: 1, name: 'Joe'}]
})
}
// src/store/people/actions.js
GetPeople({ commit }, payload) {
return new Promise(function (resolve, reject) {
axios.get('http://www.example.com/people', { payload })
.then(function (response) {
resolve(response) // response = [{ id: 1, name: 'Joe'}]
}).catch(function (error) {
reject(error)
})
})
}
复制代码
(2) async / await
// src/People.vue
async created() {
await this.$store.dispatch('GetPeople', { page: 1, size: 20 })
// [{ id: 1, name: 'Joe'}]
}
// src/store/people/actions.js
async GetPeople({ commit }, payload) {
const response = await axios.get('http://www.example.com/people', { payload })
return response
}
复制代码
参考:
咱们是来自帝都的一枚前端程序猿 + 一枚前端程序媛。
这里发布的文章是咱们对学习内容的总结,预计会每周至少会更新一篇。
目前咱们学习计划是: 小程序实战 => vue 进阶用法 => vue 原理 => css 基础 => es6 => js 深刻
另外,工做中用到的一些技术和完成的功能,咱们也会及时总结更新在这里
如文章有错误或表述不清晰,欢迎各位留言反馈~~