[實踐系列]Promises/A+規范

前言

[實踐系列] 主要是讓我們通過實踐去加深對一些原理的理解。

實踐系列-前端路由

實踐系列-Babel原理

有興趣的同學可以關注 實踐系列 。 求star求follow~

什么是Promise ?

Promise是JS異步編程中的重要概念,異步抽象處理對象,是目前比較流行Javascript異步編程解決方案之一

Promises/A+ 規范

為實現者提供一個健全的、可互操作的 JavaScript promise 的開放標準。

術語

  • 解決 (fulfill) : 指一個 promise 成功時進行的一系列操作,如狀態的改變、回調的執行。雖然規范中用 fulfill 來表示解決,但在后世的 promise 實現多以 resolve 來指代之。
  • 拒絕(reject) : 指一個 promise 失敗時進行的一系列操作。
  • 拒因 (reason) : 也就是拒絕原因,指在 promise 被拒絕時傳遞給拒絕回調的值。
  • 終值(eventual value) : 所謂終值,指的是 promise 被解決時傳遞給解決回調的值,由于 promise 有一次性的特征,因此當這個值被傳遞時,標志著 promise 等待態的結束,故稱之終值,有時也直接簡稱為值(value)。
  • Promise : promise 是一個擁有 then 方法的對象或函數,其行為符合本規范。
  • thenable : 是一個定義了 then 方法的對象或函數,文中譯作“擁有 then 方法”。
  • 異常(exception) : 是使用 throw 語句拋出的一個值。

基本要求

下面我們先來講述Promise/A+ 規范的幾個基本要求。

1. Promise的狀態

一個Promise的當前狀態必須是以下三種狀態中的一種: 等待狀態(Pending) 執行狀態(Fulfilled)拒絕狀態(Rejected)。


const PENDING = 'pending';const FULFILLED = 'fulfilled';const REJECTED = 'rejected';

等待狀態 (Pending)

處于等待態時,promise 需滿足以下條件:

  • 可以遷移至執行態或拒絕態
 if (this.state === PENDING) {this.state = FULFILLED || REJECTED ;}

執行狀態 (Fulfilled)

處于執行態時,promise 需滿足以下條件:

  • 不能遷移至其他任何狀態
  • 必須擁有一個不可變的終值
 this.value = value;

拒絕狀態 (Rejected)

處于拒絕態時,promise 需滿足以下條件:

  • 不能遷移至其他任何狀態
  • 必須擁有一個不可變的據因
 this.reason = reason;

這里的不可變指的是恒等(即可用 === 判斷相等),而不是意味著更深層次的不可變(譯者注:蓋指當 value 或 reason 不是基本值時,只要求其引用地址相等,但屬性值可被更改)

2. Then 方法

一個 promise 必須提供一個 then 方法以訪問其當前值、終值和據因。

promise 的 then 方法接受兩個參數:

promise.then(onFulfilled, onRejected)

參數可選

onFulfilled 和 onRejected 都是可選參數。

  • 如果 onFulfilled 不是函數,其必須被忽略
  • 如果 onRejected 不是函數,其必須被忽略

onFulfilled 特性

如果 onFulfilled 是函數:

  • 當 promise 執行結束后其必須被調用,其第一個參數為 promise 的終值
  • 在 promise 執行結束前其不可被調用
  • 其調用次數不可超過一次

onRejected 特性

如果 onRejected 是函數:

  • 當 promise 被拒絕執行后其必須被調用,其第一個參數為 promise 的據因
  • 在 promise 被拒絕執行前其不可被調用
  • 其調用次數不可超過一次

調用時機

onFulfilled 和 onRejected 只有在執行環境堆棧僅包含平臺代碼時才可被調用 注1

注1 這里的平臺代碼指的是引擎、環境以及 promise 的實施代碼。實踐中要確保 onFulfilled 和 onRejected 方法異步執行,且應該在 then 方法被調用的那一輪事件循環之后的新執行棧中執行。

