如何链接原生 Javascript Promise?
Posted
技术标签:
【中文标题】如何链接原生 Javascript Promise?【英文标题】:How to chain native Javascript Promises? 【发布时间】:2015-10-06 10:47:32 【问题描述】:我已经阅读了所有可以想象到的关于 JS 承诺的文章,但我仍然无法弄清楚它们。我正在尝试使用承诺来管理多个 XMLHTTPRequest。 eg: 当xhr 请求1 & 2 完成时,调用这个函数。
示例代码:
function initSession()
loadRates(0);
loadRates(10);
buildTable();
// Get all rates from API, save to localStorage, then build the table.
function loadRates(days)
var xhr = new XMLHttpRequest();
xhr.onload = function()
// save response to localStorage, using a custom variable
localStorage.setItem("rates" + days, xhr.responseText);
;
xhr.open('GET', url);
xhr.send();
function buildTable()
// get data from localStorage
// write to html table
在这种情况下,我将如何将每个函数调用包装在一个 Promise 对象中,以便我可以控制它们何时被调用?
【问题讨论】:
也许How do I promisify native XHR? 有帮助 【参考方案1】:使用回调,您总是通过一个函数“响应”。例如:
function getUsers (age, done)
// done has two parameters: err and result
return User.find(age, done)
Promises 让你根据当前状态做出响应:
function getUsers (age)
return new Promise((resolve, reject) =>
User.find( age , function (err, users)
return err ? reject(err) : resolve(users)
)
)
这会使“回调金字塔”变平。而不是
getUsers(18, function (err, users)
if (err)
// handle error
else
// users available
)
你可以使用:
getUsers(18).then((users) =>
// `getPetsFromUserIds` returns a promise
return getPetsFromUserIds(users.map(user => user._id))
).then((pets) =>
// pets here
).catch((err) =>
console.log(err) // handle error
)
所以,要回答你的问题,首先你要为你的 http 请求使用一个 Promise:
function GET (url)
return new Promise((resolve, reject) =>
let xhr = new XMLHttpRequest()
xhr.open('GET', url, true)
xhr.onload = function ()
if (this.status >= 200 && this.status < 300)
return resolve(xhr.response)
else
return reject( status: this.status, text: xhr.statusText )
xhr.onerror = reject
xhr.send()
)
然后,您希望将其合并到您的 loadRates
函数中:
function loadRates (days)
var URL = URL_GENERATOR(days)
return GET(URL).catch((err) =>
// handle our error first
console.log(err)
// decide how you want to handle a lack of data
return null
).then((res) =>
localStorage.setItem('rates' + days, res)
return res
)
然后,在initSession
:
function initSession ()
Promise.all([ loadRates(0), loadRates(10) ]).then((results) =>
// perhaps you don't want to store in local storage,
// since you'll have access to the results right here
let [ zero, ten ] = results
return buildTable()
)
【讨论】:
第一句话……不寒而栗。 Imo,您应该将 Promise 视为 返回值(携带异步负载)。 @Bergi 我猜 Promise 是异步操作,忽略了它们的使用方式(这就是为什么它们通常比回调更好用)......? 我认为看到 represent 是(异步)操作的 result 非常重要——它们既不代表操作本身,也不代表操作本身他们just callbacks :-) @Bergi - 我想在你的总结中添加一个词:承诺代表异步操作的未来结果。 前两句和对应的代码sn-ps我不太明白是什么意思。如果您实际展示了 User.find 函数和回调的实际调用,那么第一个代码 sn-p 会不会更简单和更具说明性?而且我不明白第二句话中的“根据当前状态”是什么意思。你能扩展一下吗?【参考方案2】:另外,请注意,有一个方便的功能可以发出 AJAX 请求并获得承诺 - window.fetch。 Chrome 和 Firefox 已经支持,其他浏览器可以是polyfilled。
那么你就可以轻松解决你的问题了
function loadRates(days)
return window.fetch(url).then(function(response)
return response.json(); // needed to parse raw response data
).then(function(response)
localStorage.setItem("rates" + days, response);
return response; // this return is mandatory, otherwise further `then` calls will get undefined as argument
);
Promise.all([
loadRates(0),
loadRates(1)
]).then(function(rates)
return buildTable(rates)
)
【讨论】:
以上是关于如何链接原生 Javascript Promise?的主要内容,如果未能解决你的问题,请参考以下文章