成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

從使用角度漸進(jìn)式剖析Promise源碼

DTeam / 3472人閱讀

摘要:規(guī)范鏈接規(guī)范中文鏈接本篇文章將從的使用角度來剖析源碼具體實(shí)現(xiàn)。但是對于則不一樣,回調(diào)函數(shù)通過遞歸調(diào)用自己從而保證其值不為類型才結(jié)束,并將賦值到數(shù)組,最后直到所有的數(shù)組都處理完畢由統(tǒng)一的方法結(jié)束當(dāng)前的操作,進(jìn)入處理流程。

開篇

最近在 github 上看到了一個(gè) extremely lightweight Promise polyfill 實(shí)現(xiàn),打開源碼發(fā)現(xiàn)只有240行,果然極其輕量級,于是帶著驚嘆和好奇的心理去了解了下其具體實(shí)現(xiàn)。
源碼的 github 地址:promise-polyfill

Promise 對于前端來說,是個(gè)老生常談的話題,Promise 的出現(xiàn)解決了 js 回調(diào)地域的問題。目前市面上有很多 Promise 庫,但其最終實(shí)現(xiàn)都要遵從 Promise/A+ 規(guī)范,這里對規(guī)范不做解讀,有興趣的可以查看鏈接內(nèi)容。
Promise/A+規(guī)范鏈接
Promise/A+規(guī)范中文鏈接

本篇文章將從 Promise 的使用角度來剖析源碼具體實(shí)現(xiàn)。

API 列表
Promise  // 構(gòu)造函數(shù)
Promise.prototype.then
Promise.prototype.catch
Promise.prototype.finally

// 靜態(tài)方法
Promise.resolve
Promise.reject
Promise.race
Promise.all
源碼解析 構(gòu)造函數(shù)

使用
Promise 使用第一步,構(gòu)造實(shí)例,傳入 Function 形參,形參接收兩個(gè) Function 類型參數(shù)resolve, reject

