1.21(异步解决方案:Promise and Generator)

案例使用Promise解决按顺序请求a b c 三个json文件的回调地狱问题

一个 Promise 必然处于以下几种状态之一:

待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
已兑现(fulfilled): 意味着操作成功完成。
已拒绝(rejected): 意味着操作失败。

一、Promise

1、对于异步操作的状态管理

let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log('wuyan');
        // 对异步操作的执行结果进行判断
        // if () {
        //     resolve()
        // } else {
        //     reject();
        // }
        // resolve('成功')
        // reject('失败')
    }, 1000);
    // then 里面第一个参数是必须的,第二个可以省略,也就是说可以只写已兑现
}).then(res => {
    console.log(res);
}, err => {
    console.log(err);
})

2、执行顺序(1 2 3)

// promise会立即执行,回调函数有异步性,属于微任务
let p2 = new Promise((resolve, reject) => {
    console.log(1);
    resolve();
})
console.log(2);
p2.then(res => {
    console.log(3);
})

3、封装ajax

function ajax(url, successCallback, failCallback) {
    //1、创建XMLHttpRequest对象
    var xmlhttp;
    //判断浏览器是否支持
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else {
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    }
    // 2、发送请求
    xmlhttp.open('GET', url, true);
    xmlhttp.send();
    // 3、服务器响应
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
            var obj = JSON.parse(xmlhttp.responseText);
            //console.log(obj);
            successCallback && successCallback(obj);
        } else if (xmlhttp.readyState === 4 && xmlhttp.status === 404) {
            failCallback && failCallback(xmlhttp.statusText );
        }
    }
}

4、链式操作,不再是回调深渊

let p3 = new Promise((resolve, reject) => {
    ajax('./static/a.json', res => {
        console.log(res);
        resolve('./static/b.json');
    })
    // 这里接收'./static/b.json'
}).then(res => {
    console.log('a成功');
    return new Promise((resolve, reject) => {
        ajax(res, res => {
            console.log(res);
            resolve('./static/c.json');
        })
    })
    // 这里接收./static/c.json,上面不返回新的Promise对像
    // 这里顺序就会出错
}).then(res => {
    console.log('B成功');
    return new Promise((resolve, reject) => {
        ajax(res, res => {
            console.log(res);
            resolve('c也成功了');
        })
    })
}).then(res => {
    console.log(res);
})

5、 封装ajax请求

function getPromise(url) {
    return new Promise((resolve, reject) => {
        ajax(url, res => {
            resolve(res);
        },err => {
            reject(err);
        })
    })
}

6、链式调用

 getPromise('static/a.json')
     .then(res => {
         console.log(res);
         return getPromise('static/b.json')
     }).then(res => {
         console.log(res);
         return getPromise('static/c.json')
     }).then(res => {
         console.log(res);
     })

7、一环出错会影响下一环

这里不存在aa.json这个文件,导致promise回调到err

 getPromise('static/aa.json')
     .then(res => {
         console.log(res);
         return getPromise('static/b.json')
     }, err => {
         console.log(err);
         //上一个回调没有找到,返回reject()
         // 所以需要再请求一下
         return getPromise('static/b.json')
     }).then(res => {
         console.log(res);
         return getPromise('static/c.json')
     }).then(res => {
         console.log(res);
     })

8、catch 统一处理失败

getPromise('static/a.json')
    .then(res => {
        console.log(res);
        return getPromise('static/b.json')
    }).then(res => {
        console.log(res);
        return getPromise('static/c.json')
    }).then(res => {
        console.log(res);
    }).catch(err => {
        console.log(err);
    })

二、Promise 静态方法

1、Promise.resolve()

方法返回一个以给定值解析后的Promise 对象。如果这个值是一个 promise ,那么将返回这个 promise;如果这个值是thenable(即带有"then"方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;否则返回的promise将以此值完成。此函数将类promise对象的多层嵌套展平。

let p1 = Promise.resolve('success');
// console.log(p1);//Promise {<fulfilled>: "success"}
// 那么既然能返回成功,在then里面能不能打印呢
p1.then(res => {
    console.log(res);//success
})

2、Promise.reject()

方法返回一个带有拒绝原因的Promise对象。

let p2 = Promise.reject('fail');
//console.log(p2);//Promise {<rejected>: "fail"}
p2.catch(err => {
    console.log(err);
})

3、应用

function foo(flag) {
    if(flag) {
        return new Promise(resolve => {
            resolve('success');
        })
    } else {
        // return 'fail';
        return Promise.resolve('fail');
    }
}

foo(false).then(res => {
    console.log(res);//fail
}, err => {
    console.log(err);
})

4、Promise.all()

方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例,
那个输入的所有promise的resolve回调的结果是一个数组。这个Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候。它的reject回调执行是,只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。

简单说:all()这个静态方法是等多个任务执行完之后再执行,只要有一个任务失败,那么all()就会认为整个都是失败的

let p3 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(1);
        resolve('1成功');
    }, 1000);
})
let p4 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(2);
        resolve('2成功');
        // reject('2失败');
    }, 2000);
})
let p5 = new Promise((resolve, reject) => {
    setTimeout(() => {
        console.log(3);
        resolve('3成功');
    }, 3000);
})

