美文网首页
异步相关

异步相关

作者: 我家有个王胖胖 | 来源:发表于2022-03-10 21:32 被阅读0次

    一:同步异步
    XmlHttpRequest:

    let url = 'static/a.json';
    let xmlHttpRequest;
    if(window.XMLHttpRequest){
        xmlHttpRequest = new XMLHttpRequest();
    }else{//兼容旧版本
        xmlHttpRequest = new ActiveXObject('Microsoft.XMLHTTP')
    }
    xmlHttpRequest.open('GET',url,true);
    xmlHttpRequest.send();
    xmlHttpRequest.onreadystatechange = function() {
        if(xmlHttpRequest.readyState === 4 && xmlHttpRequest.status === 200){
           let obj = JSON.parse(xmlHttpRequest.responseText);
            console.log(obj);
        }
    }
    //{a: '我是A'}
    

    Ajax原理:

    //ajax的简单封装
    let a = 'static/a.json';
    
    
    function ajax(url,method,callback) {
        let xmlHttpRequest;
        if (window.XMLHttpRequest) {
            xmlHttpRequest = new XMLHttpRequest();
        } else {//兼容旧版本
            xmlHttpRequest = new ActiveXObject('Microsoft.XMLHTTP')
        }
        xmlHttpRequest.open(method, url, true);
        xmlHttpRequest.send();
        xmlHttpRequest.onreadystatechange = function () {
            if (xmlHttpRequest.readyState === 4 && xmlHttpRequest.status === 200) {
                let obj = JSON.parse(xmlHttpRequest.responseText);
                callback(obj)
            }
        }
    }
    ajax(a,'GET',res=>{
        console.log(res);//{a: '我是A'}
    })
    

    a->b->c
    地狱回调问题:

    ajax(a, 'GET', res => {
        console.log("aaa---", res);
        ajax(b, 'GET', res => {
            console.log("bbb---", res);
            ajax(c, 'GET', res => {
                console.log("ccc---", res);
            })
        })
    })
    aaa--- {a: '我是A'}
    bbb--- {b: '我是B'}
    ccc--- {c: '我是C'}
    

    Promise解决回调地狱:

    //基于上面的ajax的封装,我们进一步通过promise解决回调问题
    //获取promise
    function getPromise(url,method){
        return new Promise((resolve,reject)=>{
            ajax(url,method,res=>{
                resolve(res)
            })
        })
    }
    getPromise(a,"GET").then(res=>{
        console.log(res);
        return getPromise(b,'GET');
    }).then(res => {
        console.log(res);
        return getPromise(c,'GET');
    }).then(res=>{
        console.log(res);
    })
    

    案例:promise加载图片

    const url = 'https://m.360buyimg.com/babel/jfs/t1/145983/4/5065/136336/5f313fcfEa5213607/170f4951fa1a845e.jpg.webp'
    const url2 = 'https://img12.360buyimg.com/pop/s590x470_jfs/t1/136750/17/3835/71376/5f0434ecE1e5daa8d/7ab8f3deb1f8dd62.jpg.webp'
    const wrapper = document.querySelector('#wrapper')
    function loadImage(imgUrl) {
        let p = new Promise((resolve, reject) => {
            //let img = document.createElement("img");
            let img = new Image();
            img.onload = () => resolve(img);
            img.onerror = () => {
                let error = new Error("加载失败")
                reject(error);
            };
    img.src = imgUrl;
            img.height = 200 
            img.width = 200 
        })
        return p;
    }
    loadImage(url).then(res=>{
        wrapper.appendChild(res)
        return loadImage(url2);
    }).then(res=>{
        wrapper.appendChild(res)
    }).catch(err=>{
        console.log(err.error,message);
    })
    

    效果:

    promise加载图片.png
    Promise的静态方法
    ①Promise.resolve
    ②Promise.reject
    ③Promise.all
    ④Promise.race
    Promise.all():Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值。
    //上传图片
    let imgArr = ['https://m.360buyimg.com/babel/jfs/t1/145983/4/5065/136336/5f313fcfEa5213607/170f4951fa1a845e.jpg.webp', 'https://img12.360buyimg.com/pop/s590x470_jfs/t1/136750/17/3835/71376/5f0434ecE1e5daa8d/7ab8f3deb1f8dd62.jpg.webp'];
    let pushArr = [];
    imgArr.forEach(item => {
        pushArr.push(new Promise((resolve, reject) => {
            resolve(item)//模拟上传后端
        }))
    })
    Promise.all(pushArr).then(result=>{
        console.log(result);
        console.log('图上上传成功');
    })
    

    效果:


    Promise.all().png

    Promise.race():顾名思义,Promse.race就是赛跑的意思,意思就是说,Promise.race([p1, p2, p3])里面哪个结果获得的快,就返回那个结果,不管结果本身是成功状态还是失败状态。

    let url = 'https://m.360buyimg.com/babel/jfs/t1/145983/4/5065/136336/5f313fcfEa5213607/170f4951fa1a845e.jpg.webp'
    
    function loadImg() {
        let p1 = new Promise((resolve, reject) => {
            let img = new Image();
            img.onload = function() {
                resolve('图片加载成功')
            }
            img.src = url;
        })
        return p1
    }
    
    function delay() {
        let p2 = new Promise((resolve, reject) => {
            setTimeout(() => {
                reject('图片加载失败')
            }, 2000)
        })
        return p2
    }
    Promise.race([loadImg(), delay()]).then(result => {
        console.log(result);
    })
    

    Generator函数:
    概念
        Generator 函数是 ES6 提供的一种异步编程解决方案。它既是一个生成器,也是一个状态机,内部拥有值及相关的状态,生成器返回一个迭代器 Iterator 对象,我们可以通过这个迭代器,手动地遍历相关的值、状态,保证正确的执行顺序。

    特征
    function 关键字与函数名之间有一个星号(ES6 没有规定,function 关键字与函数名之间的星号,写在哪个位置)
    函数体内部使用 yield 表达式,定义不同的内部状态
    调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是遍历器对象(Iterator Object)

    function* sum(a) {
        let x = yield 1 + a;//6
        let y = yield 2 + x;//8
        return x + y;//16
    }
    //next()中参数会作为上一个yield表达式的返回值 
    let sum1 = sum(5);
    console.log(sum1.next());//{value: 6, done: false}
    console.log(sum1.next(6));//{value: 8, done: false}
    console.log(sum1.next(10));//{value: 16, done: done}
    

    yield 表达式和 next() 方法
        由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield 表达式就是暂停标志。

    遍历器对象的next方法的运行逻辑:

    遇到 yield 表达式,就暂停执行后面的操作,并将紧跟在 yield 后面的那个表达式的值,作为返回的对象的 value 属性值
    下一次调用 next() 方法时,再继续往下执行,直到遇到下一个 yield 表达式.
    如果没有再遇到新的 yield 表达式,就一直运行到函数结束,直到 return 语句为止,并将 return 语句后面的表达式的值,作为返回的对象的 value 属性值.
    如果该函数没有 return 语句,则返回的对象的 value 属性值为 undefined
    注意:

    yield 表达式后面的表达式,只有当调用next()方法、内部指针指向该语句时才会执行.
    yield 语句只能用于 function* 的作用域,如果 function* 的内部还定义了其他的普通函数,则函数内部不允许使用 yield 语句.
    yield 语句如果参与运算,必须用括号括起来.

    next() 方法的参数:
    yield 表达式本身没有返回值,或者说总是返回undefined
    next() 方法可以带一个参数,该参数会改变上一个yield表达式的返回值
    Iterator:

    Iterator.png
    //模拟iterator的过程
    function makeIterator(arr) {
        let nextIndex = 0;
        return {
            next() {
                return nextIndex < arr.length ? {value:arr[nextIndex++],done:false} : {value:undefined,done:true}
            }
        }
    }
    let it = makeIterator([1,2,3])
    console.log(it.next());//{value: 1, done: false}
    console.log(it.next());//{value: 2, done: false}
    console.log(it.next());//{value: 3, done: false}
    console.log(it.next());//{value: undefined, done: true}
    
    

    原生具有iterator接口的数据结构


    原生具有iterator接口的数据结构.png

    对象使用for...of

    let obj = {
            0:"我是0",
            1:"我是1",
            2:"我是2",
            length:3,
            //添加[Symbol.iterator]方法
            [Symbol.iterator] : function() {
                let _this = this;
                let index = 0;
                return {
                    next:() => {
                        let value = _this[index];
                        let done = (index >= _this.length);
                        index++;
                        return {value,done}
                    }
                }
            }
        };
    
        //咱们来for...of一下
        for(let v of obj){
            console.log(v);
        }
        //结果:"我是0"
        //      "我是1"
        //      "我是2"
    

    Module:
    AMD,CMD,CommonJS,ES6的区别

    相关文章

      网友评论

          本文标题:异步相关

          本文链接:https://www.haomeiwen.com/subject/sufqdrtx.html