const asyncTask = () => {};
const pro = new Promise((resolve, reject) => {
  asyncTask((err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
});

源碼

function Promise(fn) {
  if (!(this instanceof Promise))
    throw new TypeError("Promises must be constructed via new");
  if (typeof fn !== "function") throw new TypeError("not a function");
  this._state = 0;
  this._handled = false;
  this._value = undefined;
  this._deferreds = [];
  doResolve(fn, this);
}

function doResolve(fn, self) {
  // done變量保護(hù) resolve 和 reject 只執(zhí)行一次
  // 這個(gè)done在 Promise.race()函數(shù)中有用
  var done = false;
  try {
    // 立即執(zhí)行 Promise 傳入的 fn(resolve,reject)
    fn(
      function(value) {
        // resolve 回調(diào)
        if (done) return;
        done = true;
        resolve(self, value);
      },
      function(reason) {
        // reject 回調(diào)
        if (done) return;
        done = true;
        reject(self, reason);
      }
    );
  } catch (ex) {
    if (done) return;
    done = true;
    reject(self, ex);
  }
}

Promise必須通過構(gòu)造函數(shù)實(shí)例化來使用,傳入 Promise 構(gòu)造函數(shù)的形參 fn 在doResolve方法內(nèi)是 立即調(diào)用執(zhí)行 的,并沒有異步(指放入事件循環(huán)隊(duì)列)處理。doResolve內(nèi)部針對 fn 函數(shù)的回調(diào)參數(shù)做了封裝處理,done變量保證了 resolve reject 方法只執(zhí)行一次,這在后面說到的Promise.race()函數(shù)實(shí)現(xiàn)有很大用處。

Promise 實(shí)例的內(nèi)部變量介紹
名稱 類型 默認(rèn)值 描述
_state Number 0 Promise內(nèi)部狀態(tài)碼
_handled Boolean false onFulfilled,onRejected是否被處理過
_value Any undefined Promise 內(nèi)部值,resolve 或者 reject返回的值
_deferreds Array [] 存放 Handle 實(shí)例對象的數(shù)組,緩存 then 方法傳入的回調(diào)

_state枚舉值類型

_state === 0  // pending
_state === 1  // fulfilled,執(zhí)行了resolve函數(shù),并且_value instanceof Promise === true
_state === 2  // rejected,執(zhí)行了reject函數(shù)
_state === 3  // fulfilled,執(zhí)行了resolve函數(shù),并且_value instanceof Promise === false

注意:這里_state區(qū)分了1 和 3 兩種狀態(tài),下面會解釋原因

/**
 * Handle 構(gòu)造函數(shù)
 * @param onFulfilled resolve 回調(diào)函數(shù)
 * @param onRejected reject 回調(diào)函數(shù)
 * @param promise 下一個(gè) promise 實(shí)例對象
 * @constructor
 */
function Handler(onFulfilled, onRejected, promise) {
  this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null;
  this.onRejected = typeof onRejected === "function" ? onRejected : null;
  this.promise = promise;
}

_deferreds數(shù)組的意義:當(dāng)在 Promise 內(nèi)部調(diào)用了異步處理任務(wù)時(shí),pro.then(onFulfilled,onRejected)傳入的兩個(gè)函數(shù)不會立即執(zhí)行,所以此時(shí)會把當(dāng)前的回調(diào)和下一個(gè) pro 對象關(guān)聯(lián)緩存起來,待到 resolve 或者 reject觸發(fā)調(diào)用時(shí),會去 forEach 這個(gè)_deferreds數(shù)組中的每個(gè) Handle 實(shí)例去處理對應(yīng)的 onFulfilled,onRejected 方法。

Promise 內(nèi)部 resolve reject finale 方法

上面說到,doResolve 內(nèi)部做了 fn 的立即執(zhí)行,并保證 resolve 和 reject 方法只執(zhí)行一次,接下來說說resolve 和 reject 內(nèi)部具體做了什么

function resolve(self, newValue) {
  try {
    // resolve 的值不能為本身 this 對象
    // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
    if (newValue === self)
      throw new TypeError("A promise cannot be resolved with itself.");
    // 針對 resolve 值為 Promise 對象的情況處理
    if (
      newValue &&
      (typeof newValue === "object" || typeof newValue === "function")
    ) {
      var then = newValue.then;
      if (newValue instanceof Promise) {
        self._state = 3;
        self._value = newValue;
        finale(self);
        return;
      } else if (typeof then === "function") {
        // 兼容類 Promise 對象的處理方式,對其 then 方法繼續(xù)執(zhí)行 doResolve
        doResolve(bind(then, newValue), self);
        return;
      }
    }
    //  resolve 正常值的流程,_state = 1
    self._state = 1;
    self._value = newValue;
    finale(self);
  } catch (e) {
    reject(self, e);
  }
}

function reject(self, newValue) {
  self._state = 2;
  self._value = newValue;
  finale(self);
}

function finale(self) {
  //  Promise reject 情況,但是 then 方法未提供 reject 回調(diào)函數(shù)參數(shù) 或者 未實(shí)現(xiàn) catch 函數(shù)
  if (self._state === 2 && self._deferreds.length === 0) {
    Promise._immediateFn(function() {
      if (!self._handled) {
        Promise._unhandledRejectionFn(self._value);
      }
    });
  }

  for (var i = 0, len = self._deferreds.length; i < len; i++) {
    // 這里調(diào)用之前 then 方法傳入的onFulfilled, onRejected函數(shù)
    // self._deferreds[i] => Handler 實(shí)例對象
    handle(self, self._deferreds[i]);
  }
  self._deferreds = null;
}

resolve,reject 是由用戶在異步任務(wù)里面觸發(fā)的回調(diào)函數(shù)
調(diào)用 resolve reject 方法的注意點(diǎn)
1、newValue不能為當(dāng)前的 this 對象,即下面的這樣寫法是錯(cuò)誤的

const pro = new Promise((resolve)=>{setTimeout(function () {
  resolve(pro);
},1000)});
pro.then(data => console.log(data)).catch(err => {console.log(err)});

因?yàn)閞esolve做了 try catch 的操作,直接會進(jìn)入 reject 流程。

2、newValue可以為另一個(gè)Promise 對象類型實(shí)例, resolve 的值返回的是另一個(gè) Promise 對象實(shí)例的內(nèi)部的_value,而不是其本身 Promise 對象。即可以這樣寫

const pro1 = new Promise((resolve)=>{setTimeout(function () {
  resolve(100);
},2000)});
const pro = new Promise((resolve)=>{setTimeout(function () {
  resolve(pro1);
},1000)});
pro.then(data => console.log("resolve" + data)).catch(err => {console.log("reject" + err)});
// 輸出結(jié)果:resolve 100
// data 并不是pro1對象

具體原因就在 resolve 方法體內(nèi)部做了newValue instanceof Promise的判斷,并將當(dāng)前的_state=3,self._value = newValue,然后進(jìn)入 finale 方法體,在 handle 方法做了核心處理,這個(gè)下面介紹 handle 方法會說到;

這里有一個(gè)注意點(diǎn),resolve 的 value 可能是其他框架的 Promise(比如:global.Promise,nodejs 內(nèi)部的 Promise 實(shí)現(xiàn)) 構(gòu)造實(shí)例,所以在typeof then === "function"條件下做了doResolve(bind(then, newValue), self);的重新調(diào)用,繼續(xù)執(zhí)行當(dāng)前類型的 Promise then 方法,即又重新回到了doResolve流程。

如果這里的實(shí)現(xiàn)方式稍微調(diào)整下,即不管newValue是自身的 Promise 實(shí)例還是其他框架實(shí)現(xiàn)的 Promise實(shí)例,都執(zhí)行doResolve(bind(then, newValue), self)也能行得通,只不過會多執(zhí)行 then 方式一次,從代碼性能上說,上面的實(shí)現(xiàn)方式會更好。參照代碼如下

function resolve(self, newValue) {
  try {
    // Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
    if (newValue === self)
      throw new TypeError("A promise cannot be resolved with itself.");
    if (
      newValue &&
      (typeof newValue === "object" || typeof newValue === "function")
    ) {
      // 這里簡單粗暴處理,無論是 Promise 還是 global.Promise
      // 都直接調(diào)用doResolve
      var then = newValue.then;
      if (typeof then === "function") {
        doResolve(bind(then, newValue), self);
        return;
      }
    }
    //  resolve 正常值的流程,_state = 1
    self._state = 1;
    self._value = newValue;
    finale(self);
  } catch (e) {
    reject(self, e);
  }
}

所有 resolve 和 reject 的值最終都會去到finale函數(shù)中去處理,只不過在這里的_state狀態(tài)會有所不同;當(dāng)Promise 出現(xiàn)reject的情況時(shí),而沒有提供 onRejected 函數(shù)時(shí),內(nèi)部會打印一個(gè)錯(cuò)誤出來,提示要捕獲錯(cuò)誤。代碼實(shí)現(xiàn)即

const pro = new Promise((resolve,reject)=>{setTimeout(function () {
  reject(100);
},1000)});
pro.then(data => console.log(data));  // 會報(bào)錯(cuò)
pro.then(data => console.log(data)).catch();  // 會報(bào)錯(cuò)
pro.then(data => console.log(data)).catch(()=>{});  // 不會報(bào)錯(cuò)
pro.then(data => console.log(data),()=>{})  // 不會報(bào)錯(cuò)
then、catch、finally 方法

第二步,調(diào)用 then 方法來處理回調(diào),支持無限鏈?zhǔn)秸{(diào)用,then 方法第一個(gè)參數(shù)成功回調(diào),第二個(gè)參數(shù)失敗或者異?;卣{(diào)

源碼

function noop() {}

Promise.prototype.then = function(onFulfilled, onRejected) {
  var prom = new this.constructor(noop);
  handle(this, new Handler(onFulfilled, onRejected, prom));
  return prom;
};

Promise.prototype["catch"] = function(onRejected) {
  return this.then(null, onRejected);
};

Promise.prototype["finally"] = function(callback) {
  var constructor = this.constructor;
  return this.then(
    function(value) {
      return constructor.resolve(callback()).then(function() {
        return value;
      });
    },
    function(reason) {
      return constructor.resolve(callback()).then(function() {
        return constructor.reject(reason);
      });
    }
  );
};

Promise.prototype.then方法內(nèi)部構(gòu)造了一個(gè)新的Promsie 實(shí)例并返回,這樣從 api 角度解決了 Promise 鏈?zhǔn)秸{(diào)用的問題,而且值得注意的是,每個(gè) then 方法返回的都是一個(gè)新的 Promise 對象,并不是當(dāng)前的 this鏈接調(diào)用方式。最終的處理都會調(diào)用 handle 方法。

catch方法在 then 方法上做了一個(gè)簡單的封裝,所以從這里也可以看出,then 方法的形參并不是必傳的,catch 只接收onRejected。

finally方法不管是調(diào)用了 then 還是 catch,最終都會執(zhí)行到finally的 callback

核心邏輯:handle方法內(nèi)部實(shí)現(xiàn)

上面說了這么多,最終的 resolve reject 回調(diào)處理都會進(jìn)入到 handle 方法中,來處理onFulfilled 和 onRejected,先看源碼

Promise._immediateFn =
  (typeof setImmediate === "function" &&
    function(fn) {
      setImmediate(fn);
    }) ||
  function(fn) {
    setTimeoutFunc(fn, 0);
  };
  
function handle(self, deferred) {
  // 如果當(dāng)前的self._value instanceof Promise
  // 將self._value => self,接下來處理新 Promise
  while (self._state === 3) {
    self = self._value;
  }
  // self._state=== 0 說明還沒有執(zhí)行 resolve || reject 方法
  // 此處將 handle 掛起
  if (self._state === 0) {
    self._deferreds.push(deferred);
    return;
  }
  self._handled = true;
  // 通過事件循環(huán)異步來做回調(diào)的處理
  Promise._immediateFn(function() {
    // deferred.promise :第一個(gè) Promise then 方法 返回的新 Promise 對象
    // 這里調(diào)用下一個(gè) Promise 對象的 then 方法的回調(diào)函數(shù)
    // 如果當(dāng)前 Promise resolve 了,則調(diào)用下一個(gè) Promise 的 resolve方法,反之,則調(diào)用下一個(gè) Promise 的 reject 回調(diào)
    // 如果當(dāng)前 Promise resolve 了,則調(diào)用下一個(gè) Promise 的 resolve方法
    // cb回調(diào)方法:如果自己有onFulfilled||onRejected方法,則執(zhí)行自己的方法;如果沒有,則調(diào)用下一個(gè) Promise 對象的onFulfilled||onRejected
    var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected;
    // 自己沒有回調(diào)函數(shù),進(jìn)入下一個(gè) Promise 對象的回調(diào)
    if (cb === null) {
      (self._state === 1 ? resolve : reject)(deferred.promise, self._value);
      return;
    }
    // 自己有回調(diào)函數(shù),進(jìn)入自己的回調(diào)函數(shù)
    var ret;
    try {
      ret = cb(self._value);
    } catch (e) {
      reject(deferred.promise, e);
      return;
    }
    // 處理下一個(gè) Promise 的 then 回調(diào)方法
    // ret 作為上一個(gè)Promise then 回調(diào) return的值 => 返回給下一個(gè)Promise then 作為輸入值
    resolve(deferred.promise, ret);
  });
}

self._state === 3,說明當(dāng)前 resolve(promise)方法回傳的值類型為 Promise 對象,
即 self._value instanceOf Promise === true, 將 self=self._value,即當(dāng)前處理變更到了新的 Promise 對象上 ,如果當(dāng)前 promise對象內(nèi)部狀態(tài)是fulfilled或者 rejected,則直接處理onFulfilled 或者 onRejected回調(diào);如果仍然是 padding 狀態(tài),則繼續(xù)等待。這就很好的解釋了為什么resolve(pro1),pro.then的回調(diào)取的值卻是 pro1._value.
從使用角度來看

const pro1 = new Promise(resolve=>{setTimeout(()=>{resolve(100)},1000)})  // 執(zhí)行耗時(shí)1s 的異步任務(wù)
pro.then(()=>pro1).then(data => console.log(data)).catch(err => {});
// 輸出結(jié)果: 正常打印了100,data并不是當(dāng)前的pro1對象

pro1內(nèi)部是耗時(shí)1s 的異步任務(wù),此時(shí)self._state === 0,即內(nèi)部是 Padding 狀態(tài),則將deferred對象 push 到_deferreds數(shù)組里面,然后等待 pro1內(nèi)部調(diào)用resolve(100)時(shí),繼續(xù)上面resolve方法體執(zhí)行

const pro1 = new Promise(resolve=>resolve(100)}) // 執(zhí)行同步任務(wù)
pro.then(()=>pro1).then(data => console.log(data)).catch(err => {});
// 輸出結(jié)果: 正常打印了100,data并不是當(dāng)前的pro1對象

但是如果pro1內(nèi)部是同步任務(wù),立即執(zhí)行的話,當(dāng)前的self._state === 1,即調(diào)過 push 到_deferreds數(shù)組的操作,執(zhí)行最后的onFulfilled, onRejected回調(diào),onFulfilled, onRejected會被放入到事件循環(huán)隊(duì)列里面執(zhí)行,即執(zhí)行到了Promise._immediateFn

Promise._immediateFn回調(diào)函數(shù)放到了事件循環(huán)隊(duì)列里面來執(zhí)行
這里的deferred對象存放了當(dāng)前的onFulfilled和onRejected回調(diào)函數(shù)和下一個(gè) promise 對象。
當(dāng)前對象的onFulfilled和onRejected如果存在時(shí),則執(zhí)行自己的回調(diào);

pro.then(data => data}).then(data => data).catch(err => {});
// 正確寫法: 輸出兩次  data 

