javascript 作用_JavaScript承諾如何從內到外真正發揮作用

javascript 作用

One of the most important questions I faced in interviews was how promises are implemented. Since async/await is becoming more popular, you need to understand promises.

我在采訪中面臨的最重要的問題之一是如何實現承諾。 由于異步/等待變得越來越流行,因此您需要了解Promise。

什么是諾言? (What is a Promise?)

A promise is an object which represents the result of an asynchronous operation which is either resolved or rejected (with a reason).

一個promise是一個對象,它表示異步操作的結果,該結果被解決或被拒絕(有原因)。

There are 3 states

有3個州

  • Fulfilled: onFulfilled() will be called (e.g., resolve() was called)

    已實現:將調用onFulfilled() (例如,調用了resolve() )

  • Rejected: onRejected() will be called (e.g., reject() was called)

    拒絕:將調用onRejected() (例如,調用了reject() )

  • Pending: not yet fulfilled or rejected

    待處理:尚未實現或拒絕

So let’s see how’s it is implemented:

因此,讓我們看看它是如何實現的:

https://github.com/then/promise/blob/master/src/core.js

https://github.com/then/promise/blob/master/src/core.js

According to the definition at Mozilla: It takes an executor function as an argument.

根據Mozilla的定義:它以執行程序函數作為參數。

function noop() {} function Promise(executor) {if (typeof this !== 'object') {throw new TypeError('Promises must be constructed via new');}if (typeof executor !== 'function') {throw new TypeError('Promise constructor\'s argument is not a function');}this._deferredState = 0;this._state = 0;this._value = null;this._deferreds = null;if (executor === noop) return;doResolve(executor, this);
}

Looks like a simple function with some properties initialized to 0 or null. Here are a few things to notice:

看起來像一個簡單的函數,其某些屬性初始化為0null 。 這里有一些注意事項:

this._state property can have three possible values as described above:

this._state 屬性可以具有三個如上所述的可能值:

0 - pending1 - fulfilled with _value2 - rejected with _value3 - adopted the state of another promise, _value

Its value is0 (pending) when you create a new promise.

創建新的承諾時,其值為0 ( 待定)

Later doResolve(executor, this) is invoked with executor and promise object.

之后, doResolve(executor, this)executor and promise對象一起調用。

Let’s move on to the definition of doResolve and see how it’s implemented.

讓我們繼續進行doResolve的定義,看看它是如何實現的。

/**
* Take a potentially misbehaving resolver function and make sure
* onFulfilled and onRejected are only called once.
*
* Makes no guarantees about asynchrony.
*/function doResolve(fn, promise) {var done = false;var resolveCallback = function(value) {if (done) return;done = true;resolve(promise, value);};var rejectCallback = function(reason) {if (done) return;done = true;reject(promise, reason);
};var res = tryCallTwo(fn, resolveCallback, rejectCallback);if (!done && res === IS_ERROR) {done = true;reject(promise, LAST_ERROR);}
}

Here it is again calling tryCallTwo function with executor and 2 callbacks. The callbacks are again calling resolve and reject

在這里,它再次使用executor和2個回調調用tryCallTwo函數。 回調再次調用resolvereject

The done variable is used here to make sure the promise is resolved or rejected only once, so if you try to reject or resolve a promise more than once then it will return because done = true.

這里, done變量用于確保僅對諾言進行一次解析或拒絕,因此,如果您多次嘗試拒絕或解決諾言,則它將返回,因為done = true

function tryCallTwo(fn, a, b) {try {fn(a, b);} catch (ex) {LAST_ERROR = ex;return IS_ERROR;}
}

This function indirectly calls the main executor callback with 2 arguments. These arguments contain logic on how resolve or reject should be called. You can check resolveCallback and rejectCallback in doResolve function above.

此函數使用2個參數間接調用主executor回調。 這些參數包含有關如何調用resolvereject邏輯。 您可以在上面的doResolve函數中檢查resolveCallbackrejectCallback

If there is an error during execution it will store the error in LAST_ERROR and return the error.