Promise.all([p3, p4, p5]).then(res => {
    console.log(res);
},err => {
    console.log(err);
})

5、Promise.race()

方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

简单说:race()这个静态方法是 等多个任务执行完之后再执行,只要有一个任务成功,那么all()就会认为整个都是成功的

Promise.race([p3, p4, p5]).then(res => {
    console.log(res);
},err => {
    console.log(err);
})

6、应用

const imgArr = ['1.jpg', '2.jpg', '3.jpg'];
let promisrArr = [];
imgArr.forEach(item => {
    promisrArr.push(new Promise((resolve, reject) => {
        //上传图片操作
        resolve();
    })) 
});

Promise.all(promisrArr).then(res => {
    console.log('图片全部上传完成!');
})


// 7、图片加载成功或超时
function getImg() {
    return new Promise((resolve, reject) => {
        let img = new Image();
        img.onload = function () {
            resolve(img);
        }
        img.src = 'http://120.55.162.187:8080/%E4%B8%BB%E9%A1%B5/%E5%A3%81%E7%BA%B88.jpg';
    })
}

function timeout() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('图片请求超时');
        }, 1000);
    })
}

Promise.race([getImg(), timeout()]).then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
})

三、Generator

生成器函数在执行时能暂停,后面又能从暂停处继续执行。

function* foo() {
    for (let i = 0; i < 4; i++) {
        let arr = ['我', '是', '吴', '炎'];
        console.log(arr[i]);
        //位置很关键
        yield i;
    }
}

let f = foo();

// 循环完成后,状态为true
console.log(f.next());//我 {value: 0, done: false}
console.log(f.next());//是 {value: 1, done: false}
console.log(f.next());//吴 {value: 2, done: false}
console.log(f.next());//炎 {value: 3, done: false}
console.log(f.next());//{value: undfined, done: true}

调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器 ( iterator )对象。当这个迭代器的 next()方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现yield的位置为止,yield 后紧跟迭代器要返回的值。或者如果用的是yield*(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。

next()方法返回一个对象,这个对象包含两个属性:value 和 done,value 属性表示本次 yield 表达式的返回值,done属性为布尔类型,表示生成器后续是否还有 yield 语句,即生成器函数是否已经执行完毕并返回。

yield注意事项

不能作为构造函数使用 yield 只能在生成器内部使用(内部嵌套在别的函数都不行)

function* gen(args) {
    args.forEach(element => {
        yield element + 1;
    });
}

调用 next()方法时,如果传入了参数,那么这个参数会传给上一条执行的 yield语句左边的变量

function* gen1(x) {
    let y = 2 * (yield(x + 1));
    let z = yield(y / 3);
    return x + y + z;
}
let g = gen1(5);
//next()里面的是上一次yield的结果
console.log(g.next());//(x + 1) = 6
console.log(g.next(12));//y = 2 * 12 = 24
console.log(g.next(13));// z = 13  y = 24  x = 5 => 42

1、死循环?

function* count(x = 1) {
    while (true) {
        if (x % 7 === 0) {
            yield x;
        }
        x++;
    }
}

let n = count();
console.log(n.next().value);//7
console.log(n.next().value);//14
console.log(n.next().value);//21

2、Generator对异步操作进行管理

封装好的ajax,先手动开启,后面由回调函数自动请求

function ajax(url, callback) {
    //1、创建XMLHttpRequest对象
    var xmlhttp;
    //判断浏览器是否支持
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else {//兼容早期浏览器
        xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
    }

    // 2、发送请求
    xmlhttp.open('GET', url, true);
    xmlhttp.send();

    // 3、服务器响应
    xmlhttp.onreadystatechange = function () {
        if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
            var obj = JSON.parse(xmlhttp.responseText);
            //console.log(obj);
            callback(obj);
        }
    }
}
function request(url) { 
    ajax(url, res => {
        //每次回调都会调用next(),除了第一次是手动调用外
        getDate.next(res);
    })
}
function* gen() {
    let res1 = yield request('./static/a.json');
    console.log(res1);//a
    let res2 = yield request('./static/b.json');
    console.log(res2);//b
    let res3 = yield request('./static/c.json');
    console.log(res3);//c
}
let getDate = gen();
getDate.next();//
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值