注意:then 方法一定要做 return 下一個(gè)值的操作,因?yàn)楫?dāng)前的 ret 值會被帶入到下一個(gè) Promise 對象,即 resolve(deferred.promise, ret)。如果不提供返回值,則第二個(gè) then 的 data 會變成 undefined,即這樣的錯(cuò)誤寫法

pro.then(data => {}}).then(data => data).catch(err => {});
// 錯(cuò)誤寫法: 第二個(gè) then 方法的 data 為 undefined

如果onFulfilled和onRejected回調(diào)不存在,則執(zhí)行下一個(gè) promise 的回調(diào)并攜帶當(dāng)前的_value 值。即可以這樣寫

pro.then().then().then().then(data => {}).catch(err => {});
// 正確寫法: 第四個(gè) then 方法仍然能取到第一個(gè)pro 的內(nèi)部_value 值
// 當(dāng)然前面的三個(gè) then 寫起來毫無用處

所以針對下面的情況:當(dāng)?shù)谝粋€(gè) then 提供了 reject 回調(diào),后面又跟了個(gè) catch 方法。
當(dāng) reject 時(shí),會優(yōu)先執(zhí)行第一個(gè) Promise 的onRejected回調(diào)函數(shù),catch 是在下一個(gè) Promise 對象上的捕獲錯(cuò)誤方法

