記錄--通過手寫,分析Promise核心原理

来源:https://www.cnblogs.com/smileZAZ/archive/2022/09/21/16716772.html
-Advertisement-
Play Games

這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 1. 定義整體結構 先寫出構造函數,將Promise向外暴露 /* 自定義Promise函數模塊:IIFE */ (function (window) { /* Promise構造函數 executor:執行器函數 */ function ...


這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助

1. 定義整體結構

  1. 先寫出構造函數,將Promise向外暴露
/*
自定義Promise函數模塊:IIFE
 */

(function (window) {
    /*
    Promise構造函數
    executor:執行器函數
     */
    function Promise(executor) {

    }

    // 向外暴露Promise
    window.Promise = Promise
})()
  1. 添加Promise原型對象上的方法
 /*
    Promise原型對象的then
    指定一個成功/失敗的回調函數
    返回一個新的promise對象
     */
    Promise.prototype.then = function(onResolved,onRejected){

    }

    /*
    Promise原型對象的.catch
    指定一個失敗的回調函數
    返回一個新的promise對象
     */
    Promise.prototype.catch = function(onRejected){

    }
  1. 添加Promise函數對象上的方法
/*
    Promise函數對象的resovle方法
    返回一個指定結果的promise對象
     */
    Promise.resolve = function(value){

    }

    /*
    Promise函數對象的reject方法
    返回一個指定reason的失敗狀態的promise對象
    */
    Promise.reject = function(value){

    }

    /*
    Promise函數對象的all方法
    返回一個promise對象,只有當所有promise都成功時返回的promise狀態才成功
    */
    Promise.all = function(0value){

    }

    /*
    Promise函數對象的race方法
    返回一個promise對象,狀態由第一個完成的promise決定
    */
    Promise.race = function(value){

    }

通過上面的註釋可以知道。不管是Promise原型對象上的方法還是Promise函數對象上的方法 ,它們的執行結果都將返回一個Promise對象

2. 實現Promise構造函數

我們看看我們是怎麼使用Promise的

const promiseA = new Promise( (resolve,reject) => {
    resolve(777);
});
  1. 我們傳入了一個函數,而且這個函數被立即執行,不僅如此,這個函數還會立即執行resolve和reject。說明構造函數里有resolve和reject方法。因此我們可以初步實現:
    /*
    Promise構造函數
    executor:執行器函數
     */
    function Promise(executor) {

        function resovle() {

        }
        function reject() {

        }

        // 立即同步執行executor
        executor(resovle,reject)
    }
  1. 每個promise都有一個狀態可能為pending或resolved,rejected。而且初始狀態都為pending。因此需要添加個status來表示當前promise的狀態.。並且每個promise有自己的data。
function Promise(executor) {

        var self = self
        新增代碼
        self.status = 'pending' // 給promise對象指定status屬性,初始值為pending
    
        self.data = undefined // 給promise對象指定一個存儲結果的data

        function resovle() {

        }
        function reject() {

        }

        // 立即同步執行executor
        executor(resovle,reject)
    }

此外,當我們這樣使用Promise的時候,

// 例1
var promise = new Promise((resovle,reject)=>{
    
})

promise.then(resolve=>{},reject=>{})

這時執行到then,因為我們傳入的立即執行函數沒有執行resolve或者reject,所以promise的狀態還是pending,這時要把then裡面的回調函數保存起來,所以需要個callbacks數組

function Promise(executor) {

        var self = self

        self.status = 'pending' // 給promise對象指定status屬性,初始值為pending
        self.data = undefined // 給promise對象指定一個存儲結果的data
        新增代碼
        self.callbacks = []  // 每個元素的結構:{onResolved(){},onRejected(){}}


        function resovle() {

        }
        function reject() {

        }

        // 立即同步執行executor
        executor(resovle,reject)
    }

那 then函數是怎麼把傳入的回調收集起來的。其實很簡單,就是判斷當前promise是否為pending狀態,是的話,就把回調push到callbacks中。

Promise.prototype.then = function(onResolved,onRejected){

        var self = this
        
        if(self.status === 'pending'){
            // promise當前狀態還是pending狀態,將回調函數保存起來
            self.callbacks.push({
                onResolved(){onResolved(self.data)},
                onRejected(){onRejected(self.data)}
            })
        }else if(self.status === 'resolved'){
        }else{
        }

    }
  1. 在上面的例子1的基礎上,當我們執行resovle(value)時,如例2
// 例2
var promise = new Promise((resolve,reject)=>{
    setTimeout(function () {
        resolve(1)
    })
})

promise.then(
    value=>{console.log(value)},
    err=>{console.log(err)}
    )

此時代碼執行情況是怎麼樣的呢?

  1. 先執行new Promise里的代碼,然後發現個定時器,js線程將定時器交給定時器線程處理,2. 然後繼續執行下麵的代碼,發現是then,而且當前的promise還是pending的狀態。就把then里的回調函數放到callbacks中。
  2. 5秒後定時器線程將定時器里的回調函數(也就是巨集任務)放到消息隊列中,js線程在消息隊列里發現了這個巨集任務,就把它拿來執行。
  3. 執行這個巨集任務,就執行了resolve(1),此時promise的callbacks里的回調被執行。並將當前promise狀態改為resolved。然後這個1也會被保存到當前promise對象中

那怎麼實現resolve呢?依舊上面的描述,就知道resovle的功能是執行callbacks里的函數,並保存data並將當前promise狀態改為resolved。所以我們可以這麼實現

function resolve(value) {
    // 將狀態改為resolved
    self.status = 'resolved'
    // 保存value的值
    self.data = value

    // 如果有待執行的callback函數,立即非同步執行回調函數onResolved
    if (self.callbacks.length>0){
        self.callbacks.forEach(callbackObj=>{
            callbackObj.onResolved(value)
        })
    }
}
  1. 我們還知道,promise的狀態只能改變一次,因此當執行resolve的時候要判斷是不是promise是不是pending的狀態,否則是不能執行的
function resolve(value) {
    // 如果當前狀態不是pending,則不執行
    if(this.status !== 'pending'){
        return 
    }
    // 將狀態改為resolved
    this.status = 'resolved'
    // 保存value的值
    this.data = value

    // 如果有待執行的callback函數,立即非同步執行回調函數onResolved
    if (this.callbacks.length>0){
        setTimeout(()=>{
            this.callbacks.forEach(callbackObj=>{ A
                callbackObj.onResolved(value)
            })
        })
    }
}
  1. 異曲同工之妙的是reject方法也是這個道理,因此這裡無需贅述
function reject(value) {
    // 如果當前狀態不是pending,則不執行
    if(self.status !== 'pending'){
        return
    }
    // 將狀態改為rejected
    self.status = 'rejected'
    // 保存value的值
    self.data = value

    // 如果有待執行的callback函數,立即非同步執行回調函數onResolved
    if (self.callbacks.length>0){
      self.callbacks.forEach(callbackObj=>{
          callbackObj.onRejected(value)
      })
    }
}
  1. 我們又知道,當在執行executor的時候,如果執行異常的話,這個promise的狀態會直接執行reject方法。例如
// 例 3
var promise = new Promise((resolve,reject)=>{

    error;執行到這裡出錯了

    setTimeout(function () {
        resolve(1)
    })
})

要實現這個功能,我們可以在executor外讓try catch來捕獲

try{
    // 立即同步執行executor
    executor(resolve,reject)
}catch (e) { // 如果執行器拋出異常,promise對象變為rejected狀態
    reject(e)
}

好了,現在測試下

 // 例4
 let promise = new Promise((resolve,reject)=>{
        
        setTimeout(function () {
            resolve(1)
            //reject(1)
        },100)
    })

    promise.then(
        value=>{
            console.log("onResolved:",value);
        },
        reason=>{
            console.log("onRejected:",reason);
        }
    )

發現成功。 成功輸出onResolved:1

3. 實現then方法

我們在上面簡單的實現了當前promise為pending狀態的情況,如:

Promise.prototype.then = function(onResolved,onRejected){

    var self = this

    if(self.status === 'pending'){
        // promise當前狀態還是pending狀態,將回調函數保存起來
        self.callbacks.push({
            onResolved(){onResolved(self.data)},
            onRejected(){onRejected(self.data)}
        })
    }else if(self.status === 'resolved'){
    }else{
    }

}

那其他情況呢?

執行到then時,promise可能會是pending狀態,此時就要把then里的回調函數保存起來,也可能會是resolved或者rejected狀態,此時就不用把回調保存起來,直接執行onResolved或onRejected方法。註意是非同步執行。而且是做為微任務的,這裡我們簡單的用setTimeout來實現就好了。

Promise.prototype.then = function(onResolved,onRejected){

  var self = this

  if(self.status === 'pending'){
      // promise當前狀態還是pending狀態,將回調函數保存起來
      self.callbacks.push({
          onResolved(){onResolved(self.data)},
          onRejected(){onRejected(self.data)}
      })
  }else if(self.status === 'resolved'){
      setTimeout(()=>{
          onResolved(self.data)
      })
  }else{
      setTimeout(()=>{
          onResolved(self.data)
      })
  }

}

而且我們知道,執行完then是要返回一個新的promise的,而新的promise的狀態則由當前then的執行結果來確定。

 Promise.prototype.then = function(onResolved,onRejected){

    var self = this

    return new Promise((resolve,reject)=>{
        if(self.status === 'pending'){
            // promise當前狀態還是pending狀態,將回調函數保存起來
            self.callbacks.push({
                onResolved(){onResolved(self.data)},
                onRejected(){onRejected(self.data)}
            })
        }else if(self.status === 'resolved'){
            setTimeout(()=>{
                onResolved(self.data)
            })
        }else{
            setTimeout(()=>{
                onResolved(self.data)
            })
        }
    })

}

當 當前的promise狀態為resolved的時候,則執行then的時候,會執行第二個判斷語句

則當前執行第二個判斷語句的時候會出現三種情況

  1. 如果then里的回調函數返回的不是promise,return的新promise的狀態是則是resolved,value就是返回的值。例如:
// 例5
let promise = new Promise((resolve,reject)=>{
    resolve(1)
})

promise.then(
    value=>{
        return value //返回的不是promise,是value
    }
)

因此,我們可以這樣實現

Promise.prototype.then = function(onResolved,onRejected){

    var self = this

    return new Promise((resolve,reject)=>{
        if(self.status === 'pending'){
            // promise當前狀態還是pending狀態,將回調函數保存起來
            self.callbacks.push({
                onResolved(){onResolved(self.data)},
                onRejected(){onRejected(self.data)}
            })
        }else if(self.status === 'resolved'){
            修改代碼
            setTimeout(()=>{
                const result = onResolved(self.data)
                if (result instanceof Promise){

                } else {
                // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
                    resolve(result)
                }
            })
        }else{
            setTimeout(()=>{
                onResolved(self.data)
            })
        }
    })

}

簡單解釋下:

執行onResolved(self.data),其實就是執行例子中的下麵這個回調函數

value=>{
        return value //返回的不是promise,是value
    }

那麼這個回調函數返回了value。就把value傳入resolve函數,resolve函數將當前新的promise的狀態改為resolved,同時將value保存到當前新的promise的data中。

  1. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果,如代碼所示,我們返回一個新的promise。如果這個promise執行了resolve,返回的新的promise的狀態則是resolved的。否則為rejected
// 例6
let promise = new Promise((resolve,reject)=>{
    resolve(1)
})

promise.then(
    value=>{
        return new Promise((resolve,reject)=>{
            resolve(2)
            //或者
            //reject(error)
        })
    }
)

因此我們可以這樣實現

Promise.prototype.then = function(onResolved,onRejected){

    var self = this

    return new Promise((resolve,reject)=>{
        if(self.status === 'pending'){
            // promise當前狀態還是pending狀態,將回調函數保存起來
            self.callbacks.push({
                onResolved(){onResolved(self.data)},
                onRejected(){onRejected(self.data)}
            })
        }else if(self.status === 'resolved'){
            setTimeout(()=>{
                const result = onResolved(self.data)
                if (result instanceof Promise){
                    // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
                    result.then(
                        value => {resolve(value)},
                        reason => {reject(reason)}
                    )
                } else {
                    // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
                    resolve(result)
                }
            })
        }else{
            setTimeout(()=>{
                onResolved(self.data)
            })
        }
    })

}

在這裡說明一下:

result.then(
    value => {resolve(value)},
    reason => {reject(reason)}
)

由於我們在例6中執行了then里的

value=>{
        return new Promise((resolve,reject)=>{
            resolve(2)
            //或者
            //reject(error)
        })
    }

則返回一個promise對象,這個promise對象可能為resolved狀態(執行 resolve(2))也可能為rejected狀態(執行reject(error))。

將會導致value => {resolve(value)},這個回調函數的執行或者 reason => {reject(reason)}的執行。

因此會把即將返回的新的promise的data設置為value或者,reason。會把狀態設置為resolved或者rejected。

  1. 如果執行這段代碼的時候拋出錯誤,則返回的promise的狀態為rejected,我們可以用try catch來實現
setTimeout(()=>{
    try{
        const result = onResolved(self.data)
        if (result instanceof Promise){
            // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
            result.then(
                value => {resolve(value)},
                reason => {reject(reason)}
            )
        } else {
            // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
            resolve(result)
        }
    }catch (e) {
      //  3.如果執行onResolved的時候拋出錯誤,則返回的promise的狀態為rejected
        reject(e)
    }
})

異曲同工之妙的是當status === 'rejected',道理一樣

 setTimeout(()=>{
      try{
          const result = onRejected(self.data)
          if (result instanceof Promise){
              // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
              result.then(
                  value => {resolve(value)},
                  reason => {reject(reason)}
              )
          } else {
              // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
              resolve(result)
          }
      }catch (e) {
          //  3.如果執行onResolved的時候拋出錯誤,則返回的promise的狀態為rejected
          reject(e)
      }
  })

到這裡,我們發現當執行resolve的時候,onResolved(self.data)onRejected(self.data)執行時也會跟上面一樣的結果,可以說執行回調函數都要做以上判斷,因此我們要將

 self.callbacks.push({
    onResolved(){onResolved(self.data)},
    onRejected(){onRejected(self.data)}
})

改成

if(self.status === 'pending'){
// promise當前狀態還是pending狀態,將回調函數保存起來
self.callbacks.push({
    onResolved(){
        try{
            const result = onResolved(self.data)
            if (result instanceof Promise){
                // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
                result.then(
                    value => {resolve(value)},
                    reason => {reject(reason)}
                )
            } else {
                // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
                resolve(result)
            }
        }catch (e) {
            //  3.如果執行onResolved的時候拋出錯誤,則返回的promise的狀態為rejected
            reject(e)
        }
    },

到此,我們發現,相同的代碼太多了,因此有必要封裝一下

 function handle(callback) {
    try{
        const result = callback(self.data)
        if (result instanceof Promise){
            // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
            result.then(
                value => {resolve(value)},
                reason => {reject(reason)}
            )
        } else {
            // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
            resolve(result)
        }
    }catch (e) {
        //  3.如果執行onResolved的時候拋出錯誤,則返回的promise的狀態為rejected
        reject(e)
    }
}

這樣以來就清爽了很多

   Promise.prototype.then = function(onResolved,onRejected){

        var self = this

        return new Promise((resolve,reject)=>{
           /*
            調用指定回調函數的處理,根據執行結果。改變return的promise狀態
             */
            function handle(callback) {
                try{
                    const result = callback(self.data)
                    if (result instanceof Promise){
                        // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
                        result.then(
                            value => {resolve(value)},
                            reason => {reject(reason)}
                        )
                    } else {
                        // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
                        resolve(result)
                    }
                }catch (e) {
                    //  3.如果執行onResolved的時候拋出錯誤,則返回的promise的狀態為rejected
                    reject(e)
                }
            }
            if(self.status === 'pending'){
                // promise當前狀態還是pending狀態,將回調函數保存起來
                self.callbacks.push({
                    onResolved(){
                        handle(onResolved)
                    },
                    onRejected(){
                        handle(onRejected)
                    }
                })
            }else if(self.status === 'resolved'){
                setTimeout(()=>{
                    handle(onResolved)
                })
            }else{ // 當status === 'rejected'
                setTimeout(()=>{
                    handle(onRejected)
                })
            }
        })

    }

另外,我們還知道,promise會發生值傳透,例如

let promsie = new Promise((resolve,reject)=>{
    resolve(1)
})
promsie
  .then(2)
  .then(3)
  .then(value =>console.log(value))

運行結果: 1

解釋:.then 或者 .catch 的參數期望是函數,傳入非函數則會發生值穿透。值傳透可以理解為,當傳入then的不是函數的時候,這個then是無效的。而實際原理上其實是當then中傳入的不算函數,則這個then返回的promise的data,將會保存上一個的promise.data。這就是發生值穿透的原因。而且每一個無效的then所返回的promise的狀態都為resolved

因此,要實現直傳透這個特性,我們可以這樣實現

添加這兩句來判斷要不要發生值傳透

onResolved = typeof onResolved === 'function'? onResolved: value => value
onRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason}

實際上就是改寫,如果傳入的不是函數,那就忽略那個傳入值,自己再寫一個函數。這個函數的執行結果將返回上一個promise的data

Promise.prototype.then = function(onResolved,onRejected){
    onResolved = typeof onResolved === 'function'? onResolved: value => value
    onRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason}
    var self = this

    return new Promise((resolve,reject)=>{

        /*
        調用指定回調函數的處理,根據執行結果。改變return的promise狀態
         */
        function handle(callback) {
            try{
                const result = callback(self.data)
                if (result instanceof Promise){
                    // 2. 如果回調函數返回的是promise,return的promise的結果就是這個promise的結果
                    result.then(
                        value => {resolve(value)},
                        reason => {reject(reason)}
                    )
                } else {
                    // 1. 如果回調函數返回的不是promise,return的promise的狀態是resolved,value就是返回的值。
                    resolve(result)
                }
            }catch (e) {
                //  3.如果執行onResolved的時候拋出錯誤,則返回的promise的狀態為rejected
                reject(e)
            }
        }
        if(self.status === 'pending'){
            // promise當前狀態還是pending狀態,將回調函數保存起來
            self.callbacks.push({
                onResolved(){
                    handle(onResolved)
                },
                onRejected(){
                    handle(onRejected)
                }
            })
        }else if(self.status === 'resolved'){
            setTimeout(()=>{
                handle(onResolved)
            })
        }else{ // 當status === 'rejected'
            setTimeout(()=>{
                handle(onRejected)
            })
        }
    })

}

3.實現catch方法

catch方法的作用跟then里的第二歌回調函數一樣,因此我們可以這樣來實現

Promise.prototype.catch = function(onRejected){
    return this.then(undefined,onRejected)
}

我的天啊,居然這麼簡單

4. 實現Promise.resolve

我們都知道,Promise.resolve方法可以傳三種值

  1. 不是promise
  2. 成功狀態的promise
  3. 失敗狀態的promise
    Promise.resolve(1)
    Promise.resolve(Promise.resolve(1))
    Promise.resolve(Promise.reject(1))

實際上跟實現上面的then時有點像

Promise.resolve = function(value){
  return new Promise((resolve,reject)=>{
      if (value instanceof Promise){
          // 如果value 是promise
          value.then(
              value => {resolve(value)},
              reason => {reject(reason)}
          )
      } else{
          // 如果value不是promise
          resolve(value)
      }

  }

}

5.實現Promise.reject

實現這個比較簡單,返回一個狀態為rejected的promise就好了

/*
Promise函數對象的reject方法
返回一個指定reason的失敗狀態的promise對象
*/
Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason)
    })
}

