普通回调,promises,generator 或 async-wait
现在使用4种方式,依次获取店铺 shops,再获取该店铺的水果 fruits
1. 普通回调
const ajax = require('yu.ajax')
function getShop() {
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/shops',
onSuccess: function (result) {
console.log(result)
getFruit()
}
})
}
function getFruit() {
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/fruits',
onSuccess: function (result) {
console.log(result)
}
})
}
getShop()
2. Promise
const ajax = require('yu.ajax')
new Promise(function (resolve, reject) {
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/shops',
onSuccess: function (result) {
resolve(result);
},
onFailure: function (error) {
reject(error)
},
})
}).then(data=>{
console.log(data)
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/fruits',
onSuccess: function (result) {
console.log(result);
},
onFailure: function (error) {
console.log(error)
},
})
}).catch(error=>{
console.log('error:', error)
})
3. Generator
const ajax = require('yu.ajax')
function getShop() {
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/shops',
onSuccess: function (result) {
task.next(result);
}
})
}
function getFruit() {
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/fruits',
onSuccess: function (result) {
task.next(result);
}
})
}
function* doTask() {
const shops = yield getShop()
const fruit = yield getFruit()
console.log(shops)
console.log(fruit)
}
const task = doTask()
task.next()
4. async await
function getShop() {
return new Promise(resolve=>{
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/shops',
onSuccess: function (result) {
resolve(result)
}
})
})
}
function getFruit() {
return new Promise(resolve=>{
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/fruits',
onSuccess: function (result) {
resolve(result)
}
})
})
}
async function doTask() {
const shops = await getShop()
const fruit = await getFruit()
console.log(shops)
console.log(fruit)
}
doTask()
5. Promise的深入应用
我对他们三者之间的关联理解如上图所示,Promise是基础,Generator和async/await串连多个Promise的同步执行,也就是把Promise的异步特性变为同步,编程更爽。当然Generator的yield也可以跟非Promise类型的对象,对于Generator更可以理解为迭代器。而async/await则是多个Promise同步执行的简单方法。
Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了
- 简单使用,执行代码和处理结果分开
new Promise((resolve,reject)=>{
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/fruits',
onSuccess: function (result) {
resolve(result)
},
onFailure: function (result) {
reject(result)
},
})
}).then(result=>{
// 处理成功
console.log(result)
}).catch(error=>{
// 处理失败
console.log(error)
})
- 可以按顺序执行多个异步任务
平常业务中我们发起多个异步ajax请求时,往往不知道哪个请求先返回结果,异步结果不可控。
让异步任务可控,可以按照我们的要求顺序执行
场景:
- 当任务是异步的,
- 下一个任务依赖上一个任务的执行结果
- 全部成功才算成功
- 只要其中一个任务失败,则全部失败
function task1(input) {
console.log(input)
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(1)
}, 1000)
})
}
function task2(input) {
console.log(input)
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(2)
}, 1000)
})
}
function task3(input) {
console.log(input)
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(3)
}, 1000)
})
}
new Promise((resolve, reject)=>{
resolve(0)
}).then(task1)
.then(task2)
.then(task3)
.then(result=>{
console.log(result)
})
- 可以同时执行多个异步任务
场景:
- 当任务是异步的,
- 任务之间无依赖关系
- 全部成功才算成功
- 只要其中一个任务失败,则全部失败
const task1 = new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(1)
}, 1000)
})
const task2 = new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(2)
}, 1000)
})
const task3 = new Promise((resolve, reject)=>{
setTimeout(function () {
reject(3)
}, 1000)
})
Promise.all([task1, task2, task3]).then(result=>{
console.log(result)
}).catch(error=>{
console.log(error)
})
- 异步任务竞争,以先完成的任务的结果为准
因为以下异步任务中,任务2先完成,所以结果返回是2
const task1 = new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(1)
}, 2000)
})
const task2 = new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(2)
}, 1000)
})
Promise.race([task1, task2]).then(result=>{
console.log(result)
})
6. Generator 的深入应用
将Promise的深入应用用Generator重写
- 简单使用
function getFruits() {
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/fruits',
onSuccess: function (result) {
task.next(result)
},
})
}
function* doTask() {
const fruits = yield getFruits()
console.log(fruits)
}
const task = doTask()
task.next()
- 可以按顺序执行多个异步任务
从代码来看,比Promise简洁多了
function task1() {
setTimeout(function () {
task.next(1)
}, 1000)
}
function task2() {
setTimeout(function () {
task.next(2)
}, 1000)
}
function task3() {
setTimeout(function () {
task.next(3)
}, 1000)
}
function* doTask() {
console.log(0)
const one = yield task1()
console.log(one)
const two = yield task2()
console.log(two)
const three = yield task3()
console.log(three)
}
const task = doTask()
task.next()
- 不可以同时执行多个异步任务
因为next()表示的是下一个任务,那么Generator只是迭代器,不能是并发器,只能按顺序执行
- 当然也有没竞争任务
- 那Generator的应用场景是什么?
我觉得是简化异步流程,比如我们现在要处理多个表单多个流程多个目标,我先报名,报名成功后,向政府a报备,政府a通过后,我就向政府b请求。如果政府a拒绝,我就向政府c请求。每个表单提交都是一个异步任务,并且还不知道结果如何。如果用promise,则也会比较绕。
function* doTask() {
console.log(0)
const one = yield task1()
console.log(one)
const two = one === 1 ? yield task2() : yield task3()
console.log(two)
}
7. async, await 的深入应用
而async/await则是多个Promise同步执行的简单方法, 同时,async/await的功能和效果应该和generator相同。因为babel中有async/await转generator语法的转换器。
将Promise的深入应用用async awit重写
- 简单使用
function getShop() {
return new Promise(resolve=>{
ajax({
method: 'GET',
url: 'http://mock.yurencloud.com/shops',
onSuccess: function (result) {
resolve(result)
}
})
})
}
async function doTask() {
const shops = await getShop()
console.log(shops)
}
doTask()
- 可以按顺序执行多个异步任务
async/await 同时具有promise和generator的写法和优点,又比promise简洁,比generator更容易理解,不会有.next()这样的迭代。
function task1() {
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(1)
}, 1000)
})
}
function task2() {
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(2)
}, 1000)
})
}
function task3() {
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(3)
}, 1000)
})
}
async function doTask() {
console.log(0)
const one = await task1()
console.log(one)
const two = await task2()
console.log(two)
const three = await task3()
console.log(three)
}
doTask()
- async/await处理reject,处理错误
使用try/catch来处理错误,抛出的处理就是reject的结果
async function doTask() {
try{
console.log(0)
const one = await task1()
console.log(one)
const two = await task2()
console.log(two)
const three = await task3()
console.log(three)
}catch (e) {
console.log(e)
}
}