Rumah  >  Artikel  >  Fahami janji/async menanti dalam satu artikel dan kejar 70% orang hadapan

Fahami janji/async menanti dalam satu artikel dan kejar 70% orang hadapan

青灯夜游
青灯夜游ke hadapan
2022-09-28 10:39:462704semak imbas

Hari ini saya akan berkongsi janji dengan anda Pengarang akan bermula dengan dilema kod tak segerak awal, apakah masalah kemunculan janji yang diselesaikan, penyelesaian muktamad kepada neraka panggilan balik tak segerak, dan melaksanakan sintaks teras async menanti , async/wait hanyalah satu varian janji penjana.

1. Dilema kod tak segerak awal

  • Seperti yang kita semua tahu, js adalah satu benang dan operasi yang memakan masa dikendalikan oleh pelayar. Apabila masanya tamat, keluarkan pelaksanaan dari baris gilir dan reka konsep gelung acara. Anda boleh membacanya di bawah, anda boleh memahaminya dengan lebih baik promise .
  • Saya menggunakan keperluan sebagai titik permulaan dan saya mensimulasikan permintaan rangkaian (operasi tak segerak)
    • Jika permintaan rangkaian berjaya, anda beritahu saya bahawa ia berjaya
    • Jika permintaan rangkaian gagal , anda memberitahu saya bahawa saya gagal

1.1 Pendekatan pintar

function requestData(url) {
  setTimeout(() => {
    if (url === 'iceweb.io') {
      return '请求成功'
    }
    return '请求失败'
  }, 3000)
}

const result = requestData('iceweb.io')

console.log(result) //undefined
  • Mula-mula anda kena fahamjs Perintah pelaksanaan kod bukanlah sesuatu yang anda ambil mudah Kod itu sebenarnya tidak dilaksanakan mengikut susunan yang anda tulis.
  • Jadi kenapa undefined呢?
    • Pertama apabila saya melaksanakan fungsi requestData, fungsi itu mula dilaksanakan. Menghadapi operasi tak segerak tidak akan menyekat pelaksanaan kod berikut, kerana js adalah satu-benang, jadi kejayaan atau kegagalan return yang anda tulis tidak akan kembali dalam fungsi ini, tidak kira operasi tak segerak. Jadi nilainya ialah undefined.

2.2 Amalan Betul Awal

function requestData(url, successCB, failureCB) {
  setTimeout(() => {
    if (url === 'iceweb.io') {
      successCB('我成功了,把获取到的数据传出去', [{name:'ice', age:22}])
    } else {
      failureCB('url错误,请求失败')
    }
  }, 3000)
}

//3s后 回调successCB 
//我成功了,把获取到的数据传出去 [ { name: 'ice', age: 22 } ]
requestData('iceweb.io', (res, data) => console.log(res, data), rej => console.log(rej))

//3s后回调failureCB
//url错误,请求失败
requestData('icexxx.io', res => console.log(res) ,rej => console.log(rej))
  • Penyelesaian awal perlu lulus dalam dua panggilan balik, satu daripadanya gagal Ya, yang berjaya. Kemudian ramai pembangun akan bertanya, bukankah ini hebat? Ia agak mudah. ​​Fungsi dalam js adalah warga kelas pertama dan boleh disebarkan, tetapi ini terlalu fleksibel dan tidak mempunyai spesifikasi.
  • Jika anda menggunakan rangka kerja, anda juga harus membaca kod sumber rangka kerja untuk menghantar parameter sebenar dalam susunan yang salah Amat berbahaya jika parameter dihantar dalam susunan yang salah.

2. Janji

  • Promise (janji), beri janji kepada pemanggil dan kembalikan data kepada anda selepas beberapa ketika. Cipta objek janji
  • Apabila kita new promise, kita perlu menghantar fungsi panggil balik Fungsi ini dilaksanakan dengan segera, dipanggil (pelaksana)
  • fungsi panggil balik ini, kita perlukan. untuk menghantar dalam dua fungsi panggil balik parameter, reslove, reject (fungsi boleh lulus parameter)
    • Apabila fungsi reslove dilaksanakan, fungsi .then bagi objek promise
    • Apabila fungsi
    • dilaksanakan, fungsi .catche objek janji akan dipanggil semula reject