6.實現Promise.all

我們知道,這個方法會返回一個promise

    /*
    Promise函數對象的all方法
    返回一個promise對象,只有當所有promise都成功時返回的promise狀態才成功
    */
    Promise.all = function(promises){
        return new Promise((resolve,reject)=>{
           
        })
    }
  

而這個promise的狀態由遍歷每個promise產生的結果決定

    /*
    Promise函數對象的all方法
    返回一個promise對象,只有當所有promise都成功時返回的promise狀態才成功
    */
    Promise.all = function(promises){
        return new Promise((resolve,reject)=>{
            // 遍歷promises,獲取每個promise的結果
            promises.forEach((p,index)=>{
                
            })
        })
    }

有兩種結果:

  1. 遍歷到有一個promise是reject狀態,則直接返回的promise狀態為rejected
 Promise.all = function(promises){
        return new Promise((resolve,reject)=>{
            // 遍歷promises,獲取每個promise的結果
            promises.forEach((p,index)=>{
                p.then(
                    value => {
    
                    },
                    reason => { //只要有一個失敗,return的promise狀態就為reject
                        reject(reason)
                    }
                )
            })
        })
    }
  1. 遍歷所有的promise的狀態都為resolved,則返回的promise狀態為resolved,並且還要每個promise產生的值傳遞下去
   Promise.all = function(promises){
      const values = new Array(promises.length)
      var resolvedCount = 0 //計狀態為resolved的promise的數量
      return new Promise((resolve,reject)=>{
          // 遍歷promises,獲取每個promise的結果
          promises.forEach((p,index)=>{
              p.then(
                  value => {
                      // p狀態為resolved,將值保存起來
                      values[index] = value
                      resolvedCount++;
                      // 如果全部p都為resolved狀態,return的promise狀態為resolved
                      if(resolvedCount === promises.length){
                          resolve(values)
                      }
                  },
                  reason => { //只要有一個失敗,return的promise狀態就為reject
                      reject(reason)
                  }
              )
          })
      })
  }