pro.then(data => data,err => err).catch(err => err);

最終總結(jié):resolve 要么提供帶返回值的回調(diào),要么不提供回調(diào)函數(shù)

靜態(tài)方法:race
Promise.race = function(values) {
  return new Promise(function(resolve, reject) {
    for (var i = 0, len = values.length; i < len; i++) {
      // 因?yàn)閐oResolve方法內(nèi)部 done 變量控制了對 resolve reject 方法只執(zhí)行一次的處理
      // 所以這里實(shí)現(xiàn)很簡單,清晰明了,最快的 Promise 執(zhí)行了  resolve||reject,后面相對慢的 // Promise都不執(zhí)行
      values[i].then(resolve, reject);
    }
  });
};

用法

Promise.race([pro1,pro2,pro3]).then()

race的實(shí)現(xiàn)非常巧妙,對當(dāng)前的 values(必須是 Promise 數(shù)組) for 循環(huán)執(zhí)行每個(gè) Promise 的 then 方法,resolve, reject方法對于所有race中 promise 對象都是公用的,從而利用doResolve內(nèi)部的 done變量,保證了最快執(zhí)行的 Promise 能做 resolve reject 的回調(diào),從而達(dá)到了多個(gè)Promise race 競賽的機(jī)制,誰跑的快執(zhí)行誰。