如果執行期間發生錯誤,它將錯誤存儲在LAST_ERROR并返回錯誤。

Before we jump to the resolve function definition, let’s check out the .then function first:

在跳轉到resolve函數定義之前,讓我們先檢查.then函數:

Promise.prototype.then = function(onFulfilled, onRejected) {if (this.constructor !== Promise) {return safeThen(this, onFulfilled, onRejected);}var res = new Promise(noop);handle(this, new Handler(onFulfilled, onRejected, res));return res;
};function Handler(onFulfilled, onRejected, promise) {this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled  : null;this.onRejected = typeof onRejected === "function" ? onRejected :  null;this.promise = promise;
}

So in the above function, then is creating new promise and assigning it as a property to a new function called Handler. The Handler function has arguments onFulfilled and onRejected. Later it will use this promise to resolve or reject with value/reason.

因此,在上述函數中,將創建新的promise并將其作為屬性分配給一個名為Handler的新函數。 Handler函數具有onFulfilledonRejected參數 稍后,它將使用此承諾以價值/理由來解決或拒絕。

As you can see, the .then function is calling again another function:

如您所見, .then函數再次調用另一個函數:

handle(this, new Handler(onFulfilled, onRejected, res));

實現方式: (Implementation:)

function handle(self, deferred) {while (self._state === 3) {self = self._value;}if (Promise._onHandle) {Promise._onHandle(self);}if (self._state === 0) {if (self._deferredState === 0) {self._deferredState = 1;self._deferreds = deferred;return;}if (self._deferredState === 1) {self._deferredState = 2;self._deferreds = [self._deferreds, deferred];return;}self._deferreds.push(deferred);return;}handleResolved(self, deferred);
}
  • There is a while loop which will keep assigning the resolved promise object to the current promise which is also a promise for _state === 3

    有一個while循環,它將繼續將解析的promise對象分配給當前的promise,這也是_state === 3的promise

  • If _state = 0(pending) and promise state has been deferred until another nested promise is resolved, its callback is stored in self._deferreds

    如果_state = 0(pending)并且承諾狀態已推遲到另一個嵌套的承諾被解決,則其回調存儲在self._deferreds

