主頁 > 企業開發 > 記錄--通過手寫,分析Promise核心原理

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

2022-09-22 08:36:05 企業開發

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

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 = https://www.cnblogs.com/smileZAZ/archive/2022/09/21/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 = https://www.cnblogs.com/smileZAZ/archive/2022/09/21/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=https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>{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 = https://www.cnblogs.com/smileZAZ/archive/2022/09/21/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 = https://www.cnblogs.com/smileZAZ/archive/2022/09/21/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 = https://www.cnblogs.com/smileZAZ/archive/2022/09/21/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=https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>{
            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=https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>{
        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=https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>{
        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=https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>{
        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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {resolve(value)},
                        reason => {reject(reason)}
                    )
                } else {
                    // 1. 如果回呼函式回傳的不是promise,return的promise的狀態是resolved,value就是回傳的值,
                    resolve(result)
                }
            })
        }else{
            setTimeout(()=>{
                onResolved(self.data)
            })
        }
    })

}

在這里說明一下:

result.then(
    value =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {resolve(value)},
    reason => {reject(reason)}
)

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

value=https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>{
        return new Promise((resolve,reject)=>{
            resolve(2)
            //或者
            //reject(error)
        })
    }

則回傳一個promise物件,這個promise物件可能為resolved狀態(執行 resolve(2))也可能為rejected狀態(執行reject(error)),

將會導致value =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/>console.log(value))

運行結果: 1

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

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

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

onResolved = typeof onResolved === 'function'? onResolved: value =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> value
onRejected = typeof onRejected ==='function'? onRejected: reason => {throw reason}

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

Promise.prototype.then = function(onResolved,onRejected){
    onResolved = typeof onResolved === 'function'? onResolved: value =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> 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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {
    
                    },
                    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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {
                      // 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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {
                        // 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 =https://www.cnblogs.com/smileZAZ/archive/2022/09/21/> {
                        // 只要有一個成功,回傳的promise的狀態九尾resolved
                        resolve(value)

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

本文轉載于:

https://juejin.cn/post/6856213486633304078

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

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/509274.html

標籤:其他

上一篇:02 uniapp/微信小程式 專案day02

下一篇:Html飛機大戰(十七): 優化移動端

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more