2.1 Pelaksana dilaksanakan serta-merta

new Promise((resolve, reject) => {
  console.log(`executor 立即执行`)
})
    Yang diluluskan dalam
  • dilaksanakan serta-merta executor

2.2 permintaan Pembinaan semula data

function requestData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (url === 'iceweb.io') {
        //只能传递一个参数
        resolve('我成功了,把获取到的数据传出去')
      } else {
        reject('url错误,请求失败')
      }
    }, 3000)    
  })
}

//1. 请求成功
requestData('iceweb.io').then(res => {
  //我成功了,把获取到的数据传出去
  console.log(res)
})

//2. 请求失败

//2.2 第一种写法
//url错误,请求失败
requestData('iceweb.org').then(res => {},rej => console.log(rej))

//2.2 第二种写法
//url错误,请求失败
requestData('iceweb.org').catch(e => console.log(e))
    dalam fungsi , dalam kelas baharu, fungsi panggil balik yang diluluskan dipanggil
  • (ia akan dilaksanakan secara automatik dalam kelas Promise) executor
  • memanggil fungsi
  • apabila ia betul, dan memanggil Fungsi, lulus parameter yang diperlukan. resolverejectPengendalian pengecualian
  • Dua panggilan balik boleh dihantar dalam kaedah
      Anda juga boleh melihat
    • Promise/A .thenSpesifikasiYang Pertama ialah. panggilan balik
      • fulfilledYang kedua ialah panggilan balik
      • rejected
    Jadi apakah faedahnya? Adakah ia kelihatan lebih rumit daripada penyelesaian awal?
    • Spesifikasi bersatu boleh meningkatkan kebolehbacaan dan kebolehskalaan
    • Kurangkan sedikit panggilan balik
2.3 Status Janji