function handleResolved(self, deferred) {asap(function() { // asap is external lib used to execute cb immediatelyvar cb = self._state === 1 ? deferred.onFulfilled :     deferred.onRejected;if (cb === null) {if (self._state === 1) {resolve(deferred.promise, self._value);} else {reject(deferred.promise, self._value);}return;}var ret = tryCallOne(cb, self._value);if (ret === IS_ERROR) {reject(deferred.promise, LAST_ERROR);} else {resolve(deferred.promise, ret);}});
}

What's happening:

發生了什么:

  • If the state is 1(fulfilled) then call the resolve else reject

    如果狀態為1 (fulfilled)則調用解決方法 else 拒絕

  • If onFulfilled or onRejected is null or if we used an empty .then() resolved or reject will be called respectively

    如果onFulfilledonRejectednull或如果我們使用一個空.then() 解析拒絕將分別被調用

  • If cb is not empty then it is calling another function tryCallOne(cb, self._value)

    如果cb不為空,則它正在調用另一個函數tryCallOne(cb, self._value)

function tryCallOne(fn, a) {try {return fn(a);} catch (ex) {LAST_ERROR = ex;return IS_ERROR;}
} a) {

tryCallOne : This function only calls the callback that is passed into the argument self._value. If there is no error it will resolve the promise, otherwise it will reject it.

tryCallOne 此函數僅調用傳遞到參數self._value的回調。 如果沒有錯誤,它將解決承諾,否則將拒絕它。

Every promise must supply a .then() method with the following signature:

每個Promise必須提供具有以下簽名的.then()方法:

promise.then(onFulfilled?: Function,onRejected?: Function
) => Promise
  • Both onFulfilled() and onRejected() are optional.

    onFulfilled()onRejected()都是可選的。

  • If the arguments supplied are not functions, they must be ignored.

    如果提供的參數不是函數,則必須將其忽略。
  • onFulfilled() will be called after the promise is fulfilled, with the promise’s value as the first argument.

    在實現諾言之后,將調用onFulfilled() ,并將諾言的值作為第一個參數。

  • onRejected() will be called after the promise is rejected, with the reason for rejection as the first argument.

    在拒絕承諾后,將調用onRejected()并將拒絕的原因作為第一個參數。

  • Neither onFulfilled() nor onRejected() may be called more than once.

    onFulfilled()onRejected()不得被調用一次以上。

  • .then() may be called many times on the same promise. In other words, a promise can be used to aggregate callbacks.

    .then()可能在同一諾言中被多次調用。 換句話說,promise可以用于聚集回調。

  • .then() must return a new promise.

    .then()必須返回新的諾言。

承諾鏈 (Promise Chaining)

.then should return a promise. That's why we can create a chain of promises like this:

.then應該兌現承諾。 這就是為什么我們可以創建如下這樣的承諾鏈:

Promise
.then(() => Promise.then(() => Promise.then(result => result) 
)).catch(err)

兌現諾言 (Resolving a promise)

Let’s see the resolve function definition that we left earlier before moving on to .then():

讓我們看一下在繼續.then()之前我們留下的resolve函數定義:

function resolve(self, newValue) {
// Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedureif (newValue === self) {return reject(self,new TypeError("A promise cannot be resolved with itself."));}if (newValue &&(typeof newValue === "object" || typeof newValue === "function")) {var then = getThen(newValue);if (then === IS_ERROR) {return reject(self, LAST_ERROR);}if (then === self.then && newValue instanceof Promise) {self._state = 3;self._value = newValue;finale(self);return;} else if (typeof then === "function") {doResolve(then.bind(newValue), self);return;}
}self._state = 1;self._value = newValue;finale(self);
}
  • We check if the result is a promise or not. If it’s a function, then call that function with value using doResolve().

    我們檢查結果是否是一個承諾。 如果它是一個函數,則使用doResolve()以值調用該函數。

  • If the result is a promise then it will be pushed to the deferreds array. You can find this logic in the finale function.

    如果結果是一個承諾,那么它將被推送到deferreds數組。 您可以在finale功能中找到此邏輯。

拒絕承諾: (Rejecting a promise:)

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

The above function can be found in ./es6-extensions.js.

可以在./es6-extensions.js找到以上功能。

Whenever we reject a promise, the .catch callback is called which is a sugar coat for then(null, onRejected).

每當我們拒絕承諾時, .catch調用.catch回調,這是then(null, onRejected)

Here is the basic rough diagram that I have created which is a birds-eye view of what's happening inside:

這是我創建的基本示意圖,它是內部情況的鳥瞰圖:

Let’s see once again how everything is working:

讓我們再次看看一切如何進行:

For example, we have this promise:

例如,我們有以下承諾:

new Promise((resolve, reject) => {setTimeout(() => {resolve("Time is out");}, 3000)
})
.then(console.log.bind(null, 'Promise is fulfilled'))
.catch(console.error.bind(null, 'Something bad happened: '))
  1. Promise constructor is called and an instance is created with new Promise

    調用Promise constructor ,并使用new Promise創建實例

  2. executor function is passed to doResolve(executor, this) and callback where we have defined setTimeout will be called by tryCallTwo(executor, resolveCallback, rejectCallback)so it will take 3 seconds to finish

    executor函數傳遞給doResolve(executor, this)tryCallTwo(executor, resolveCallback, rejectCallback)將調用我們定義了setTimeout回調,因此需要3秒鐘才能完成

  3. We are calling .then() over the promise instance so before our timeout is completed or any async api returns, Promise.prototype.then will be called as .then(cb, null)

    我們在promise實例上調用.then() ,因此在timeout或任何異步api返回之前, Promise.prototype.then將被稱為Promise.prototype.then .then(cb, null)

  4. .then creates a new promise and passes it as an argument to new Handler(onFulfilled, onRejected, promise)

    .then創建一個新的promise并將其作為參數傳遞給new Handler(onFulfilled, onRejected, promise)

  5. handle function is called with the original promise instance and the handler instance we created in point 4.

    使用原始promise實例和我們在第4點中創建的handler實例調用handle函數。

  6. Inside the handle function, current self._state = 0 and self._deferredState = 0 so self_deferredState will become 1 and handler instance will be assigned to self.deferreds after that control will return from there

    里面的handle功能,目前self._state = 0self._deferredState = 0這樣self_deferredState將成為1handler實例將被分配到self.deferreds后控制將回到那里

  7. After .then() we are calling .catch() which will internally call .then(null, errorCallback) — again the same steps are repeated from point 4 to point 6 and skip point 7 since we called .catch once

    .catch()之后.then()我們將調用.catch() ,該方法將在內部調用.then(null, errorCallback) -再次,從點4到點6重復相同的步驟, 并跳過點7,因為我們一次調用.catch

  8. Current promise state is pending and it will wait until it is resolved or rejected. So in this example, after 3 seconds, setTimeout callback is called and we are resolving this explicitly which will call resolve(value).

    當前的promise狀態處于掛起狀態,它將等待直到解決或拒絕該狀態。 因此,在此示例中,在3秒鐘后,調用了setTimeout回調,并且我們正在明確解決此問題,這將調用resolve(value)

  9. resolveCallback will be called with value Time is out :) and it will call the main resolve function which will check if value !== null && value == 'object' && value === 'function'

    resolveCallback值將為Time is out :),它將調用主resolve函數,該函數將檢查value !== null && value == 'object' && value === 'function'

  10. It will fail in our case since we passed string and self._state will become 1 with self._value = 'Time is out' and later finale(self) is called.

    因為我們通過它會在我們的案例失敗stringself._state將成為1self._value = 'Time is out' ,后來finale(self)被調用。

  11. finale will call handle(self, self.deferreds) once because self._deferredState = 1, and for the chain of promises, it will call handle() for each deferred function.

    由于self._deferredState = 1finale將調用一次handle(self, self.deferreds) ,對于諾言鏈,它將為每個deferred函數調用handle()

  12. In the handle function, since promise is resolved already, it will call handleResolved(self, deferred)

    handle函數中,由于promise已經解決,它將調用handleResolved(self, deferred)

  13. handleResolved function will check if _state === 1 and assign cb = deferred.onFulfilled which is our then callback. Later tryCallOne(cb, self._value) will call that callback and we get the final result. While doing this if any error occurred then promise will be rejected.

    handleResolved功能會檢查是否_state === 1和分配cb = deferred.onFulfilled這是我們then回調。 稍后tryCallOne(cb, self._value)將調用該回調,然后得到最終結果。 在執行此操作時,如果發生任何錯誤,則promise將被拒絕。