好像可以了,當其實這裡還有一個問題,就是all傳進去的數組不一定都是promise對象,可能是這樣的

all([p,2,3,p])

因此需要把不是promise的數字包裝成promise

    Promise.all = function(promises){
        const values = new Array(promises.length)
        var resolvedCount = 0 //計狀態為resolved的promise的數量
        return new Promise((resolve,reject)=>{
            // 遍歷promises,獲取每個promise的結果
            promises.forEach((p,index)=>{
                Promise.resolve(p).then(
                    value => {
                        // p狀態為resolved,將值保存起來
                        values[index] = value
                        resolvedCount++;
                        // 如果全部p都為resolved狀態,return的promise狀態為resolved
                        if(resolvedCount === promises.length){
                            resolve(values)
                        }
                    },
                    reason => { //只要有一個失敗,return的promise狀態就為reject
                        reject(reason)
                    }
                )
            })
        })
    }

7.實現Promise.race

這個方法的實現要比all簡單很多

  /*
    Promise函數對象的race方法
    返回一個promise對象,狀態由第一個完成的promise決定
    */
    Promise.race = function(promises){
        return new Promise((resolve,reject)=>{
            // 遍歷promises,獲取每個promise的結果
            promises.forEach((p,index)=>{
                Promise.resolve(p).then(
                    value => {
                        // 只要有一個成功,返回的promise的狀態九尾resolved
                        resolve(value)

                    },
                    reason => { //只要有一個失敗,return的promise狀態就為reject
                        reject(reason)
                    }
                )
            })
        })
    }