Pertama sekali, saya akan memberi anda buah berangan dan abstrak kod tersebut ke dalam bentuk berangan yang realistik
    Janji dengan teman wanita anda bahawa anda akan membawanya makan makanan yang lazat pada hujung minggu depan (belum hujung minggu depan, dan statusnya
  • Belum selesai
      )
    • Masa berlalu begitu pantas hujung minggu anda dan teman wanita anda makan barbeku, pencuci mulut dan teh susu bersama-sama... ( Status tunai
    • )
    • Masa berlalu, hari ini hujung minggu, dan anda akan keluar . Malangnya, pengurus produk perlu kembali kepada syarikat untuk menyelesaikan masalah mendesak yang berlaku dalam talian Anda (demi kehidupan) hanya boleh menolak teman wanita anda dengan sopan dan menjelaskan sebabnya (Status ditolak
    • )<.>
    • Apabila menggunakan
    • , beri janji Kami boleh membahagikannya kepada tiga peringkat
  • pending (pending), pelaksana dilaksanakan, dan statusnya. masih menunggu. , belum dihormati atau ditolak
  • promisedipenuhi (dipenuhi), dilaksanakan
      fungsi mewakili status dipenuhi
    • ditolak (ditolak), dilaksanakan
    • Fungsi mewakili status ditolak resolve
    • rejectPertama sekali, selagi status bertukar daripada status belum selesai kepada status lain, status tidak boleh ditukar
  • Fikirkan perkara berikut kod:
  • const promise = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('失败')
        resolve('成功')
      }, 3000);
    })
    
    promise.then(res => console.log(res)).catch(err => console.log(err))
    
    //失败
    • 当我调用reject之后,在调用resolve是无效的,因为状态已经发生改变,并且是不可逆的。

    2.4 resolve不同值的区别

    • 如果resolve传入一个普通的值或者对象,只能传递接受一个参数,那么这个值会作为then回调的参数
    const promise = new Promise((resolve, reject) => {
      resolve({name: 'ice', age: 22})
    })
    
    promise.then(res => console.log(res))
    
    // {name: 'ice', age: 22}
    • 如果resolve中传入的是另外一个Promise,那么这个新Promise会决定原Promise的状态
    const promise = new Promise((resolve, reject) => {
      resolve(new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('ice')
        }, 3000);
      }))
    })
    
    promise.then(res => console.log(res))
    
    //3s后 ice
    • 如果resolve中传入的是一个对象,并且这个对象有实现then方法,那么会执行该then方法,then方法会传入resolvereject函数。此时的promise状态取决于你调用了resolve,还是reject函数。这种模式也称之为: thenable
    const promise = new Promise((resolve, reject) => {
      resolve({
        then(res, rej) {
          res('hi ice')
        }
      })
    })
    
    promise.then(res => console.log(res))
    
    // hi ice

    2.5 Promise的实例方法

    • 实例方法,存放在Promise.prototype上的方法,也就是Promise的显示原型上,当我new Promise的时候,会把返回的改对象的 promise[[prototype]](隐式原型) === Promise.prototype (显示原型)
    • 即new返回的对象的隐式原型指向了Promise的显示原型

    2.5.1 then方法

    2.5.1.1 then的参数
    • then方法可以接受参数,一个参数为成功的回调,另一个参数为失败的回调,前面重构requestData中有演练过。
    const promise = new Promise((resolve, reject) => {
      resolve('request success')
      // reject('request error')
    })
    
    promise.then(res => console.log(res), rej => console.log(rej))
    
    //request success
    • 如果只捕获错误,还可以这样写
      • 因为第二个参数是捕获异常的,第一个可以写个null""占位
    const promise = new Promise((resolve, reject) => {
      // resolve('request success')
      reject('request error')
    })
    
    promise.then(null, rej => console.log(rej))
    
    //request error
    2.5.1.2 then的多次调用
    const promise = new Promise((resolve, reject) => {
      resolve('hi ice')
    })
    
    promise.then(res => ({name:'ice', age:22}))
           .then(res => console.log(res))
           
    //{name:'ice', age:22}
    • 调用多次则会执行多次
    2.5.1.3 then的返回值
    • then方法是有返回值的,它的返回值是promise,但是是promise那它的状态如何决定呢?接下来让我们一探究竟。
    2.5.1.3.1 返回一个普通值 状态:fulfilled
    const promise = new Promise((resolve, reject) => {
      resolve('hi ice')
    })
    
    promise.then(res => ({name:'ice', age:22}))
           .then(res => console.log(res))
           
    //{name:'ice', age:22}
    • 返回一个普通值,则相当于主动调用Promise.resolve,并且把返回值作为实参传递到then方法中。
    • 如果没有返回值,则相当于返回undefined
    2.5.1.3.2 明确返回一个promise 状态:fulfilled
    const promise = new Promise((resolve, reject) => {
      resolve('hi ice')
    })
    
    promise.then(res => {
      return new Promise((resolve, reject) => {
        resolve('then 的返回值')
      })
    }).then(res => console.log(res))
    
    //then 的返回值
    • 主动返回一个promise对象,状态和你调用resolve,还是reject有关
    2.5.1.3.3 返回一个thenable对象 状态:fulfilled
    const promise = new Promise((resolve, reject) => {
      resolve('hi ice')
    })
    
    promise.then(res => {
      return {
        then(resolve, reject) {
          resolve('hi webice')
        }
      }
    }).then(res => console.log(res))
    
    //hi webice
    • 返回了一个thenable对象,其状态取决于你是调用了resolve,还是reject

    2.5.2 catch方法

    2.5.2.1 catch的多次调用
    const promise = new Promise((resolve, reject) => {
      reject('ice error')
    })
    
    promise.catch(err => console.log(err))
    promise.catch(err => console.log(err))
    promise.catch(err => console.log(err))
    
    //ice error
    //ice error
    //ice error
    2.5.2.2 catch的返回值
    • catch方法是有返回值的,它的返回值是promise,但是是promise那它的状态如何决定呢?接下来让我们一探究竟。
    • 如果返回值明确一个promise或者thenble对象,取决于你调用了resolve还是reject
    2.5.2.2.1 返回一个普通对象
    const promise = new Promise((resolve, reject) => {
      reject('ice error')
    })
    
    promise.catch(err => ({name:'ice', age: 22})).then(res => console.log(res))
    
    //{name:'ice', age: 22}
    2.5.2.2.2 明确返回一个promise
    const promise = new Promise((resolve, reject) => {
      reject('ice error')
    })
    
    promise.catch(err => {
      return new Promise((resolve, reject) => {
        reject('ice error promise')
      })
    }).catch(res => console.log(res))
    
    //ice error promise
    • 此时new Promise() 调用了reject函数,则会被catch捕获到
    2.5.2.2.3 返回thenble对象
    const promise = new Promise((resolve, reject) => {
      reject('ice error')
    })
    
    promise.catch(err => {
      return {
        then(resolve, reject) {
          reject('ice error then')
        }
      }
    }).catch(res => console.log(res))
    
    //ice error then

    2.5.3 finally方法

    • ES9(2018)新实例方法
    • finally(最后),无论promise状态是fulfilled还是rejected都会执行一次finally方法
    const promise = new Promise((resolve, reject) => {
      resolve('hi ice')
    })
    
    promise.then(res => console.log(res)).finally(() => console.log('finally execute'))
    
    //finally execute

    2.6 Promise中的类方法/静态方法

    2.6.1 Promise.reslove

    Promise.resolve('ice')
    //等价于
    new Promise((resolve, reject) => resolve('ice'))
    • 有的时候,你已经预知了状态的结果为fulfilled,则可以用这种简写方式

    2.6.2 Promise.reject

    Promise.reject('ice error')
    //等价于
    new Promise((resolve, reject) => reject('ice error'))
    • 有的时候,你已经预知了状态的结果为rejected,则可以用这种简写方式

    2.6.3 Promise.all

    fulfilled 状态

    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi ice')
      }, 1000);
    })
    
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi panda')
      }, 2000);
    })
    
    const promise3 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi grizzly')
      }, 3000);
    })
    
    
    Promise.all([promise1, promise2, promise3]).then(res => console.log(res))
    
    //[ 'hi ice', 'hi panda', 'hi grizzly' ]
    • all方法的参数传入为一个可迭代对象,返回一个promise,只有三个都为resolve状态的时候才会调用.then方法。
    • 只要有一个promise的状态为rejected,则会回调.catch方法

    rejected状态

    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi ice')
      }, 1000);
    })
    
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('hi panda')
      }, 2000);
    })
    
    const promise3 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi grizzly')
      }, 3000);
    })
    
    Promise.all([promise1, promise2, promise3]).then(res => console.log(res)).catch(err => console.log(err))
    
    //hi panda
    • 当遇到rejectd的时候,后续的promise结果我们是获取不到,并且会把reject的实参,传递给catch的err形参中

    2.6.4 Promise.allSettled

    • 上面的Promise.all有一个缺陷,就是当遇到一个rejected的状态,那么对于后面是resolve或者reject的结果我们是拿不到的
    • ES11 新增语法Promise.allSettled,无论状态是fulfilled/rejected都会把参数返回给我们

    所有promise都有结果

    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('hi ice')
      }, 1000);
    })
    
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi panda')
      }, 2000);
    })
    
    const promise3 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('hi grizzly')
      }, 3000);
    })
    
    Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res))
    
    /* [
      { status: 'rejected', reason: 'hi ice' },
      { status: 'fulfilled', value: 'hi panda' },
      { status: 'rejected', reason: 'hi grizzly' }
    ] */
    • 该方法会在所有的Promise都有结果,无论是fulfilled,还是rejected,才会有最终的结果

    其中一个promise没有结果

    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('hi ice')
      }, 1000);
    })
    
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi panda')
      }, 2000);
    })
    
    const promise3 = new Promise((resolve, reject) => {})
    
    
    Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res))
    // 什么都不打印
    • 其中一个promise没有结果,则什么都结果都拿不到

    2.6.5 Promise.race

    • race(竞争竞赛)
    • 优先获取第一个返回的结果,无论结果是fulfilled还是rejectd
    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('hi error')
      }, 1000);
    })
    
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi panda')
      }, 2000);
    })
    
    
    Promise.race([promise1, promise2])
           .then(res => console.log(res))
           .catch(e => console.log(e))
           
    //hi error

    2.6.6 Promise.any

    • 与race类似,只获取第一个状态为fulfilled,如果全部为rejected则报错AggregateError
    const promise1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        reject('hi error')
      }, 1000);
    })
    
    const promise2 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('hi panda')
      }, 2000);
    })
    
    
    Promise.any([promise1, promise2])
           .then(res => console.log(res))
           .catch(e => console.log(e))
           
    //hi panda

    3. Promise的回调地狱 (进阶)

    • 我还是以一个需求作为切入点,把知识点嚼碎了,一点一点喂进你们嘴里。
      • 当我发送网络请求的时候,需要拿到这次网络请求的数据,再发送网络请求,就这样重复三次,才能拿到我最终的结果。

    3.1 卧龙解法

    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (url.includes('iceweb')) {
            resolve(url)
          } else {
            reject('请求错误')
          }
        }, 1000);
      })
    }
    
    
    requestData('iceweb.io').then(res => {
      requestData(`iceweb.org ${res}`).then(res => {
        requestData(`iceweb.com ${res}`).then(res => {
          console.log(res)
        })
      })
    })
    
    //iceweb.com iceweb.org iceweb.io
    • 虽然能够实现,但是多层代码的嵌套,可读性非常差,我们把这种多层次代码嵌套称之为回调地狱

    3.2 凤雏解法

    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (url.includes('iceweb')) {
            resolve(url)
          } else {
            reject('请求错误')
          }
        }, 1000);
      })
    }
    
    requestData('iceweb.io').then(res => {
      return requestData(`iceweb.org ${res}`)
    }).then(res => {
      return requestData(`iceweb.com ${res}`)
    }).then(res => {
      console.log(res)
    })
    
    //iceweb.com iceweb.org iceweb.io
    • 利用了then链式调用这一特性,返回了一个新的promise,但是不够优雅,思考一下能不能写成同步的方式呢?

    3.3 生成器+Promise解法

    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (url.includes('iceweb')) {
            resolve(url)
          } else {
            reject('请求错误')
          }
        }, 1000);
      })
    }
    
    function* getData(url) {
      const res1 = yield requestData(url)
      const res2 = yield requestData(res1)
      const res3 = yield requestData(res2)
    
      console.log(res3)
    }
    
    const generator = getData('iceweb.io')
    
    generator.next().value.then(res1 => {
      generator.next(`iceweb.org ${res1}`).value.then(res2 => {
        generator.next(`iceweb.com ${res2}`).value.then(res3 => {
          generator.next(res3)
        })
      })
    })
    
    //iceweb.com iceweb.org iceweb.io
    • 大家可以发现我们的getData已经变为同步的形式,可以拿到我最终的结果了。那么很多同学会问,generator一直调用.next不是也产生了回调地狱吗?
    • 其实不用关心这个,我们可以发现它这个是有规律的,我们可以封装成一个自动化执行的函数,我们就不用关心内部是如何调用的了。

    3.4 自动化执行函数封装

    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (url.includes('iceweb')) {
            resolve(url)
          } else {
            reject('请求错误')
          }
        }, 1000);
      })
    }
    
    function* getData() {
      const res1 = yield requestData('iceweb.io')
      const res2 = yield requestData(`iceweb.org ${res1}`)
      const res3 = yield requestData(`iceweb.com ${res2}`)
    
      console.log(res3)
    }
    
    //自动化执行 async await相当于自动帮我们执行.next
    function asyncAutomation(genFn) {
      const generator = genFn()
    
      const _automation = (result) => {
        let nextData = generator.next(result)
        if(nextData.done) return
    
        nextData.value.then(res => {
          _automation(res)
        })
      }
    
      _automation()
    }
    
    asyncAutomation(getData)
    
    //iceweb.com iceweb.org iceweb.io
    • 利用promise+生成器的方式变相实现解决回调地狱问题,其实就是async await的一个变种而已
    • 最早为TJ实现,前端大神人物
    • async await核心代码就类似这些,内部主动帮我们调用.next方法

    3.5 最终解决回调地狱的办法

    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (url.includes('iceweb')) {
            resolve(url)
          } else {
            reject('请求错误')
          }
        }, 1000);
      })
    }
    
    async function getData() {
      const res1 = await requestData('iceweb.io')
      const res2 = await requestData(`iceweb.org ${res1}`)
      const res3 = await requestData(`iceweb.com ${res2}`)
    
      console.log(res3)
    }
    
    getData()
    
    //iceweb.com iceweb.org iceweb.io
    • 你会惊奇的发现,只要把getData生成器函数函数,改为async函数,yeild的关键字替换为await就可以实现异步代码同步写法了。

    4. async/await 剖析

    • async(异步的)
    • async 用于申明一个异步函数

    4.1 async内部代码同步执行

    • 异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行
    async function sayHi() {
      console.log('hi ice')
    }
    
    sayHi()
    
    //hi ice

    4.2 异步函数的返回值

    • 异步函数的返回值和普通返回值有所区别

      • 普通函数主动返回什么就返回什么,不返回为undefined
      • 异步函数的返回值特点
        • 明确有返回一个普通值,相当于Promise.resolve(返回值)
        • 返回一个thenble对象则由,then方法中的resolve,或者reject有关
        • 明确返回一个promise,则由这个promise决定
    • 异步函数中可以使用await关键字,现在在全局也可以进行await,但是不推荐。会阻塞主进程的代码执行

    4.3 异步函数的异常处理

    • 如果函数内部中途发生错误,可以通过try catch的方式捕获异常
    • 如果函数内部中途发生错误,也可以通过函数的返回值.catch进行捕获
    async function sayHi() {
      console.log(res)
    }
    sayHi().catch(e => console.log(e))
    
    //或者
    
    async function sayHi() {
      try {
        console.log(res)
      }catch(e) {
        console.log(e)
      }
    }
    
    sayHi()
    
    //ReferenceError: res is not defined

    4.4 await 关键字

    • 异步函数中可以使用await关键字,普通函数不行
    • await特点
      • 通常await关键字后面都是跟一个Promise
        • 可以是普通值
        • 可以是thenble
        • 可以是Promise主动调用resolve或者reject
      • 这个promise状态变为fulfilled才会执行await后续的代码,所以await后面的代码,相当于包括在.then方法的回调中,如果状态变为rejected,你则需要在函数内部try catch,或者进行链式调用进行.catch操作
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (url.includes('iceweb')) {
            resolve(url)
          } else {
            reject('请求错误')
          }
        }, 1000);
      })
    }
    
    async function getData() {
      const res = await requestData('iceweb.io')
      console.log(res)
    }
    
    getData()
    
    // iceweb.io

    5. 结语

    • 如果现在真的看不到未来是怎样,你就不如一直往前走,不知道什么时候天亮,去奔跑就好,跑着跑着天就亮了。

    【相关推荐:javascript视频教程编程基础视频

Kenyataan:
Artikel ini dikembalikan pada:juejin.cn. Jika ada pelanggaran, sila hubungi admin@php.cn Padam