這個事件隊列可以采用“宏任務(macro - task)”機制或者“微任務(micro - task)”機制來實現。

由于 promise 的實施代碼本身就是平臺代碼(譯者注:即都是 JavaScript),故代碼自身在處理在處理程序時可能已經包含一個任務調度隊列。

調用要求

onFulfilled 和 onRejected 必須被作為函數調用(即沒有 this 值)

多次調用

then 方法可以被同一個 promise 調用多次

  • 當 promise 成功執行時,所有 onFulfilled 需按照其注冊順序依次回調
  • 當 promise 被拒絕執行時,所有的 onRejected 需按照其注冊順序依次回調

簡易版實踐

我們先通過實踐一個簡易版的Promise來消化一下上面Promises/A+規范的基本要求。

首先

npm init // 測試實現是否符合 promises/A+ 規范npm install promises-aplus-tests -D 

package.json

{"name": "ajpromise","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "promises-aplus-tests ./simple.js"},"author": "webfansplz","license": "MIT","devDependencies": {"promises-aplus-tests": "^2.1.2"}
}

simple.js

//Promise 的三種狀態  (滿足要求 -> Promise的狀態)
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class AjPromise {constructor(fn) {//當前狀態this.state = PENDING;//終值this.value = null;//拒因this.reason = null;//成功態回調隊列this.onFulfilledCallbacks = [];//拒絕態回調隊列this.onRejectedCallbacks = [];//成功態回調const resolve = value => {// 使用macro-task機制(setTimeout),確保onFulfilled異步執行,且在 then 方法被調用的那一輪事件循環之后的新執行棧中執行。setTimeout(() => {if (this.state === PENDING) {// pending(等待態)遷移至 fulfilled(執行態),保證調用次數不超過一次。this.state = FULFILLED;// 終值this.value = value;this.onFulfilledCallbacks.map(cb => {this.value = cb(this.value);});}});};//拒絕態回調const reject = reason => {// 使用macro-task機制(setTimeout),確保onRejected異步執行,且在 then 方法被調用的那一輪事件循環之后的新執行棧中執行。 (滿足要求 -> 調用時機)setTimeout(() => {if (this.state === PENDING) {// pending(等待態)遷移至 fulfilled(拒絕態),保證調用次數不超過一次。this.state = REJECTED;//拒因this.reason = reason;this.onRejectedCallbacks.map(cb => {this.reason = cb(this.reason);});}});};try {//執行promisefn(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled, onRejected) {typeof onFulfilled === 'function' && this.onFulfilledCallbacks.push(onFulfilled);typeof onRejected === 'function' && this.onRejectedCallbacks.push(onRejected);// 返回this支持then 方法可以被同一個 promise 調用多次return this;}
}

就這樣,一個簡單的promise就完成了.

new AjPromise((resolve, reject) => {setTimeout(() => {resolve(2);}, 2000);
}).then(res => {console.log(res);return res + 1;}).then(res => {console.log(res);});//output  // delay 2s..
//  2 
//  3 

接下來,我們來看看我們的實現是否完全符合promises/A+規范~

npm run test

GG,測試用例只過了一小部分,大部分飄紅~

OK,接下來,我們來繼續了解promises/A+ 進一步的規范要求~

進一步要求

由于接下來的要求比較抽象和難理解,所以我們將一步一步實踐來加深理解。

1. 返回

  • 1.then方法必須返回一個promise對象
  • 2.如果 onFulfilled 或者 onRejected 返回一個值 x ,則運行下面的 Promise 解決過程:[[Resolve]](promise2, x)
  • 3.如果 onFulfilled 或者 onRejected 拋出一個異常 e ,則 promise2 必須拒絕執行,并返回拒因 e。
  • 4.如果 onFulfilled 不是函數且 promise1 成功執行, promise2 必須成功執行并返回相同的值。
  • 5.如果 onRejected 不是函數且 promise1 拒絕執行, promise2 必須拒絕執行并返回相同的據因。
  • 6.不論 promise1 被 reject 還是被 resolve 時 promise2 都會被 resolve,只有出現異常時才會被 rejected。

我們通過以上要求來一步一步完善then方法
1.

// 1.首先,then方法必須返回一個promise對象then(onFulfilled, onRejected) {let newPromise;return (newPromise = new AjPromise((resolve, reject) => {}));}

2.

  then(onFulfilled, onRejected) {let newPromise;return (newPromise = new AjPromise((resolve, reject) => {// 2.如果 onFulfilled 或者 onRejected 返回一個值 x ,則運行下面的 Promise 解決過程:[[Resolve]](promise2, x)this.onFulfilledCallbacks.push(value => {let x = onFulfilled(value);//解決過程 resolvePromiseresolvePromise(newPromise, x);});this.onRejectedCallbacks.push(reason => {let x = onRejected(reason);//解決過程 resolvePromiseresolvePromise(newPromise, x);});}));}// 解決過程function resolvePromise() {//...}

3.

  then(onFulfilled, onRejected) {let newPromise;return (newPromise = new AjPromise((resolve, reject) => {//  3.如果 onFulfilled 或者 onRejected 拋出一個異常 e ,則 promise2 必須拒絕執行,并返回拒因 e。this.onFulfilledCallbacks.push(value => {try {let x = onFulfilled(value);resolvePromise(newPromise, x);} catch (e) {reject(e);}});this.onRejectedCallbacks.push(reason => {try {let x = onRejected(reason);resolvePromise(newPromise, x);} catch (e) {reject(e);}});}));}

4,5.

  then(onFulfilled, onRejected) {  let newPromise;// 4.如果 onFulfilled 不是函數且 promise1 成功執行, promise2 必須成功執行并返回相同的值。onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;// 5.如果 onRejected 不是函數且 promise1 拒絕執行, promise2 必須拒絕執行并返回相同的據因。onRejected =typeof onRejected === 'function'? onRejected: reason => {throw reason;};return (newPromise = new AjPromise((resolve, reject) => {this.onFulfilledCallbacks.push(value => {try {let x = onFulfilled(value);resolvePromise(newPromise, x);} catch (e) {reject(e);}});this.onRejectedCallbacks.push(reason => {try {let x = onRejected(reason);resolvePromise(newPromise, x);} catch (e) {reject(e);}});}));}

6.

  then(onFulfilled, onRejected) {let newPromise;onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected =typeof onRejected === 'function'? onRejected: reason => {throw reason;};// 2.2.6規范 對于一個promise,它的then方法可以調用多次.// 當在其他程序中多次調用同一個promise的then時 由于之前狀態已經為FULFILLED / REJECTED狀態,則會走以下邏輯,// 所以要確保為FULFILLED / REJECTED狀態后 也要異步執行onFulfilled / onRejected ,這里使用setTimeout// 6.不論 promise1 被 reject 還是被 resolve 時 promise2 都會被 resolve,只有出現異常時才會被 rejected。// 由于在接下來的解決過程中需要調用resolve,reject進行處理,處理我們在調用處理過程時,傳入參數if (this.state == FULFILLED) {  return (newPromise = new AjPromise((resolve, reject) => {setTimeout(() => {try {let x = onFulfilled(this.value);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});}));}if (this.state == REJECTED) {return (newPromise = new AjPromise((resolve, reject) => {setTimeout(() => {try {let x = onRejected(this.reason);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});}));}if (this.state === PENDING) {return (newPromise = new AjPromise((resolve, reject) => {this.onFulfilledCallbacks.push(value => {try {let x = onFulfilled(value);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});this.onRejectedCallbacks.push(reason => {try {let x = onRejected(reason);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});}));}}

ok,完整的then方法搞定了。相信通過以上實踐,你對返回要求已經有了更深的理解。

2. Promise 解決過程

Promise 解決過程是一個抽象的操作,其需輸入一個 promise 和一個值,我們表示為 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一個 Promise ,解決程序即嘗試使 promise 接受 x 的狀態;否則其用 x 的值來執行 promise 。

這種 thenable 的特性使得 Promise 的實現更具有通用性:只要其暴露出一個遵循 Promise/A+ 協議的 then 方法即可;這同時也使遵循 Promise/A+ 規范的實現可以與那些不太規范但可用的實現能良好共存。

運行 [[Resolve]](promise, x) 需遵循以下步驟:

1。x 與 promise 相等

如果 promise 和 x 指向同一對象,以 TypeError 為據因拒絕執行 promise。

2。x 為 Promise

  • 如果 x 為 Promise ,則使 promise 接受 x 的狀態。
  • 如果 x 處于等待態, promise 需保持為等待態直至 x 被執行或拒絕。
  • 如果 x 處于執行態,用相同的值執行 promise。
  • 如果 x 處于拒絕態,用相同的據因拒絕 promise。

3。x 為對象或函數

如果 x 為對象或者函數:

  • 把 x.then 賦值給 then。
  • 如果取 x.then 的值時拋出錯誤 e ,則以 e 為據因拒絕 promise。
  • 如果 then 是函數,將 x 作為函數的作用域 this 調用之。傳遞兩個回調函數作為參數,第一個參數叫做 resolvePromise ,第二個參數叫做 rejectPromise:

    • 如果 resolvePromise 以值 y 為參數被調用,則運行 [[Resolve]](promise, y)
    • 如果 rejectPromise 以據因 r 為參數被調用,則以據因 r 拒絕 promise
    • 如果 resolvePromise 和 rejectPromise 均被調用,或者被同一參數調用了多次,則優先采用首次調用并忽略剩下的調用
    • 如果調用 then 方法拋出了異常 e:

      • 如果 resolvePromise 或 rejectPromise 已經被調用,則忽略之
      • 否則以 e 為據因拒絕 promise
    • 如果 then 不是函數,以 x 為參數執行 promise
  • 如果 x 不為對象或者函數,以 x 為參數執行 promise

如果一個 promise 被一個循環的 thenable 鏈中的對象解決,而 [[Resolve]](promise, thenable) 的遞歸性質又使得其被再次調用,根據上述的算法將會陷入無限遞歸之中。算法雖不強制要求,但也鼓勵施者檢測這樣的遞歸是否存在,若檢測到存在則以一個可識別的 TypeError 為據因來拒絕 promise 。

1.x 與 promise 相等

function resolvePromise(promise2, x, resolve, reject) {//x 與 promise 相等 //如果從onFulfilled中返回的x 就是promise2 就會導致循環引用報錯//如果 promise 和 x 指向同一對象,以 TypeError 為據因拒絕執行 promiseif (x === promise2) {reject(new TypeError('循環引用'));}
}

2.x 為 Promise。

function resolvePromise(promise2, x, resolve, reject) {if (x === promise2) {reject(new TypeError('循環引用'));}// x 為 Promiseelse if (x instanceof AjPromise) {// 如果 x 為 Promise ,則使 promise 接受 x 的狀態// 如果 x 處于等待態, promise 需保持為等待態直至 x 被執行或拒絕if (x.state === PENDING) {x.then(y => {resolvePromise(promise2, y, resolve, reject);},reason => {reject(reason);});} else {// 如果 x 處于執行態,用相同的值執行 promise// 如果 x 處于拒絕態,用相同的據因拒絕 promisex.then(resolve, reject);}}
}

3.x 為對象或函數

function resolvePromise(promise2, x, resolve, reject) {if (x === promise2) {reject(new TypeError('循環引用'));}if (x instanceof AjPromise) {if (x.state === PENDING) {x.then(y => {resolvePromise(promise2, y, resolve, reject);},reason => {reject(reason);});} else {x.then(resolve, reject);}} else if (x && (typeof x === 'function' || typeof x === 'object')) {// 避免多次調用let called = false;try {//把 x.then 賦值給 thenlet then = x.then;if (typeof then === 'function') {// 如果 then 是函數,將 x 作為函數的作用域 this 調用之。// 傳遞兩個回調函數作為參數,第一個參數叫做 resolvePromise ,第二個參數叫做 rejectPromise// 如果 resolvePromise 和 rejectPromise 均被調用,或者被同一參數調用了多次,則優先采用首次調用并忽略剩下的調用then.call(x,// 如果 resolvePromise 以值 y 為參數被調用,則運行[[Resolve]](promise, y)y => {if (called) return;called = true;resolvePromise(promise2, y, resolve, reject);},// 如果 rejectPromise 以據因 r 為參數被調用,則以據因 r 拒絕 promiser => {if (called) return;called = true;reject(r);});}else {// 如果 then 不是函數,以 x 為參數執行 promiseresolve(x);}  } catch (e) {// 如果取 x.then 的值時拋出錯誤 e ,則以 e 為據因拒絕 promise// 如果調用 then 方法拋出了異常 e:// 如果 resolvePromise 或 rejectPromise 已經被調用,則忽略之// 否則以 e 為據因拒絕 promiseif (called) return;called = true;reject(e);}} else {// 如果 x 不為對象或者函數,以 x 為參數執行 promiseresolve(x);}
}

Ok~比較復雜的解決過程也讓我們搞定了.接下來我們整合下代碼

Promises/A+ 規范 實踐


const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';class AjPromise {constructor(fn) {this.state = PENDING;this.value = null;this.reason = null;this.onFulfilledCallbacks = [];this.onRejectedCallbacks = [];const resolve = value => {if (value instanceof Promise) {return value.then(resolve, reject);}setTimeout(() => {if (this.state === PENDING) {this.state = FULFILLED;this.value = value;this.onFulfilledCallbacks.map(cb => {cb = cb(this.value);});}});};const reject = reason => {setTimeout(() => {if (this.state === PENDING) {this.state = REJECTED;this.reason = reason;this.onRejectedCallbacks.map(cb => {cb = cb(this.reason);});}});};try {fn(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled, onRejected) {let newPromise;onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected =typeof onRejected === 'function'? onRejected: reason => {throw reason;};if (this.state === FULFILLED) {return (newPromise = new AjPromise((resolve, reject) => {setTimeout(() => {try {let x = onFulfilled(this.value);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});}));}if (this.state === REJECTED) {return (newPromise = new AjPromise((resolve, reject) => {setTimeout(() => {try {let x = onRejected(this.reason);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});}));}if (this.state === PENDING) {return (newPromise = new AjPromise((resolve, reject) => {this.onFulfilledCallbacks.push(value => {try {let x = onFulfilled(value);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});this.onRejectedCallbacks.push(reason => {try {let x = onRejected(reason);resolvePromise(newPromise, x, resolve, reject);} catch (e) {reject(e);}});}));}}
}
function resolvePromise(promise2, x, resolve, reject) {if (x === promise2) {reject(new TypeError('循環引用'));}if (x instanceof AjPromise) {if (x.state === PENDING) {x.then(y => {resolvePromise(promise2, y, resolve, reject);},reason => {reject(reason);});} else {x.then(resolve, reject);}} else if (x && (typeof x === 'function' || typeof x === 'object')) {let called = false;try {let then = x.then;if (typeof then === 'function') {then.call(x,y => {if (called) return;called = true;resolvePromise(promise2, y, resolve, reject);},r => {if (called) return;called = true;reject(r);});} else {resolve(x);}} catch (e) {if (called) return;called = true;reject(e);}} else {resolve(x);}
}AjPromise.deferred = function() {let defer = {};defer.promise = new AjPromise((resolve, reject) => {defer.resolve = resolve;defer.reject = reject;});return defer;
};module.exports = AjPromise;

再來看看我們的實現是否符合Promises/A+規范

npm run test

nice,測試用例全部通過!

源碼地址

傳送門

如果覺得有幫助到你,請給個star支持下作者~

參考文獻

Promises/A+規范譯文

Promise詳解與實現

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/276131.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276131.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276131.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Web Components 上手指南

現在的前端開發基本離不開 React、Vue 這兩個框架的支撐,而這兩個框架下面又衍生出了許多的自定義組件庫:Element(Vue)Ant Design(React)這些組件庫的出現,讓我們可以直接使用已經封裝好的組件&…

隱藏網頁文件的后綴(IIS測試通過)!

網上很多網站會看到如這樣的地址: /content?actadd&id1 /column?actedit&id2 原本是 /content.asp?actadd&id1 /column.asp?actedit&id2 這樣的效果就是在iis上做了下手腳,使用了rewrite重寫組件,就可以實現。 rewrite.rar轉載于:ht…

Linux下查看文件內容的ASCII碼以檢查內容的編碼一致

轉載鏈接:http://blog.csdn.net/tiantang46800/article/details/6460567 ascii查詢方式,查看文件以ascii顯示,od命令 隨著計算機飛速的發展,很多人開始學習Linux,怎樣才能學好Linux,一定要學好Linux的命令…

乘基取整法是什么_十進制小數轉二進制小數乘2取整法的直觀理解

乘2取整法介紹舉例:0.35轉換成二進制0.3520.7 取0(d1)0.721.4 取1(d2)0.420.8 取0(d3)0.821.6 取1(d4)0.621.2 取1(d5)0.220.4 取0(d6)直到滿足規定的位數為止所以(0.35)10(0.d1d2d3d4d5d6)2(0.010110)2這個方法不難掌握,就是有點不好理解&#xf…

如何遠程連接Windows和linux服務器

linux的方法在下面 Windows服務器遠程連接 登錄控制臺查看服務器系統是什么系統例如阿里云的ECS服務器 Windows系統可以使用微軟自帶的遠程工具進行連接,可以連接的系統有Windows server 和Windows 7-10 等等系列;Windows系統,例如Windows10系…

URL是什么

URL是什么意思? 懸賞分:0 - 提問時間2006-3-12 08:14我在玩QQ空間的時候,在添加音樂時會有一個添加URL的地方‘~我是想問那是什么意思???提問者: caoyiwang1107 - 魔法學徒 一級 其他…

手把手教你接入前端熱門抓包神器 - whistle

大家好,我是若川,今天推薦騰訊前端團隊的這篇好文。whistle 是一個基于 Node.js 的跨平臺網絡調試工具。最近隨著 Nohost 的開源,有不少同學問了 whistle 相關的問題,本篇文章將結合幾個常見的業務場景介紹如何在本地前端項目開發…

Linux命令之hexdump - ”十六“進制查看器

轉載鏈接:http://codingstandards.iteye.com/blog/805778 用途說明 hexdump命令一般用來查看”二進制“文件的十六進制編碼,但實際上它的用途不止如此,手冊頁上的說法是“ascii, decimal, hexadecimal, octal dump“,這也就是本文…

使用數據增強技術提升模型泛化能力

在《提高模型性能,你可以嘗試這幾招...》一文中,我們給出了幾種提高模型性能的方法,但這篇文章是在訓練數據集不變的前提下提出的優化方案。其實對于深度學習而言,數據量的多寡通常對模型性能的影響更大,所以擴充數據規…

關于不同用戶進入系統報錯的請求

我自己搞了個系統,用超級用戶進入系統正常,用普通用戶進入系統就報錯,Microsoft JET Database Engine (0x80040E07) 標準表達式中數據類型不匹配。 /xs/huiyuan/huiyuan_bf.asp, 第 203 行 代碼如下請各位高手幫忙 <% if request.Cookies("shiwei_username")"…

React 與 Vue 框架的設計思路大 PK

大家好&#xff0c;我是若川。今天分享一篇框架設計思路的好文。關于我 大家好我是花果山的大圣&#xff0c;今天很榮幸&#xff0c;有機會跟大家分享一下很多年輕人感興趣的話題《 Vue 和 React 設計思想 PK》,個人水平有限&#xff0c;如果有理解不到位的請傾盆&#xff0c;大…

php foreach id是否存在數組_請糾正這 5 個 PHP 編碼小陋習

在做過大量的代碼審查后&#xff0c;我經常看到一些重復的錯誤&#xff0c;以下是糾正這些錯誤的方法。在循環之前測試數組是否為空$items [];// ...if (count($items) > 0) {foreach ($items as $item) {// process on $item ...}}foreach以及數組函數 (array_*) 可以處理…

1161轉進制(C語言)

一&#xff1a;題目 二&#xff1a;思路分析 1.首先該題目讓我們使用遞歸求十進制轉其他進制 2.其次&#xff0c;我們要知道十進制轉換為其他進制怎么轉換&#xff0c;以例題所給的數據為例 由此圖可以看出&#xff0c;十進制轉換為其他進制&#xff0c;是輾轉相除法&#xf…

PHP異常處理

轉載鏈接&#xff1a;http://www.blogdaren.com/post-2030.html 版權聲明&#xff1a;除非注明&#xff0c;本文由( manon )原創&#xff0c;轉載請保留文章出處 本文鏈接&#xff1a;PHP register_shutdown_function函數詳解 腳本時常死掉,而且并不總是那么好看. 我們可不想…

應對無協議脫歐 葡萄牙機場將為英籍旅客設快速通道

中新網1月18日電 據臺灣《聯合報》援引英媒報道&#xff0c;英國首相特蕾莎?梅的脫歐協議遭下院否決后&#xff0c;英國無協議脫歐的可能性變大。葡萄牙總理科斯塔17日表示&#xff0c;里斯本當局正對機場開設特殊通道進行規劃&#xff0c;使英國旅客無論英國最后如何脫歐&…

javascript 日期控件

http://www.my97.net/dp/index.asp轉載于:https://www.cnblogs.com/Ken-Cai/archive/2010/04/08/1707080.html

6輪字節前端校招面試經驗分享

大家好&#xff0c;我是若川。最近金三銀四&#xff0c;今天分享一篇字節前端校招面試經驗的輕松好文&#xff0c;相信看完會有所收獲。也歡迎點擊下方卡片關注或者星標我的公眾號若川視野因為我錯過了2020年的秋招&#xff08;ps: 那時候連數據結構與算法都還沒學完&#xff0…

redis存opc_Redis集群的三種模式

一、主從模式通過持久化功能&#xff0c;Redis保證了即使在服務器重啟的情況下也不會損失(或少量損失)數據&#xff0c;因為持久化會把內存中數據保存到硬盤上&#xff0c;重啟會從硬盤上加載數據。但是由于數據是存儲在一臺服務器上的&#xff0c;如果這臺服務器出現硬盤故障等…

斥資近1億港元,小米二次回購

1月21日消息&#xff0c;小米集團發布公告稱&#xff0c;公司于1月18日回購了984.96萬股B類普通股股票&#xff0c;占已發行股份0.041%&#xff0c;平均價為每股B類股10.1527港元&#xff0c;總計斥資近1億港元。 這也是繼1月17日首次回購后&#xff0c;小米集團連續兩日出手進…

MySQL日期數據類型、時間類型使用總結

轉載鏈接&#xff1a;http://www.jb51.net/article/23966.htm MySQL 日期類型&#xff1a;日期格式、所占存儲空間、日期范圍 比較。 日期類型 存儲空間 日期格式 日期范圍 ------------ --------- --------------------- -------------------------------…