zoukankan      html  css  js  c++  java
  • promise系列(一)

    1.同步回调和异步回调

        <script>
            // 同步回调
            let arr = [1,2,3,4,5];
            //对数组的每一个元素 * 10 返回新数组  forEach filter some every
            let newArr = arr.map(item => {
                // console.log(0);
                return item * 10;
            });
    
    
            // 异步回调 promise 回调 $.get(url, data, callback)  fs模块 readFile  readdir 
            setTimeout(() => {
                console.log(0);
            }, 1000);
    
            console.log(1);
    
    
        </script>

    2.错误类型

    <script>
        /**
         *  1.    Error: 所有错误的父类型
            2.    ReferenceError: 引用的变量不存在
            3.    TypeError: 数据类型不正确的错误
            4.    RangeError: 数据值不在其所允许的范围内
            5.    SyntaxError: 语法错误
         */
    
        // ReferenceError  引用错误
        //  console.log(abc);
    
        // TypeError 类型错误
        // let obj = {};
        // obj();
    
        // RangeError 范围
        // let arr = new Array(-1);//长度
        // console.log(arr);
    
        // SyntaxError 语法错误
        // abcxxx(xxxxa'*9s);
    
    
    </script>

    3.try...catch 处理错误

       <script>
            /**
             * 语法固定 try...catch   try 尝试的意思  catch 捕获
             * 1. try catch捕获到错误之后, 后续代码可以继续执行
             * 2. catch 可以将错误信息捕获到. e 是一个对象, 有message和stack两个属性
             * 3. 抛出错误之后, 在后续的 try 里面的代码不会执行
             * 4. try 不能捕获语法错误. 其他三种类型错误可以捕获.
             * 5. 允许使用 throw 手动的抛出错误
             * 6. 抛出任意类型的数据
             */
    
            try {
                // console.log(a;//不能捕获到语法错误
                let a = 100;
                let b = 0;
                if(b === 0) {
                    //手动抛出错误对象
                    // throw new Error('除数不能为 0');
                    throw "除数不能为 0 ";
                }
                let result = a / b;
                console.log("lalala");
            } catch (e) {
                console.log(e);
                console.log(e.message);
                console.log(e.stack);
                //处理错误的方式 
                //1. 写入日志文件
                //2. 错误提醒
            }
    
            console.log('ok');
    
    
    
        </script>

    同步代码和异步代码处理错误

     <script>
            // 同步代码抛出错误  => 可以捕获
            // function fn() {
            //     console.log(a);
            // }
    
            // try {
            //     fn(); //非手动捕获
            // } catch (e) {
            //     console.log(e.message);
            // }
    
    
            // 异步代码抛出错误  => 不能这样捕获
            // function fn() {
            //     setTimeout(() => {
            //         console.log(a);
            //     }, 1000)
            // }
            // try {
            //     fn();
            // } catch (e) {
            //     console.log(e.message);
            // }
            // console.log('test');
    
            //异步代码捕获错误的方式
            // function fn() {
            //     setTimeout(() => {
            //         try {
            //             console.log(a);
            //         } catch (e) {
            //             console.log(e.message);
            //         }
            //     }, 1000)
            // }
            // fn();
    
        </script>

    Promise基础使用

    <script>
        // 2s后 随机生成一个数字  
        // 如果是偶数则成功(弹框数字,中奖啦), 
        // 如果是奇数失败(控制台输出数字)
    
        // setTimeout(() => {
        //     //获取时间戳
        //     let n = Date.now();
        //     //
        //     if(n % 2=== 0){
        //         //成功  值
        //         alert(n + '中奖啦! 中奖啦! 笔记本和台式机有戏啦!!');
        //     }else{
        //         //失败  值
        //         console.log(n, "下次再接再厉!!");
        //     }
        // }, 2000);
    
        //Promise 实现
        // let a = new Person("xiaohigh");
        //成功和失败的值, p 对象出了有状态属性(status), 还有一个值的属性(value)
        let p = new Promise(function(resolve, reject){
            //定时器
            setTimeout(() => {
                let n = Date.now();
                if(n % 2 === 0){
                    //成功
                    resolve(n);
                }else{
                    //失败
                    reject(n);
                }
            }, 2000)
        });
    
        // 形参的潜规则名称 value 与 reason
        p.then(function(value){
            alert("中奖啦!! oh year"+n);
        }, function(reason){
            console.log("再接再厉"+n);
        });
    
    
    </script>

    2

    //读取一个文件内容  ./resource/1.html
    const fs = require("fs");
    
    // fs.readFile("./resource/1.html", (err, data) => {
    //     if(err){
    //         console.log(err);
    //         return;
    //     }
    //     console.log(data.toString());
    // });
    
    //Promise 的方式
    let p = new Promise((resolve, reject) => {
        fs.readFile("./resource/1-33.html", (err, data) => {
            //判断是否出现错误
            if(err) reject(err);
            resolve(data);
        });
    });
    
    //then 方法处理成功或失败的值
    p.then((value) =>{
        console.log(value.toString());
    }, (reason)=>{
        console.error(reason.code);
    });

    3

    //读取 1.html 和 2.html 合并输出到控制台
    const fs = require("fs");
    
    //回调函数的形式处理,回调地狱,特点,外层的函数的结果是内层函数的条件
    // fs.readFile("./resource/1.html", (err, data1)=>{
    //     if(err) throw err;// 直接抛出错误, 如果这里抛出错误, 则代码会停止
    //     fs.readFile("./resource/2.html", (err, data2) => {
    //         if(err) throw err;
    //         fs.readFile("./resource/3.html", (err, data3)=>{
    //             if(err) throw err;
    //             console.log(data1 + data2 + data3);
    //         })
    //     });
    // });
    
    //Promise 形式
    let p = new Promise((resolve, reject) => {
        //读取 1.html 文件内容
        fs.readFile("./resource/1.html", (err, data) => {
            if (err) reject(err);
            resolve(data);
        });
    });
    
    //第二个文件读取 value 为 1.html 的文件内容
    //p2为返回的新的promise实例化对象
    let p2 = p.then(value => {  //value为1.html的内容,//value是buffer类型数据
        //返回一个 新的Promise 对象
        return new Promise((resolve, reject) => {
            fs.readFile("./resource/2.html", (err, data) => {
                if(err) reject(err);
                resolve(value + data);
            });
        });
    }, reason => {
    
    });
    
    //读取 3.html 的文件内容
    let p3 = p2.then(value => {  //value 为p2中正确状态的值,1.html和2.html的数据
        //value是字符串类型数据,buffer类型相加是字符串类型
        return new Promise((resolve, reject)=>{
            fs.readFile("./resource/3.html", (err, data)=>{
                if(err) reject(err);
                resolve(value + data);
            });
        })
    }, reason => {
    
    });
    
    p3.then(value => {  //value 为p3中正确状态的值,1.html和2.html和3.html的数据
        console.log(value); //value是字符串类型数据
    },reason => {
    
    })

    4

    //读取 1.html 和 2.html 3.html 合并输出到控制台
    const fs = require("fs");
    
    //Promise 形式
    let p1 = new Promise((resolve, reject) => {
        //读取 1.html 文件内容
        fs.readFile("./resource/1.html", (err, data) => {
            if (err) reject(err);
            resolve(data.toString());
        });
    });
    let p2 = new Promise((resolve, reject)=>{
        //读取 2.html 文件内容
        fs.readFile("./resource/2.html", (err, data) => {
            if (err) reject(err);
            // console.log('dg')  //失败的promise,还是会向下执行代码
            resolve(data.toString());
        });
    });
    let p3 = new Promise((resolve, reject)=>{
        //读取 3.html 文件内容
        fs.readFile("./resource/3.html", (err, data) => {
            if (err) reject(err);
            resolve(data.toString());
        });
    });
    
    //只要有一个状态是失败的,p就是失败的promise
    let p = Promise.all([p1, p2, p3]);
    
    p.then(value => {
        // console.log(value)  //value此时是数组,是偏p1,p2,p3的值得累加
    
         // join()方法将一个数组(或一个类数组对象)的所有元素根据传入的参数连接成一个字符串,并返回这个字符串。
        // 参数:
    
        // 指定一个字符串来分割数组(类数组)的每个元素
    
        // 如果省略(),数组元素默认以逗号分隔。默认为","
    
        // 如果为(""),则表示所有元素之间不存在任何字符
        console.log(value.join(''));
    },reason=>{
        console.log(reason)
    });

    5.promise封装ajax请求

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Promise封装AJAX请求</title>
        <script crossorigin="anonymous" src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    </head>
    
    <body>
        <button id="btn">点击发送 AJAX 请求</button>
        <script>
            // $.get('/server', {}, function(){
            // })
            /*
                封装一个函数 promiseAJAX  只实现 GET 请求
                用来发送 AJAX 请求
                返回 Promise 对象
            */
                //method = "GET", 函数默认参数,promiseAJAX()就是promise对象
            function promiseAJAX({ url,data={name:'maco'}, method = "GET" }) {  //对象解构
                // console.log(url)
                // console.log(method)
                // console.log(data)
                  //返回promise实例对象
                return new Promise((resolve, reject) => {
                    // 创建ajax实例对象
                    let x = new XMLHttpRequest();
                    //初始化
                    x.open(method, url);
                    //发送
                    x.send();
                    //绑定事件, 处理响应结果
                    //只有ajax的状态改变了,才会触发该事件onreadystatechange 
                    x.onreadystatechange = function () {// 1->2 2->3  3-> 4
                        //只有状态为 4 的时候, 才能对 Promise 对象状态进行设置
                        if (x.readyState === 4) {
                            //请求成功 2xx 都标识成功   3 重定向   4 客户端错误  5 服务端错误
                            if (x.status >= 200 && x.status < 300) {
                                //成功的话, 将promise对象的状态设置为成功, 并将响应体设置为 promise 对象成功的值
                                resolve(x.response);
                            } else {
                                //失败的话
                                reject(x.status);
                            }
                        }
    
                    }
                });
            }
    
            btn.onclick = function () {
                //原生ajax-cors跨域,服务器的响应头设置了可跨域
                let url = 'https://www.tianqiapi.com/api/?version=v1&city=%E5%8C%97%E4%BA%AC&appid=23941491&appsecret=TXoD5e8P';
                promiseAJAX({
                    url: url
                }).then(value => {
                    // 将字符窜转换成对象
                    let data=JSON.parse(value)
                    console.log(data);
                });
            }
    
    
        </script>
    </body>
    
    </html>

    6.异步API的promsie形态

    /*
        封装一个函数 mineReadFile , 读取文件并返回一个 promise 对象
     */
    const fs = require("fs");
    
    function mineReadFile(path) {
        //返回promise对象
        return new Promise((resolve, reject)=>{
            //使用 fs 模块读取文件内容
            fs.readFile(path, (err, data) => {
                //如果失败 则修改promise对象状态为失败
                if(err) reject(err);
                // 如果成功, 则修改promise对象状态为成功
                resolve(data);
            })
        });
    }
    
    mineReadFile('./resource/xxx.html').then(value => {
        console.log(value.toString());
    }, reason => {
        console.log(reason.code);
    });

    7.promise的API

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Promise的API</title>
    </head>
    
    <body>
    
        <script>
            //  function Promise(executor){
    
            //  }
            /**
             * 1. Promise 的实例化接收一个 函数类型的参数( 执行器函数 )
             * 2. resolve和 reject 两个形参类型都是 函数.
             * 3. 执行器函数是一个同步的回调函数
             */
            // 1. 执行器函数式同步调用的,但是里头的异步任务是不同步的
            // let p =new Promise((resolve, reject) => {
            //     //同步调用
            //     console.log(111);
            //     //异步调用
            //     setTimeout(()=>{
            //         console.log(333);
            //         // reject("失败的数据");
            //     }, 1000);
            // });
            // console.log(222);
            // 执行顺序, 输出,111, 222, 333
    
            // 2. Promise.prototype.then
            //成功的回调 onResolved  on 当...时候  resolved 已解决
            //失败的回调 onRejected                rejected 拒绝了的 失败了
            // then方法返回的是一个promise对象,后面还可以加.
            // p.then(value=>{
    
            // }, reason=>{
    
            // }).then(value=>{
    
            // }).then(value=> {
    
            // });
    
            // 3. Promise.prototype.catch  实例对象上可以使用 catch 方法
            // p.catch(reason => {
            //     console.error(reason);
            // });
    
            // 4. Promise.resolve resolve 是一个方法, 返回是一个 Promise 对象
    
            // 4-1 参数如果为非 Promise 类型的数据, 则返回的 Promise 对象为成功的状态
             // let p10=Promise.resolve('hrllow')
            // console.log(p10)  //Promise { 'hrllow' }
            // p10.then((value)=>{ 
            //     console.log(value)   //hrllow
            // })
    
    
            // 4-2 参数如果是成功的 Promise, 则返回的 Promise 对象结果状态也为成功, 
            // 并且返回的成功的promise的值, 为传入参数的成功的值
            // let p1 = new Promise((resolve, reject)=>{
            //     resolve('成功的数据');
            // });
            // let p3 = Promise.resolve(p1); //Promise { '成功的数据' }
            // p3.then(value=>{
            //     console.log(value)  //成功的数据
            // })
    
    
            // 4-3 如果参数为失败的 Promise, 则返回的是失败的 Promise 对象
            // 返回的值,报错
            let p11 = new Promise((resolve, reject) => {
                reject("失败的数据111");
            });
            let p4 = Promise.resolve(p11);
            console.log(p4); //Promise { <rejected> '失败的数据111' }
            // p4.then(value=>{
            //     console.log(value)  // Uncaught (in promise) 失败的数据111
            // })
    
            p4.catch(reason=>{
                console.log(reason)  //失败的数据111
            })
            
    
    
            // 5-1. Promise.reject 参数为成功的promise对象,返回失败的 Promise 对象, 返回的值是一个失败原因的对象
            
            // let p0 = new Promise((resolve, reject)=>{
            //     resolve('成功的数据');
            // });
            // let p2 = Promise.reject(p0);
            // console.log(p2);  //Promise {<rejected>: Promise}
            // p2.catch( reason=>{
            //     console.log(reason) //Promise {<resolved>: "成功的数据"}
            // })
    
    
            // 5-2. Promise.reject 参数为失败的promise对象,返回失败的 Promise 对象, 返回的值是一个失败原因的对象
            // let p20 = new Promise((resolve, reject)=>{
            //     reject('成功的数据');
            // });
            // let p21 = Promise.reject(p20);
            // console.log(p21);  //Promise {<rejected>: Promise}
            // p21.catch( reason=>{
            //     console.log(reason) //Promise {<rejected>: "成功的数据"}
            // })
    
            //5-3,Promise.reject 参数为非promise数据,返回失败的 Promise 对象, 返回的值为失败的值
            // let p6=Promise.reject('ABN')
            // console.log(p6)  //Promise {<rejected>: "ABN"}
            // p6.catch(reason=>{
            //     console.log(reason)  //ABN
            // })
          
    
            // 6. Promise.all, 
            // let one = new Promise((resolve, reject) => {
            //     // reject('数据库用户的数据');
            //     // resolve('数据库用户的数据');
    
            
            // });
            // let two = Promise.resolve("订单数据");
            // let three = Promise.resolve("商品数据");
    
            // Promise.all函数的数组参数的promise如果都是成功的状态,那么p1也是成功的promise,而他的返回值是数组
            // 如果有一个参数是失败的promise,那么p1就是失败的promise,
            // let p1 = Promise.all([one, two, three]); 
            // console.log(p1)  //Promise {resolved}
            // p1.then(value=>{
            //     console.log(value) //[ '数据库用户的数据', '订单数据', '商品数据' ]
            // })
    
    
            // 7. Promise.race race 赛跑的意思,
            let one = new Promise((resolve, reject) => {
                reject('数据库用户的数据');
                //异步调用
                // setTimeout(() => {
                //     reject('数据库用户的数据');
                // }, 1000);
            });
            let two = Promise.reject("订单数据");
            // let two = Promise.resolve("订单数据");
            let three = Promise.resolve("商品数据");
    
            //Promise.race函数的数组里头的参数,p1的状态初始是pending默认状态,那个promise状态第一个先改变,p1的状态就会跟着改变
            // 返回的值就是那个引起变化的promise的值,偏
            let p1 = Promise.race([one, two, three]);
    
            console.log(p1);  
            p1.then(value=>{
                console.log(value)
            },reason=>{
                console.log(reason)
            })
    
        </script>
    </body>
    
    </html>

    8.如何改变promsie的状态

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>关键问题</title>
    </head>
    
    <body>
        <script>
            let p = new Promise((resolve, reject) => {
                //1. resolve  //"pending"状态的promise
                // resolve('数据');  //resolved
                //2. reject
                // reject('错误');   //rejected"
                //3. 抛出错误,会改变promise的状态
                // throw new Error("出错啦!!");   //rejected"
                // throw "出错啦!!";   //"rejected"
                //4. 异步回调 异步回调中抛出错误 不能改变 promise 对象状态
                // 但是里头加入try,catch即可捕获到错误,就能改变promise的状态
                //异步任务
                // setTimeout(()=>{
                //     reject('失败')  //rejected
                // },1000)
    
                // setTimeout(()=>{
                //     throw '出错了'  // "pending,未改变状态
                // },1000)
    
                setTimeout(()=>{
    
                    try{
                        throw '出错了' ;
                    }catch(e){
                        reject(e)  //"rejected
                    }
    
                },1000)
            })
    
            console.log(p);
    
        </script>
    </body>
    
    </html>

    9、改变状态和与指定回调谁先谁后

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>关键问题</title>
    </head>
    
    <body>
        <script>
    
        // 改变promise状态和指定回调函数谁先谁后?
        // 1.如果promise中有异步任务,那么先调用then()指定里头的回调,然后在改变promise状态,
        // 然后返回改变状态的值。这种居多,因为promise里头就是封装异步任务的。
    
        // 2.如果promise中有没有异步任务,那么先改变promise状态,然后调用then()指定里头的回调,
        // 然后返回改变状态的值
    
        //3.then()方法里头的回调函数也是异步任务
        
    
    
            let p = new Promise((resolve, reject) => {
                //异步任务
                // setTimeout(() => {
                //     console.log(111);
                //     resolve("OK");
                // }, 2000);
                //同步任务
                console.log(111);
                resolve("OK");
            });
    
            console.log(222);
            p.then(value => {
                console.log(value);
            })
    
            console.log(333)
        </script>
    </body>
    
    </html>

    10.then 方法返回结果特点

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>关键问题</title>
    </head>
    <body>
    <script>
        let p = new Promise((resolve, reject)=>{
            // resolve('成功')
            reject('失败');
        });
    
        //由then()指定的回调函数执行的结果决定 
        let result = p.then(value => {
            //1. 抛出错误 ,返回的就是reject状态的promise
            // throw "错误!!";  //"rejected"状态的promise
    
            //2. 返回非 Promise 类型的对象,如果没有return结果,也是resolved状态
            // return 123;  //"resolved状态的promise,
    
            //3. 返回 Promise 类型的对象
            return new Promise((resolve, reject)=>{
                // 成功的情况
                // resolve("OK");  //resolved状态的promise,值就是result的值
                // 失败的情况 
                reject('Error');  //rejected状态的promise
            });
        }, reason => {
            console.log(reason) //失败
            return 444  //resolved状态的promise,值就是444,没有return结果,也是resolved状态的promise
        });
    
        console.log(result);
    </script>
    </body>
    </html>

    11.then方法链式调用

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>关键问题</title>
    </head>
    
    <body>
        <script>
            let p = new Promise((resolve, reject)=>{
                // resolve('000');
                reject('出错')
            });
    
            let p2= p.then(value => {
                console.log(value);  //000
                return 111;   //返回状态为resolve,值为111的promise
            },reason => {
                console.error(reason);  //出错
                return 222;  ////返回状态为resolve,值为222的promise
            })
            .then(value => {
                console.log(value);  //111  /222
                return 333;  //返回状态为resolve,值为333的promise
            },reason=>{
                console.error(reason) 
    
            })
            .then(value => {
                console.log(value);  //333
                return 444;  //返回状态为resolve,值444的promise
            });
    
            console.log(p2)  //Promise {<resolve>},值为444
        </script>
    </body>
    
    </html>
    12.异常穿透
    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>关键问题</title>
    </head>
    
    <body>
        <script>
            // 如果出现了状态为rejcet的promise,调用then方法,如果没有写明第二个回调函数,会忽略,
            // 直到遇到catch(),才会执行。异常穿透
    
            let p = new Promise((resolve, reject) => {
                resolve('000');
                // reject('失败ooo');
            });
    
            p.then(value => {
                console.log(value);
                throw "Error";
            }).then(value => {
                console.log(value);
                return 333;
            }).then(value => {
                console.log(value);
                return 444;
            }).then(value=> {
                console.log(value);
            }).catch(reason => {
                console.log(reason);
            });
        </script>
    </body>
    
    </html>

    13.中断promise链

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
            content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>关键问题</title>
    </head>
    
    <body>
        <script>
    
    //     如何当使用promise的then链式调用时, 在中间中断, 不再调用后面的回调函数
    //     办法: 在回调函数中返回一个pendding状态的promise对象
    
            let p = new Promise((resolve, reject) => {
                resolve('000');
                // reject('失败ooo');
            });
    
            p.then(value => {
                console.log(value);
                return 111;
            }).then(value => {
                console.log(value);
                return 222;
            }).then(value => {
                console.log(value);
                // 在回调函数中返回一个pendding状态的promise对象
                return new Promise((resolve, reject)=>{});
            }).then(value => {
                console.log(value);
            }).catch(reason => {
                console.log(reason);
            });
        </script>
    </body>
    
    </html>
  • 相关阅读:
    VS2010中连接sdf数据库的字符串 Kevin
    找不到请求的 .Net Framework Data Provider。可能没有安装 Kevin
    MVC项目中找不到 DbContext 命名空间 Kevin
    Something About Assert()——C#中的断言 Kevin
    Html.Partial vs Html.RenderPartial & Html.Action vs Html.RenderAction Kevin
    .NET 中的双问号 Kevin
    苹果公司一道面试题 Kevin
    The diffrence between TempData and ViewBag and ViewData Kevin
    GRUB整体分析
    忠诚的成本看房产大鳄冯仑如何处理看待忠诚
  • 原文地址:https://www.cnblogs.com/fsg6/p/14549764.html
Copyright © 2011-2022 走看看