本文轉載於:

https://juejin.cn/post/6856213486633304078

如果對您有所幫助,歡迎您點個關註,我會定時更新技術文檔,大家一起討論學習,一起進步。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、 登錄 1.1 登錄預設資料庫 首先切換到oracle用戶,用資料庫預設管理員登錄。 [[email protected] ~]# su – oracle [[email protected] ~]$ lsnrctl start #開啟監聽 [[email protected] ~]$ sqlplus / as s ...
  • 對於一個服務端開發來說 MYSQL 可能是他使用最熟悉的資料庫工具,然而,大部分的Java工程師對MySQL的瞭解和掌握程度,大致就停留在這麼一個階段:它可以建庫、建表、建索引,然後就是對裡面的數據進行增刪改查,語句性能有點差?沒關係,在表裡建幾個索引或者調整一下查詢邏輯就可以了,一條sql,MYS... ...
  • 在數字化時代的今天,我們都認同數據會創造價值。為了最大化數據的價值,我們不停的建立著數據遷移的管道,從同構到異構,從關係型到非關係型,從雲下到雲上,從數倉到數據湖,試圖在各種場景挖掘數據的價值。而在這縱橫交錯的數據網路中,邏輯複製扮演著及其重要的角色。 讓我們將視角從複雜的網路拉回其中的一個端點,... ...
  • 2022年9月2日,日本MIC(総務省)發佈了“電波法施行規則等の一部を改正する省令(令和4年総務省令第59號)”省令,更新了Wi-Fi 6E Band 5頻帶5925 ~ 6425 MHz的技術要求。隔天(9月3日),日本DSP機構發佈了“「6GHz帯小電力データ通信システム」の特性試験方法”,為 ...
  • AU上傳ipa出現下圖紅框提示說明成功上傳,如果App Store後臺沒有出現構建版本, 請登錄 apple賬號對應的郵箱查看反饋,特別留意垃圾郵箱,無論成功還是失敗,apple都會發郵件 一、首先登錄iTunes Connect 後臺、查看ipa構建情況 https://appstoreconne ...
  • 現如今,人們在網上聊天、發帖時越來越愛用表情包,表情包一方面是一種個性化的表達方式,另一方面更能傳達出當下的心理活動,可以說在網路社交中表情包是一個不可或缺的存在。加上近年來元宇宙的興起,3D虛擬形象廣泛應用,用戶可以通過自己的表情來控制虛擬形象的表情,做一系列專屬的表情包,更加生動形象。 那麼,如 ...
  • ##vue+element-ui後臺管理系統模板 前端:基於vue2.0+或3.0+加上element-ui組件框架 後端:springboot+mybatis-plus寫介面 通過Axios調用介面完成數據傳遞 通過router路由完成各頁面的跳轉 ###全局配置 App.vue <templat ...
  • 好家伙,繼續優化, 好家伙,我把我的飛機大戰發給我的小伙伴們玩 期待著略微的贊賞之詞,然後他們用手機打開我的給他們的網址 然後點一下飛機就炸了。 游戲體驗零分 (滑鼠點擊在移動端依舊可以生效) 好了所以我們來優化一下這個觸屏移動事件 由於沒有參考,就去翻文檔了 觸摸事件分三個:touchstart、 ...
