原文:http://www.html5rocks.com/en/tutorials/es6/promises/
做者:Jake Archibald
翻译:Amiojavascript
女士们先生们,请准备好迎接 Web 开发历史上一个重大时刻……php
[鼓声响起]html
JavaScript 有了原生的 Promise!html5
[漫天的烟花绽开,人群沸腾了]java
这时候你大概是这三种人之一:jquery
JavaScript 是单线程的,这意味着任何两句代码都不能同时运行,它们得一个接一个来。在浏览器中,JavaScript 和其余任务共享一个线程,不一样的浏览器略有差别,但大致上这些和 JavaScript 共享线程的任务包括重绘、更新样式、用户交互等,全部这些任务操做都会阻塞其余任务。git
做为人类,你是多线程的。你能够用多个手指同时敲键盘,也能够一边开车一遍电话。惟一的全局阻塞函数是打喷嚏,打喷嚏期间全部其余事务都会暂停。很烦人对么?尤为是当你开着车打着电话的时候。咱们都不喜欢这样打喷嚏的代码。es6
你应该会用事件加回调的办法来处理这类状况:github
var img1 = document.querySelector('.img-1'); img1.addEventListener('load', function() { // woo yey image loaded }); img1.addEventListener('error', function() { // argh everything's broken });
这样就不打喷嚏了。咱们添加几个监听函数,请求图片,而后 JavaScript 就中止运行了,直到触发某个监听函数。ajax
上面的例子中惟一的问题是,事件有可能在咱们绑定监听器以前就已经发生,因此咱们先要检查图片的complete
属性:
var img1 = document.querySelector('.img-1'); function loaded() { // woo yey image loaded } if (img1.complete) { loaded(); } else { img1.addEventListener('load', loaded); } img1.addEventListener('error', function() { // argh everything's broken });
这样还不够,若是在添加监听函数以前图片加载发生错误,咱们的监听函数仍是白费,不幸的是 DOM 也没有为这个需求提供解决办法。并且,这还只是处理一张图片的状况,若是有一堆图片要处理那就更麻烦了。
事件机制最适合处理同一个对象上反复发生的事情—— keyup、touchstart 等等。你不须要考虑当绑定监听器以前所发生的事情,当碰到异步请求成功/失败的时候,你想要的一般是这样:
img1.callThisIfLoadedOrWhenLoaded(function() { // loaded }).orIfFailedCallThis(function() { // failed }); // and… whenAllTheseHaveLoaded([img1, img2]).callThis(function() { // all loaded }).orIfSomeFailedCallThis(function() { // one or more failed });
这就是 Promise。若是 HTML 图片元素有一个 ready()
方法的话,咱们就能够这样:
img1.ready().then(function() { // loaded }, function() { // failed }); // and… Promise.all([img1.ready(), img2.ready()]).then(function() { // all loaded }, function() { // one or more failed });
基本上 Promise 仍是有点像事件回调的,除了:
这些特性很是适合处理异步操做的成功/失败情景,你无需再担忧事件发生的时间点,而只需对其作出响应。
Domenic Denicola 审阅了本文初稿,给我在术语方面打了个“F”,关了禁闭而且责令我打印 States and Fates 一百遍,还写了一封家长信给我父母。即使如此,我仍是对术语有些迷糊,不过基本上应该是这样:
一个 Promise 的状态能够是:
确认(fulfilled)- 成功了
否认(rejected)- 失败了
等待(pending)- 尚未确认或者否认,进行中
结束(settled)- 已经确认或者否认了
规范里还使用“thenable”来描述一个对象是不是“类 Promise”(拥有名为“then”的方法)的。这个术语使我想起来前英格兰足球经理 Terry Venables 因此我尽可能少用它。
其实已经有一些第三方库实现了 Promise:
上面这些库和 JavaScript 原生 Promise 都遵照一个通用的、标准化的规范:Promises/A+,jQuery 有个相似的方法叫 Deferreds,但不兼容 Promises/A+ 规范,因而会有点小问题,使用需谨慎。jQuery 还有一个Promise 类型,但只是 Deferreds 的缩减版,因此也有一样问题。
尽管 Promise 的各路实现遵循同一规范,它们的 API 仍是各不相同。JavaScript Promise 的 API 比较接近 RSVP.js,以下建立 Promise:
var promise = new Promise(function(resolve, reject) { // do a thing, possibly async, then… if (/* everything turned out fine */) { resolve("Stuff worked!"); } else { reject(Error("It broke")); } });
Promise 的构造器接受一个函数做为参数,它会传递给这个回调函数两个变量 resolve 和 reject。在回调函数中作一些异步操做,成功以后调用 resolve,不然调用 reject。
调用 reject 的时候传递给它一个 Error 对象只是个惯例并不是必须,这和经典 JavaScript 中的 throw 同样。传递 Error 对象的好处是它包含了调用堆栈,在调试的时候会有点用处。
如今来看看如何使用 Promise:
promise.then(function(result) { console.log(result); // "Stuff worked!" }, function(err) { console.log(err); // Error: "It broke" });
then
接受两个参数,成功的时候调用一个,失败的时候调用另外一个,两个都是可选的,因此你能够只处理成功的状况或者失败的状况。
JavaScript Promise 最初以“Futures”的名称归为 DOM 规范,后来更名为“Promises”,最终归入 JavaScript 规范。将其加入 JavaScript 而非 DOM 的好处是方便在非浏览器环境中使用,如Node.js(他们会不会在核心API中使用就是另外一回事了)。
目前的浏览器已经(部分)实现了 Promise。
用 Chrome 的话,就像个 Chroman 同样装上 Canary 版,默认即启用了 Promise 支持。若是是 Firefox 拥趸,安装最新的 nightly build 也同样。
不过这两个浏览器的实现都还不够完整完全,你能够在 bugzilla 上跟踪 Firefox 的最新进展或者到 Chromium Dashboard 查看 Chrome 的实现状况。
要在这两个浏览器上达到兼容标准 Promise,或者在其余浏览器以及 Node.js 中使用 Promise,能够看看这个 polyfill(gzip 以后 2K)
JavaScript Promise 的 API 会把任何包含有 then
方法的对象看成“类 Promise”(或者用术语来讲就是 thenable。叹气)的对象,这些对象通过 Promise.cast()
处理以后就和原生的 JavaScript Promise 实例没有任何区别了。因此若是你使用的库返回一个 Q Promise,那没问题,无缝融入新的 JavaScript Promise。
尽管,如前所述,jQuery 的 Deferred 对象有点……没什么用,不过幸亏还能够转换成标准 Promise,你最好一拿到对象就立刻加以转换:
var jsPromise = Promise.cast($.ajax('/whatever.json'));
这里 jQuery 的 $.ajax
返回一个 Deferred 对象,含有 then
方法,所以 Promise.cast
能够将其转换为 JavaScript Promise。不过有时候 Deferred 对象会给它的回调函数传递多个参数,例如:
var jqDeferred = $.ajax('/whatever.json'); jqDeferred.then(function(response, statusText, xhrObj) { // ... }, function(xhrObj, textStatus, err) { // ... });
除了第一个参数,其余都会被 JavaScript Promise 忽略掉:
jsPromise.then(function(response) { // ... }, function(xhrObj) { // ... });
……还好这一般就是你想要的了,至少你可以用这个办法实现想要的。另外还要注意,jQuery 也没有遵循给否认回调函数传递 Error 对象的惯例。
OK,如今咱们来写点实际的代码。假设咱们想要:
……这个过程当中若是发生什么错误了要通知用户,而且把加载指示停掉,否则它就会不停转下去,使人眼晕,或者搞坏界面什么的。
固然了,你不会用 JavaScript 去这么繁琐地显示一篇文章,直接输出 HTML 要快得多,不过这个流程是很是典型的 API 请求模式:获取多个数据,当它们所有完成以后再作一些事情。
首先搞定从网络加载数据的步骤:
只要能保持向后兼容,现有 API 都会更新以支持 Promise,XMLHttpRequest 是重点考虑对象之一。不过如今咱们先来写个 GET 请求:
function get(url) { // Return a new promise. return new Promise(function(resolve, reject) { // Do the usual XHR stuff var req = new XMLHttpRequest(); req.open('GET', url); req.onload = function() { // This is called even on 404 etc // so check the status if (req.status == 200) { // Resolve the promise with the response text resolve(req.response); } else { // Otherwise reject with the status text // which will hopefully be a meaningful error reject(Error(req.statusText)); } }; // Handle network errors req.onerror = function() { reject(Error("Network Error")); }; // Make the request req.send(); }); }
而后调用它:
get('story.json').then(function(response) { console.log("Success!", response); }, function(error) { console.error("Failed!", error); });
点击这里查看代码运行页面,打开控制台查看输出结果。如今咱们能够直接发起 HTTP 请求而不须要手敲 XMLHttpRequest,这样感受好多了,能少看一次这个狂驼峰命名的 XMLHttpRequest 我就多快乐一点。
“then”的故事还没完,你能够把这些“then”串联起来修改结果或者添加进行更多异步操做。
你能够对结果作些修改而后返回一个新值:
var promise = new Promise(function(resolve, reject) { resolve(1); }); promise.then(function(val) { console.log(val); // 1 return val + 2; }).then(function(val) { console.log(val); // 3 });
回到前面的代码:
get('story.json').then(function(response) { console.log("Success!", response); });
收到的响应是一个纯文本的 JSON,咱们能够修改 get 函数,设置 responseType 要求服务器以 JSON 格式提供响应,不过仍是用 Promise 的方式来搞定吧:
get('story.json').then(function(response) { return JSON.parse(response); }).then(function(response) { console.log("Yey JSON!", response); });
既然 JSON.parse
只接收一个参数,并返回转换后的结果,咱们还能够再精简一点:
get('story.json').then(JSON.parse).then(function(response) { console.log("Yey JSON!", response); });
点击这里查看代码运行页面,打开控制台查看输出结果。事实上,咱们能够把 getJSON
函数写得超级简单:
function getJSON(url) { return get(url).then(JSON.parse); }
getJSON
会返回一个获取 JSON 并加以解析的 Promise。
你也能够把 then
串联起来依次执行异步操做。
当你从 then
的回调函数返回的时候,这里有点小魔法。若是你返回一个值,它就会被传给下一个 then
的回调;而若是你返回一个“类 Promise”的对象,则下一个 then
就会等待这个 Promise 明确结束(成功/失败)才会执行。例如:
getJSON('story.json').then(function(story) { return getJSON(story.chapterUrls[0]); }).then(function(chapter1) { console.log("Got chapter 1!", chapter1); });
这里咱们发起一个对 story.json 的异步请求,返回给咱们更多 URL,而后咱们会请求其中的第一个。Promise 开始首次显现出相较事件回调的优越性了。你甚至能够写一个抓取章节内容的独立函数:
var storyPromise; function getChapter(i) { storyPromise = storyPromise || getJSON('story.json'); return storyPromise.then(function(story) { return getJSON(story.chapterUrls[i]); }) } // and using it is simple: getChapter(0).then(function(chapter) { console.log(chapter); return getChapter(1); }).then(function(chapter) { console.log(chapter); });
咱们一开始并不加载 story.json,直到第一次 getChapter,而之后每次 getChapter 的时候均可以重用已经加载完成的 story Promise,因此 story.json 只须要请求一次。Promise 好棒!
前面已经看到,“then”接受两个参数,一个处理成功,一个处理失败(或者说确认和否认,按 Promise 术语):
get('story.json').then(function(response) { console.log("Success!", response); }, function(error) { console.log("Failed!", error); });
你还可使用 catch
:
get('story.json').then(function(response) { console.log("Success!", response); }).catch(function(error) { console.log("Failed!", error); });
这里的 catch 并没有任何特殊之处,只是 then(undefined, func)
的语法糖衣,更直观一点而已。注意上面两段代码的行为不只相同,后者至关于:
get('story.json').then(function(response) { console.log("Success!", response); }).then(undefined, function(error) { console.log("Failed!", error); });
差别不大,但意义非凡。Promise 被否认以后会跳转到以后第一个配置了否认回调的 then(或 catch,同样的)。对于 then(func1, func2)
来讲,必会调用 func1 或 func2 之一,但毫不会两个都调用。而 then(func1).catch(func2)
这样,若是 func1 返回否认的话 func2 也会被调用,由于他们是链式调用中独立的两个步骤。看下面这段代码:
asyncThing1().then(function() { return asyncThing2(); }).then(function() { return asyncThing3(); }).catch(function(err) { return asyncRecovery1(); }).then(function() { return asyncThing4(); }, function(err) { return asyncRecovery2(); }).catch(function(err) { console.log("Don't worry about it"); }).then(function() { console.log("All done!"); });
这段流程很是像 JavaScript 的 try/catch 组合,try
代码块中发生的错误会径直跳转到 catch
代码块。这是上面那段代码的流程图(我最爱流程图了):
绿线是确认的 Promise 流程,红线是否认的。
Promise 的否认回调能够由 Promise.reject()
触发,也能够由构造器回调中抛出的错误触发:
var jsonPromise = new Promise(function(resolve, reject) { // JSON.parse throws an error if you feed it some // invalid JSON, so this implicitly rejects: resolve(JSON.parse("This ain't JSON")); }); jsonPromise.then(function(data) { // This never happens: console.log("It worked!", data); }).catch(function(err) { // Instead, this happens: console.log("It failed!", err); });
这意味着你能够把全部 Promise 相关工做都放在构造函数的回调中进行,这样任何错误都能被捕捉到而且触发 Promise 否认。
get('/').then(JSON.parse).then(function() { // This never happens, '/' is an HTML page, not JSON // so JSON.parse throws console.log("It worked!", data); }).catch(function(err) { // Instead, this happens: console.log("It failed!", err); });
回到咱们的故事和章节,咱们用 catch 来捕捉错误并显示给用户:
getJSON('story.json').then(function(story) { return getJSON(story.chapterUrls[0]); }).then(function(chapter1) { addHtmlToPage(chapter1.html); }).catch(function() { addTextToPage("Failed to show chapter"); }).then(function() { document.querySelector('.spinner').style.display = 'none'; });
若是请求 story.chapterUrls[0]
失败(http 500 或者用户掉线什么的)了,它会跳过以后全部针对成功的回调,包括 getJSON
中将响应解析为 JSON 的回调,和这里把第一张内容添加到页面里的回调。JavaScript 的执行会进入 catch
回调。结果就是前面任何章节请求出错,页面上都会显示“Failed to show chapter”。
和 JavaScript 的 catch 同样,捕捉到错误以后,接下来的代码会继续执行,按计划把加载指示器给停掉。上面的代码就是下面这段的非阻塞异步版:
try { var story = getJSONSync('story.json'); var chapter1 = getJSONSync(story.chapterUrls[0]); addHtmlToPage(chapter1.html); } catch (e) { addTextToPage("Failed to show chapter"); } document.querySelector('.spinner').style.display = 'none';
若是只是要捕捉异常作记录输出,不打算在用户界面上对错误进行反馈的话,只要抛出 Error 就好了,这一步能够放在 getJSON
中:
function getJSON(url) { return get(url).then(JSON.parse).catch(function(err) { console.log("getJSON failed for", url, err); throw err; }); }
如今咱们已经搞定第一章了,接下来搞定全部的。
异步的思惟方式并不符合直觉,若是你以为起步困难,那就试试先写个同步的方法,就像这个:
try { var story = getJSONSync('story.json'); addHtmlToPage(story.heading); story.chapterUrls.forEach(function(chapterUrl) { var chapter = getJSONSync(chapterUrl); addHtmlToPage(chapter.html); }); addTextToPage("All done"); } catch (err) { addTextToPage("Argh, broken: " + err.message); } document.querySelector('.spinner').style.display = 'none';
它执行起来彻底正常!(查看示例)不过它是同步的,在加载内容时会卡住整个浏览器。要让它异步工做的话,咱们用 then
把它们一个接一个串起来:
getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); // TODO: for each url in story.chapterUrls, fetch & display }).then(function() { // And we're all done! addTextToPage("All done"); }).catch(function(err) { // Catch any error that happened along the way addTextToPage("Argh, broken: " + err.message); }).then(function() { // Always hide the spinner document.querySelector('.spinner').style.display = 'none'; });
那么咱们如何遍历章节的 URL 而且依次请求?这样是不行的:
story.chapterUrls.forEach(function(chapterUrl) { // Fetch chapter getJSON(chapterUrl).then(function(chapter) { // and add it to the page addHtmlToPage(chapter.html); }); });
forEach
没有对异步操做的支持,因此咱们的故事章节会按照它们加载完成的顺序显示,基本上《低俗小说》就是这么写出来的。咱们不写低俗小说,因此得修正它:
咱们要把章节 URL 数组转换成 Promise 的序列,仍是用 then
:
// Start off with a promise that always resolves var sequence = Promise.resolve(); // Loop through our chapter urls story.chapterUrls.forEach(function(chapterUrl) { // Add these actions to the end of the sequence sequence = sequence.then(function() { return getJSON(chapterUrl); }).then(function(chapter) { addHtmlToPage(chapter.html); }); });
这是咱们第一次用到 Promise.resolve
,它会依据你传的任何值返回一个 Promise。若是你传给它一个类 Promise 对象(带有 then
方法),它会生成一个带有一样确认/否认回调的 Promise,基本上就是克隆。若是传给它任何别的值,如 Promise.resolve('Hello')
,它会建立一个以这个值为完成结果的 Promise,若是不传任何值,则以 undefined 为完成结果。
还有一个对应的 Promise.reject(val)
,会建立以你传入的参数(或 undefined)为否认结果的 Promise。
咱们能够用 array.reduce 精简一下上面的代码:
// Loop through our chapter urls story.chapterUrls.reduce(function(sequence, chapterUrl) { // Add these actions to the end of the sequence return sequence.then(function() { return getJSON(chapterUrl); }).then(function(chapter) { addHtmlToPage(chapter.html); }); }, Promise.resolve());
它和前面的例子功能同样,可是不须要显式声明 sequence
变量。reduce 回调会依次应用在每一个数组元素上,第一轮里的“sequence”是 Promise.resolve()
,以后的调用里“sequence”就是上次函数执行的的结果。array.reduce 很是适合用于把一组值归并处理为一个值,正是咱们如今对 Promise 的用法。
汇总下上面的代码:
getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); return story.chapterUrls.reduce(function(sequence, chapterUrl) { // Once the last chapter's promise is done… return sequence.then(function() { // …fetch the next chapter return getJSON(chapterUrl); }).then(function(chapter) { // and add it to the page addHtmlToPage(chapter.html); }); }, Promise.resolve()); }).then(function() { // And we're all done! addTextToPage("All done"); }).catch(function(err) { // Catch any error that happened along the way addTextToPage("Argh, broken: " + err.message); }).then(function() { // Always hide the spinner document.querySelector('.spinner').style.display = 'none'; });
运行示例看这里,前面的同步代码改形成了彻底异步的版本。咱们还能够更进一步,如今页面加载的效果是这样:
浏览器很擅长同时加载多个文件,咱们这种一个接一个下载章节的方法很是不效率。咱们但愿同时下载全部章节,所有完成后一次搞定,正好就有这么个 API:
Promise.all(arrayOfPromises).then(function(arrayOfResults) { //... });
Promise.all
接受一个 Promise 数组为参数,建立一个当全部 Promise 都完成以后就完成的 Promise,它的完成结果是一个数组,包含了全部先前传入的那些 Promise 的完成结果,顺序和将它们传入的数组顺序一致。
getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); // Take an array of promises and wait on them all return Promise.all( // Map our array of chapter urls to // an array of chapter json promises story.chapterUrls.map(getJSON) ); }).then(function(chapters) { // Now we have the chapters jsons in order! Loop through… chapters.forEach(function(chapter) { // …and add to the page addHtmlToPage(chapter.html); }); addTextToPage("All done"); }).catch(function(err) { // catch any error that happened so far addTextToPage("Argh, broken: " + err.message); }).then(function() { document.querySelector('.spinner').style.display = 'none'; });
根据链接情况,改进的代码会比顺序加载方式提速数秒,甚至代码行数也更少。章节加载完成的顺序不肯定,但它们显示在页面上的顺序准确无误。
然而这样仍是有提升空间。当第一章内容加载完毕咱们能够当即填进页面,这样用户能够在其余加载任务还没有完成以前就开始阅读;当第三章到达的时候咱们不动声色,第二章也到达以后咱们再把第二章和第三章内容填入页面,以此类推。
为了达到这样的效果,咱们同时请求全部的章节内容,而后建立一个序列依次将其填入页面:
getJSON('story.json').then(function(story) { addHtmlToPage(story.heading); // Map our array of chapter urls to // an array of chapter json promises. // This makes sure they all download parallel. return story.chapterUrls.map(getJSON) .reduce(function(sequence, chapterPromise) { // Use reduce to chain the promises together, // adding content to the page for each chapter return sequence.then(function() { // Wait for everything in the sequence so far, // then wait for this chapter to arrive. return chapterPromise; }).then(function(chapter) { addHtmlToPage(chapter.html); }); }, Promise.resolve()); }).then(function() { addTextToPage("All done"); }).catch(function(err) { // catch any error that happened along the way addTextToPage("Argh, broken: " + err.message); }).then(function() { document.querySelector('.spinner').style.display = 'none'; });
哈哈(查看示例),鱼与熊掌兼得!加载全部内容的时间未变,但用户能够更早看到第一章。
这个小例子中各部分章节加载差很少同时完成,逐章显示的策略在章节内容不少的时候优点将会更加显著。
上面的代码若是用 Node.js 风格的回调或者事件机制实现的话代码量大约要翻一倍,更重要的是可读性也不如此例。然而,Promise 的厉害不止于此,和其余 ES6 的新功能结合起来还能更加高效……
接下来的内容涉及到一大堆 ES6 的新特性,不过对于如今应用 Promise 来讲并不是必须,把它看成接下来的第二部豪华续集的预告片来看就行了。
ES6 还给咱们带来了 Generator,容许函数在特定地方像 return 同样退出,可是稍后又能恢复到这个位置和状态上继续执行。
function *addGenerator() { var i = 0; while (true) { i += yield i; } }
注意函数名前的星号,这表示该函数是一个 Generator。关键字 yield 标记了暂停/继续的位置,使用方法像这样:
var adder = addGenerator(); adder.next().value; // 0 adder.next(5).value; // 5 adder.next(5).value; // 10 adder.next(5).value; // 15 adder.next(50).value; // 65
这对 Promise 有什么用呢?你能够用这种暂停/继续的机制写出来和同步代码看上去差很少(理解起来也同样简单)的代码。下面是一个辅助函数(helper function),咱们在 yield
位置等待 Promise 完成:
function spawn(generatorFunc) { function continuer(verb, arg) { var result; try { result = generator[verb](arg); } catch (err) { return Promise.reject(err); } if (result.done) { return result.value; } else { return Promise.cast(result.value).then(onFulfilled, onRejected); } } var generator = generatorFunc(); var onFulfilled = continuer.bind(continuer, "next"); var onRejected = continuer.bind(continuer, "throw"); return onFulfilled(); }
这段代码原样拷贝自 Q,只是改为 JavaScript Promise 的 API。把咱们前面的最终方案和 ES6 最新特性结合在一块儿以后:
spawn(function *() { try { // 'yield' effectively does an async wait, // returning the result of the promise let story = yield getJSON('story.json'); addHtmlToPage(story.heading); // Map our array of chapter urls to // an array of chapter json promises. // This makes sure they all download parallel. let chapterPromises = story.chapterUrls.map(getJSON); for (let chapterPromise of chapterPromises) { // Wait for each chapter to be ready, then add it to the page let chapter = yield chapterPromise; addHtmlToPage(chapter.html); } addTextToPage("All done"); } catch (err) { // try/catch just works, rejected promises are thrown here addTextToPage("Argh, broken: " + err.message); } document.querySelector('.spinner').style.display = 'none'; });
功能彻底同样,读起来要简单得多。这个例子目前能够在 Chrome Canary 中运行(查看示例),不过你得先到 about:flags 中开启 Enable experimental JavaScript 选项。
这里用到了一堆 ES6 的新语法:Promise、Generator、let、for-of。当咱们把 yield
应用在一个 Promise 上,spawn 辅助函数会等待 Promise 完成,而后才返回最终的值。若是 Promise 给出否认结果,spawn 中的 yield 则会抛出一个异常,咱们能够用 try/catch 捕捉到。这样写异步代码真是超级简单!
除非额外注明,最新版的 Chrome(Canary) 和 Firefox(nightly) 均支持下列全部方法。这个 Polyfill 则在全部浏览器内实现一样的接口。
Promise.cast(promise);
返回一个 Promise(当且仅当 promise.constructor == Promise)
备注:目前仅有 Chrome 实现
Promise.cast(obj);
建立一个以 obj 为成功结果的 Promise。
备注:目前仅有 Chrome 实现
Promise.resolve(thenable);
从 thenable 对象建立一个新的 Promise。一个 thenable(类 Promise)对象是一个带有“then”方法的对象。若是你传入一个原生的 JavaScript Promise 对象,则会建立一个新的 Promise。此方法涵盖了 Promise.cast 的特性,可是不如 Promise.cast 更简单高效。
Promise.resolve(obj);
建立一个以 obj 为确认结果的 Promise。这种状况下等同于 Promise.cast(obj)。
Promise.reject(obj);
建立一个以 obj 为否认结果的 Promise。为了一致性和调试便利(如堆栈追踪),obj 应该是一个 Error 实例对象。
Promise.all(array);
建立一个 Promise,当且仅当传入数组中的全部 Promise 都确认以后才确认,若是遇到数组中的任何一个 Promise 以否认结束,则抛出否认结果。每一个数组元素都会首先通过 Promise.cast,因此数组能够包含类 Promise 对象或者其余对象。确认结果是一个数组,包含传入数组中每一个 Promise 的确认结果(且保持顺序);否认结果是传入数组中第一个遇到的否认结果。
备注:目前仅有 Chrome 实现
Promise.race(array);
建立一个 Promise,当数组中的任意对象确认时将其结果做为确认结束,或者当数组中任意对象否认时将其结果做为否认结束。
备注:我不大肯定这个接口是否有用,我更倾向于一个 Promise.all 的对立方法,仅当全部数组元素所有给出否认的时候才抛出否认结果