靜態(tài)方法:all
Promise.all = function(arr) {
  return new Promise(function(resolve, reject) {
    if (!arr || typeof arr.length === "undefined")
      throw new TypeError("Promise.all accepts an array");
    var args = Array.prototype.slice.call(arr);
    if (args.length === 0) return resolve([]);
    var remaining = args.length;

    function res(i, val) {
      try {
        // 如果 val 是 Promise 對象的話,則執(zhí)行 Promise,直到 resolve 了一個(gè)非 Promise 對象
        if (val && (typeof val === "object" || typeof val === "function")) {
          var then = val.then;
          if (typeof then === "function") {
            then.call(
              val,
              function(val) {
                res(i, val);
              },
              reject
            );
            return;
          }
        }
        // 用當(dāng)前resolve||reject 的值重寫 args[i]{Promise} 對象
        args[i] = val;
        // 直到所有的 Promise 都執(zhí)行完畢,則 resolve all 的 Promise 對象,返回args數(shù)組結(jié)果
        if (--remaining === 0) {
          resolve(args);
        }
      } catch (ex) {
        // 只要其中一個(gè) Promise 出現(xiàn)異常,則全部的 Promise 執(zhí)行退出,進(jìn)入 catch異常處理
        // 因?yàn)?resolve 和 reject 回調(diào)有 done 變量的保證只能執(zhí)行一次,所以其他的 Promise 都不執(zhí)行
        reject(ex);
      }
    }

    for (var i = 0; i < args.length; i++) {
      res(i, args[i]);
    }
  });
};

用法

Promise.all([pro1,pro2,pro3]).then()