當諾言被拒絕時 (When a promise is rejected)

In this case, all the steps will remain the same — but in point 8 we call reject(reason). This will indirectly call rejectCallback defined in doResolve() and self._state will become 2. In the finale function cb will be equal to deferred.onRejected which will be called later by tryCallOne. That’s how the .catch callback will be called.

在這種情況下,所有步驟將保持不變-但在第8點中,我們將其稱為reject(reason) 。 這將間接調用rejectCallback doResolve()定義的doResolve()self._state將變為2 。 在finale函數中, cb等于deferred.onRejected ,稍后將由tryCallOne 。 這就是.catch回調將被調用的方式。

That's all for now! I hope you enjoyed the article and it helps in your next JavaScript interview.

目前為止就這樣了! 我希望您喜歡這篇文章,并且對您下一次JavaScript采訪有所幫助。

If you encounter any problem feel free to get in touch or comment below. I would be happy to help ?

如果您遇到任何問題,請 下面 與我們聯系 或發表評論。 我很樂意提供幫助嗎?

Don’t hesitate to clap if you considered this a worthwhile read!

如果您認為這值得一讀,請隨時鼓掌!

Originally published at 101node.io on February 05, 2019.

最初于2019年2月5日發布在101node.io上。

翻譯自: https://www.freecodecamp.org/news/how-javascript-promises-actually-work-from-the-inside-out-76698bb7210b/