一周排行
    -Advertisement-
    Play Games
  • Github / Gitee QQ群(1群) : 813100564 / QQ群(2群) : 579033769 視頻教學 介紹 MiniWord .NET Word模板引擎,藉由Word模板和數據簡單、快速生成文件。 Getting Started 安裝 nuget link : https:// ...
  • Array.Sort Array類中相當實用的我認為是Sort方法,相比起冗長的冒泡排序,它的出現讓排序更加的簡化 結果如下: 還可以聲明一個靜態方法用來專門調用指定數組排序,從名為 array 的一維數組中 a 索引處開始,到 b 元素 從小到大排序。 註意: a + b 不能大於 array 的 ...
  • 前言 在上一篇文章CLR類型系統概述里提到,當運行時掛起時, 垃圾回收會執行堆棧遍歷器(stack walker)去拿到堆棧上值類型的大小和堆棧根。這裡我們來翻譯BotR里一篇專門介紹Stackwalking的文章,希望能加深理解。 順便說一句,StackWalker在中文里似乎還沒有統一的翻譯,J ...
  • 使用過 nginx 的小伙伴應該都知道,這個中間件是可以設置跨域的,作為今天的主角,同樣的 反向代理中間件的 YARP 毫無意外也支持了跨域請求設置。 有些小伙伴可能會問了,怎樣才算是跨域呢? 在 HTML 中,一些標簽,例如 img、a 等,還有我們非常熟悉的 Ajax,都是可以指向非本站的資源的 ...
  • 什麼是Git Git 是一個開源的分散式版本控制系統,用於敏捷高效地處理任何或小或大的項目。 Git 是 Linus Torvalds 為了幫助管理 Linux 內核開發而開發的一個開放源碼的版本控制軟體。 Git 與常用的版本控制工具 CVS, Subversion 等不同,它採用了分散式版本庫的 ...
  • 首先CR3是什麼,CR3是一個寄存器,該寄存器內保存有頁目錄表物理地址(PDBR地址),其實CR3內部存放的就是頁目錄表的記憶體基地址,運用CR3切換可實現對特定進程記憶體地址的強制讀寫操作,此類讀寫屬於有痕讀寫,多數驅動保護都會將這個地址改為無效,此時CR3讀寫就失效了,當然如果能找到CR3的正確地址... ...
  • 說明 onlyoffice為一款開源的office線上編輯組件,提供word/excel/ppt編輯保存操作 以下操作均基於centos8系統,officeonly鏡像版本7.1.2.23 鏡像下載地址:https://yunpan.360.cn/surl_y87CKKcPdY4 (提取碼:1f92 ...
  • 二叉樹查找指定的節點 前序查找的思路 1.先判斷當前節點的no是否等於要查找的 2.如果是相等,則返回當前節點 3.如果不等,則判斷當前節點的左子節點是否為空,如果不為空,則遞歸前序查找 4.如果左遞歸前序查找,找到節點,則返回,否繼續判斷,當前的節點的右子節點是否為空,如果不為空,則繼續向右遞歸前 ...
  • ##Invalid bound statement (not found)出現原因和解決方法 ###前言: 想必各位小伙伴在碼路上經常會碰到奇奇怪怪的事情,比如出現Invalid bound statement (not found),那今天我就來分析以下出現此問題的原因。 其實出現這個問題實質就是 ...
  • ###一、背景知識 爬蟲的本質就是一個socket客戶端與服務端的通信過程,如果我們有多個url待爬取,只用一個線程且採用串列的方式執行,那隻能等待爬取一個結束後才能繼續下一個,效率會非常低。 需要強調的是:對於單線程下串列N個任務,並不完全等同於低效,如果這N個任務都是純計算的任務,那麼該線程對c ...