all 等待所有的 Promise 都執(zhí)行完畢,才會執(zhí)行 Promise.all().then()回調(diào),只要其中一個(gè)出錯(cuò),則直接進(jìn)入錯(cuò)誤回調(diào),因?yàn)閷τ谒?all 中 promise 對象 reject 回調(diào)是公用的,利用doResolve內(nèi)部的 done變量,保證一次錯(cuò)誤終止所有操作。

但是對于 resolve 則不一樣, resolve 回調(diào)函數(shù)通過 res 遞歸調(diào)用自己,從而保證其值_value不為 Promise 類型才結(jié)束,并將_value 賦值到 args 數(shù)組,最后直到所有的數(shù)組Promise都處理完畢由統(tǒng)一的 resolve 方法結(jié)束當(dāng)前的 all 操作,進(jìn)入 then 處理流程。

結(jié)束語

本篇針對 Promise 的所有 api 做了詳細(xì)的代碼解釋和使用場景,篇幅可能過長,看起來比較費(fèi)力,如果有寫的不對的地方歡迎指正。

最后附上我的 github 源碼注釋版鏈接 promise源碼注釋版

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/94207.html

相關(guān)文章

  • React 進(jìn)階設(shè)計(jì)與控制權(quán)問題

    摘要:盤點(diǎn)一下,模式反應(yīng)了典型的控制權(quán)問題。異步狀態(tài)管理與控制權(quán)提到控制權(quán)話題,怎能少得了這樣的狀態(tài)管理工具。狀態(tài)管理中的控制主義和極簡主義了解了異步狀態(tài)中的控制權(quán)問題,我們再從全局角度進(jìn)行分析。 控制權(quán)——這個(gè)概念在編程中至關(guān)重要。比如,輪子封裝層與業(yè)務(wù)消費(fèi)層對于控制權(quán)的爭奪,就是一個(gè)很有意思的話題。這在 React 世界里也不例外。表面上看,我們當(dāng)然希望輪子掌控的事情越多越好:因?yàn)槌橄髮?..

    superw 評論0 收藏0
  • React 進(jìn)階設(shè)計(jì)與控制權(quán)問題

    摘要:盤點(diǎn)一下,模式反應(yīng)了典型的控制權(quán)問題。異步狀態(tài)管理與控制權(quán)提到控制權(quán)話題,怎能少得了這樣的狀態(tài)管理工具。狀態(tài)管理中的控制主義和極簡主義了解了異步狀態(tài)中的控制權(quán)問題,我們再從全局角度進(jìn)行分析。 控制權(quán)——這個(gè)概念在編程中至關(guān)重要。比如,輪子封裝層與業(yè)務(wù)消費(fèi)層對于控制權(quán)的爭奪,就是一個(gè)很有意思的話題。這在 React 世界里也不例外。表面上看,我們當(dāng)然希望輪子掌控的事情越多越好:因?yàn)槌橄髮?..

    rubyshen 評論0 收藏0
  • 前端優(yōu)化 - 收藏集 - 掘金

    摘要:雖然有著各種各樣的不同,但是相同的是,他們前端優(yōu)化不完全指南前端掘金篇幅可能有點(diǎn)長,我想先聊一聊閱讀的方式,我希望你閱讀的時(shí)候,能夠把我當(dāng)作你的競爭對手,你的夢想是超越我。 如何提升頁面渲染效率 - 前端 - 掘金Web頁面的性能 我們每天都會瀏覽很多的Web頁面,使用很多基于Web的應(yīng)用。這些站點(diǎn)看起來既不一樣,用途也都各有不同,有在線視頻,Social Media,新聞,郵件客戶端...

    VincentFF 評論0 收藏0
  • 原理剖析(第 011 篇)Netty之服務(wù)端啟動工作原理分析(下)

    摘要:原理剖析第篇之服務(wù)端啟動工作原理分析下一大致介紹由于篇幅過長難以發(fā)布,所以本章節(jié)接著上一節(jié)來的,上一章節(jié)為原理剖析第篇之服務(wù)端啟動工作原理分析上那么本章節(jié)就繼續(xù)分析的服務(wù)端啟動,分析的源碼版本為二三四章節(jié)請看上一章節(jié)詳見原理剖析第篇之 原理剖析(第 011 篇)Netty之服務(wù)端啟動工作原理分析(下) - 一、大致介紹 1、由于篇幅過長難以發(fā)布,所以本章節(jié)接著上一節(jié)來的,上一章節(jié)為【原...

    Tikitoo 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<