javascript 作用

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

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

相關文章

linux 文件理解,對linux中文件系統的理解

首先在linux系統當中一個可被掛在的數據為一個文件系統1.在安裝linux過程中我們要進行磁盤分區,可以分根目錄/,‘/home‘,‘/boot’,swap等等這些分區,每一個分區(’/(根目錄)‘,’/home‘...)就是一個文件系統。2.文件系統分配完…

編譯原理—語法分析器(Java)

遞歸下降語法分析 1. 語法成分說明 <語句塊> :: begin<語句串> end <語句串> :: <語句>{&#xff1b;<語句>} <語句> :: <賦值語句> | <循環語句> | <條件語句> <關系運算符> :: < | < | > | > | |…

老筆記整理四:字符串的完美度

今天在寵果網上發現一道題目&#xff0c;求一個字符串的完美度http://hero.pongo.cn/home/index覺得這道題很有趣就挑戰了一下&#xff0c;結果沒有在規定的1小時里面寫完&#xff08;笑&#xff09;&#xff0c;多花了10分鐘終于做出來了。題目是這樣的&#xff1a;我們要給每…

nlp構建_使用NLP構建自殺性推文分類器

nlp構建Over the years, suicide has been one of the major causes of death worldwide, According to Wikipedia, Suicide resulted in 828,000 global deaths in 2015, an increase from 712,000 deaths in 1990. This makes suicide the 10th leading cause of death world…

域名跳轉

案例&#xff1a;當訪問lsx.com網站&#xff0c;是我最早論壇的域名。回車之后會自動跳轉到lshx.com。 為什么藥lsx跳轉到lshx.com呢&#xff1f; 為了統一品牌。建議換成了lshx.com。所有之前的lsx.com就不要用了&#xff0c;就讓它跳轉到lshx.com。是因為之前lsx.com上有很多…

Elastic Stack 安裝

Elastic Stack 是一套支持數據采集、存儲、分析、并可視化全面的分析工具&#xff0c;簡稱 ELK&#xff08;Elasticsearch&#xff0c;Logstash&#xff0c;Kibana&#xff09;的縮寫。 安裝Elastic Stack 時&#xff0c;必須相關組件使用相同的版本&#xff0c;例如&#xff1…

區塊鏈去中心化分布式_為什么漸進式去中心化是區塊鏈的最大希望

區塊鏈去中心化分布式by Arthur Camara通過亞瑟卡馬拉(Arthur Camara) 為什么漸進式去中心化是區塊鏈的最大希望 (Why Progressive Decentralization is blockchain’s best hope) 不變性是區塊鏈的最大優勢和最大障礙。 逐步分權可能是答案。 (Immutability is blockchain’s…

編譯原理—語義分析(Java)

遞歸下降語法制導翻譯 實現含多條簡單賦值語句的簡化語言的語義分析和中間代碼生成。 測試樣例 begin a:2; b:4; c:c-1; area:3.14*a*a; s:2*3.1416*r*(hr); end #詞法分析 public class analyzer {public static List<String> llistnew ArrayList<>();static …

linux問題總結

linux問題總結 編寫后臺進程的管理腳本&#xff0c;使用service deamon-name stop的時候&#xff0c;出現如下提示&#xff1a;/sbin/service: line 66: 23299 Terminated env -i LANG"$LANG" PATH"$PATH" TERM"$TERM" "${SERVICEDIR}/${SE…

linux vi行尾總是顯示顏色,【轉載】Linux 下使用 vi 沒有顏色的解決辦法

vi 是沒有顏色的&#xff0c;vim 是有顏色的。我們可以通過 rpm -qa |grep vim 看看系統中是否安裝了下面 3 個 rpm 包&#xff0c;如果有就是安裝了 vim 。[rootBetty ~]# rpm -qa |grep vimvim-minimal-7.0.109-7.el5vim-enhanced-7.0.109-7.el5vim-common-7.0.109-7.el5如果…

時間序列分析 lstm_LSTM —時間序列分析

時間序列分析 lstmNeural networks can be a hard concept to wrap your head around. I think this is mostly due to the fact that they can be used for so many different things such as classification, identification or just simply regression.神經網絡可能是一個難…

關于計算圓周率PI的經典程序

短短幾行代碼&#xff0c;卻也可圈可點。如把變量s放在PI表達式中&#xff0c;還有正負值的處理&#xff0c;都堪稱經典。尤其是處處考慮執行效率的思想令人敬佩。 /* pi/41-1/31/5-1/71/9-…… */ #include <stdio.h> int main(){ int s1; float pi0.,n1.,…

華為產品技術學習筆記之路由原理(一)

路由器&#xff1a;路由器是一種典型的網絡連接設備&#xff0c;用來進行路由選擇和報文轉發。路由器與它直接相連的網絡的跳數為0&#xff0c;通過一臺路由器可達的網絡的跳數為1.路由協議&#xff1a;路由器之間維護路由表的規則&#xff0c;用以發現路由&#xff0c;生成路由…

Linux網絡配置:設置IP地址、網關DNS、主機名

查看網絡信息 1、ifconfig eth0 2、ifconfig -a 3、ip add 設置主機名需改配置文件&#xff1a; /etc/hosts /etc/sysconfig/network vim /etc/sysconfig/network NETWORKINGyes NETWORKING_IPV6no HOSTNAMEwendyhost Linux配置網絡 方法一&#xff1a; 1、使用setup命令進入如…

編譯原理—小型(簡化)高級語言分析器前端(Java)

實現一個一遍掃描的編譯前端&#xff0c;將簡化高級語言的部分語法成分&#xff08;含賦值語句、分支語句、循環語句等&#xff09;翻譯成四元式&#xff08;或三地址代碼&#xff09;&#xff0c;還要求有合理的語法出錯報錯和錯誤恢復功能。 測試樣例 beginwhile a<b do…

linux boot菜單列表,Bootstrap 下拉菜單(Dropdowns)簡介

Bootstrap 下拉菜單是可切換的&#xff0c;是以列表格式顯示鏈接的上下文菜單。這可以通過與 下拉菜單(Dropdown) JavaScript 插件 的互動來實現。如需使用下拉菜單&#xff0c;只需要在 class .dropdown 內加上下拉菜單即可。下面的實例演示了基本的下拉菜單&#xff1a;實例主…

dynamodb管理ttl_如何使用DynamoDB TTL和Lambda安排臨時任務

dynamodb管理ttlby Yan Cui崔燕 如何使用DynamoDB TTL和Lambda安排臨時任務 (How to schedule ad-hoc tasks with DynamoDB TTL and Lambda) CloudWatch Events let you easily create cron jobs with Lambda. However, it’s not designed for running lots of ad-hoc tasks,…

5g創業的構想_數據科學項目的五個具體構想

5g創業的構想Do you want to enter the data science world? Congratulations! That’s (still) the right choice.您想進入數據科學世界嗎&#xff1f; 恭喜你&#xff01; 那(仍然)是正確的選擇。 The market currently gets tougher. So, you must be mentally prepared f…

Microsoft Windows Phone 7 Toolkit Silverlight SDK XNA Game Studio 4.0 開發工具套件正式版下載...

Windows Phone 7開發工具套件包括Visual Studio 2010 Express for Windows Phone、Windows Phone模擬器、Expression Blend 4 for Windows Phone、XNA Game Studio 4.0和新增加的必應地圖SDK。 英文版的光盤鏡像&#xff1a;點擊下載 文檔中心&#xff1a;Windows Phone develo…

數據挖掘—Apriori算法(Java實現)

算法描述 &#xff08;1&#xff09;掃描全部數據&#xff0c;產生候選1-項集的集合C1&#xff1b; &#xff08;2&#xff09;根據最小支持度&#xff0c;由候選1-項集的集合C1產生頻繁1-項集的集合L1&#xff1b; &#xff08;3&#xff09;對k>1&#xff0c;重復執行步驟…