簡體   English   中英

如何從 Promise 中提取數據

[英]How to extract data out of a Promise

我有一個返回數據的 promise,我想將其保存在變量中。 由於異步性質,這在 JavaScript 中是不可能的嗎?我是否需要使用onResolve作為回調?

我能以某種方式使用它嗎(例如用 async/await 包裝它):

const { foo, bar } = Promise.then(result => result.data, errorHandler);
// rest of script

而不是這個?

Promise.then(result => {
   const { foo, bar } = result.data;
   // rest of script
 }, errorHandler);

注意:使用 Bluebird 庫而不是本機實現,我無法從 Promise 更改為 asnyc/await 或 Generators。

不,您不能像您在示例中建議的那樣從承諾中同步獲取數據。 數據必須在回調函數中使用。 或者,在函數式編程風格中,promise 數據可以被map()ed over

如果您可以使用async/await (您應該很棒),那么您可以編寫看起來同步但保留承諾的異步性的代碼(請參閱@loganfsmyth 評論)。

const { foo, bar }  = await iAmAPromise.then(result => result.data);

總的來說,既然你已經在使用 ES6,我假設你也在使用轉譯器。 在這種情況下,您絕對應該嘗試async/await 只是一定要權衡決定,因為今天它們還沒有被批准的規范。

雖然您可以從異步函數中的等待 Promise 中獲取值(僅僅是因為它暫停函數以等待結果),但您永遠無法直接從 Promise 中獲取值並返回到與 Promise 本身相同的范圍內.

那是因為“out of”意味着嘗試將未來存在的東西(最終解決的值)放入過去已經發生的上下文(同步變量賦值)中。

也就是時間旅行。 即使時間旅行是可能的,它也可能不是一個好的編碼實踐,因為時間旅行可能會非常混亂。:)

一般來說,如果你覺得你需要這樣做,這是你需要重構某些東西的好兆頭。 請注意,您在此處使用“result => result.data”執行的操作:

Promise.then(result => result.data, errorHandler);
// rest of script

..已經是您通過將值傳遞給函數來處理(字面意思是映射)值的情況。 但是,假設“// 腳本的其余部分”做了與該值相關的重要操作,您可能希望使用另一個函數繼續映射現在更新的值,然后對該值執行一些副作用(例如顯示屏幕上的數據)。

Promise
    .then(result => result.data)
    .then(data => doSomethingWithData)// rest of script
    .catch(errorHandler);

“doSomethingWithData”將在未來某個未知時間點被調用(如果它曾經被調用過)。 這就是為什么將所有這些行為清晰地封裝到一個特定的函數中,然后將該函數連接到 Promise 鏈上是一種很好的做法。

老實說,這種方式更好,因為它要求您清楚地聲明發生的特定事件序列,明確地從第一次運行到所有應用程序代碼的執行中分離出來。

換句話說,想象一下這個場景,假設在全局頂級范圍內執行:

const { foo, bar } = Promise.then(result => result.data, errorHandler);
console.log(foo);
//...more program

你希望那里發生什么? 有兩種可能,而且都不好。

  1. 你的整個程序必須暫停並等待 Promise 執行,然后它才能知道 "foo" 和 "bar" 會......不,可能是。 (這就是異步函數內部的“等待”實際上所做的:它暫停整個函數的執行,直到值可用或拋出錯誤)
  2. foo 和 bar 只是未定義(這是實際發生的情況),因為同步執行時,它們只是頂級 Promise 對象的不存在的屬性(它本身不是“值”,而是quasi-Monadic 包裝器圍繞獲取最終值或錯誤),它很可能甚至包含值。

如果你願意,我有一個解決方案可以讓這個值“出來”。 這是后端的一種方法,用於將多個文件上傳到 AWS S3,必須異步處理。 我還需要來自 S3 的響應,所以我需要 Promise 中的值:

async function uploadMultipleFiles(files) {

const promises = [];    //Creating an array to store promises
for (i = 0; i < files.length; i++) {
    const fileStream = fs.createReadStream(files[i].path)

    const uploadParams = {
        Bucket: bucketName,
        Body: fileStream,
        Key: files[i].filename
    }

    promises.push(s3.upload(uploadParams).promise())  //pushing each promise instead 
                   //of awaiting, to enable for concurrent uploads.
}

await Promise.all(promises).then(values => {
    console.log("values: ", values) //just checking values
    result = values;  //storing in a different variable
});
return result; //returning that variable

}

與此處討論的問題相關的關鍵行是:

await Promise.all(promises).then(values => {
    console.log("values: ", values) //just checking values
    res = values;  //storing in a different variable
});
return res; //returning that variable

但當然我們還必須等待 function 將調用它:

const result = await uploadMultipleFiles(files);

您需要做的就是使用 a.then 提取 promise 中的所有內容


yourFunction().then( resp => {
... do what you require here

let var1 = resp.var1;
let var2 = resp.var2;
...
.....
})

yourFunction() 應該返回一個 Promise

如何從 Promise 中獲取值

是的! 您可以從承諾中提取價值!

不要讓這里的任何人說你不能。 只要意識到存儲返回的 promise 值的任何變量都可能會有短暫的延遲。 因此,如果您有一個 JavaScript 腳本頁面需要 Promise 或異步等待函數之外的數據,您可能必須創建循環、間隔計時器或事件偵聽器以等待一段時間后獲取值。 因為大多數異步等待承諾是 REST 次調用並且速度非常快,所以等待只需要一個快速的 while 循環!

這很簡單,只需設置一個變量(或創建一個函數)來訪問異步或 promise 代碼中的值,並將該值存儲在 oitside 變量 object 數組中。 等你可以檢查:這是一個原始的例子:

    // I just created a simple global variable to store my promise message.
    var myDelayedData = '';

   // This function is only used to go get data.
   // Note I set the delay for 5 seconds below so you can test the delay
    const getData = () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => resolve('my promise data'), 5000);
      });
    }

    // I like to create a second async function to get the data
    // from the promise object and save the data to my global variable.
    const processData = async () => {
       let data = await getData();
       // Save the delayed data to my global variable
       myDelayedData = data;
    }

    // Start the data call from the promise.
    processData();

    // Open up your browser, hit F12 to pull up the browser devtools
    // Click the "console" tab and watch the script print out
    // the value of the variable with empty message until after
    // 5 seconds the variable is assigned to the resolved promise
    // and apears in the message!

    // THAT IS IT! Your variable is assigned the promise value
    // after the delay I set above!

    // TEST: But let's test it and see...
    var end = setInterval(function(){
        console.log("My Result: " + myDelayedData);
        if(myDelayedData !== ''){
           clearInterval(end);
        }
    }, 1000);

    // You should see this in devtools console.
    // Each line below represents a 1 second delay.

    My Result: 
    My Result: 
    My Result: 
    My Result: my promise data

大多數人看到這段代碼會說“那為什么要使用 Promise,只是調用數據、暫停和更新您的應用程序?” 正確:Promise 的全部意義在於將數據處理封裝在 promise 中,並在腳本的 rest 繼續執行時執行操作。

但是......您可能需要 output Promise 之外的結果。例如,您可能有其他需要該數據的全局進程,因為它更改了全局應用程序的 state。 但至少您知道,如果需要,您可以獲得 Promise 數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM