setTimeout/EventEmitter/Promise/generator/async-await 今天着重来说解一下 promise数组
setTimeout(function(){console.log(4)},0); new Promise(function(resolve){ console.log(1) for( var i=0 ; i<10000 ; i++ ){ i==9999 && resolve() } console.log(2) }) .then(function(){ console.log(5) }); console.log(3);
doSomething().then(function () { return doSomethingElse(); }); doSomething().then(function () { doSomethingElse(); }); doSomething().then(doSomethingElse()); doSomething().then(doSomethingElse);
1.new promise (resolve,reject){};必定要resolve,或者reject 出去不要,作反作用函数。 2.then 操做里面 接收 promise 对象,若是在promise里面是执行的纯函数,也能够返回一个 promise。resolve("常量")。避免promise 穿透
新手错误 #1: promise版的金字塔问题
观察你们如何使用 PouchDB 这类大型的 promise 风格的API,我发现大量错误的 promise 使用形式。最多见的错误就是下面这个:promise
remotedb.allDocs({ include_docs: true, attachments: true }).then(function (result) { var docs = result.rows; docs.forEach(function(element) { localdb.put(element.doc).then(function(response) { alert("Pulled doc with id " + element.doc._id + " and added to local db."); }).catch(function (err) { if (err.status == 409) { localdb.get(element.doc._id).then(function (resp) { localdb.remove(resp._id, resp._rev).then(function (resp) {
// et cetera...
是的,实际上你能够像使用回调同样使用 promises,恩,就像用打磨机去削脚趾甲同样,你确实能够这么作。缓存
而且若是你觉得这样的错误只限于初学者,那么你会惊讶于我其实是在黑莓官方开发者博客上看到上面的代码。老的回调风格的习惯难以消灭。(至开发者: 抱歉选了你的例子,可是你的例子将会有积极的教育意义)异步
正确的风格应该是这样:async
remotedb.allDocs(...).then(function (resultOfAllDocs) { return localdb.put(...); }).then(function (resultOfPut) { return localdb.get(...); }).then(function (resultOfGet) { return localdb.put(...); }).catch(function (err) { console.log(err); });
这种写法被称为 composing promises ,是 promises 的强大能力之一。每个函数只会在前一个 promise 被调用而且完成回调后调用,而且这个函数会被前一个 promise 的输出调用,稍后咱们在这块作更多的讨论。ide
下面的代码有什么问题?函数
somePromise().then(function () { someOtherPromise(); }).then(function () { // Gee, I hope someOtherPromise() has resolved! // Spoiler alert: it hasn't. });
好了,如今是时候讨论一下关于 promises 你所须要知道的一切。code
认真的说,这是一个一旦你理解了它,就会避免全部我说起的错误的古怪的技巧。你准备好了么?对象
就如我前面所说,promises 的奇妙在于给予咱们之前的 return 与 throw。可是在实践中这究竟是怎么一回事呢?blog
每个 promise 都会提供给你一个 then() 函数 (或是 catch(),实际上只是 then(null, ...) 的语法糖)。当咱们在 then() 函数内部时:
somePromise().then(function () { // I'm inside a then() function! });
咱们能够作什么呢?有三种事情:
return 另外一个 promise
return 一个同步的值 (或者 undefined)
throw 一个同步异常
就是这样。一旦你理解了这个技巧,你就理解了 promises。所以让咱们逐个了解下。
返回另外一个 promise
这是一个在 promise 文档中常见的使用模式,也就是咱们在上文中提到的 “composing promises”:
getUserByName('nolan').then(function (user) { return getUserAccountById(user.id); }).then(function (userAccount) { // I got a user account! });
注意到我是 return
第二个 promise,这个 return
很是重要。若是我没有写 return
,getUserAccountById()
就会成为一个反作用,而且下一个函数将会接收到 undefined
而非 userAccount
。
返回一个同步值 (或者 undefined)
返回 undefined 一般是错误的,可是返回一个同步值其实是将同步代码包裹为 promise 风格代码的一种很是赞的手段。举例来讲,咱们对 users 信息有一个内存缓存。咱们能够这样作:
getUserByName('nolan').then(function (user) { if (inMemoryCache[user.id]) { return inMemoryCache[user.id]; // returning a synchronous value! } return getUserAccountById(user.id); // returning a promise! }).then(function (userAccount) { // I got a user account! });
是否是很赞?第二个函数不须要关心 userAccount 是从同步方法仍是异步方法中获取的,而且第一个函数能够很是自由的返回一个同步或者异步值。
不幸的是,有一个不便的现实是在 JavaScript 中无返回值函数在技术上是返回 undefined,这就意味着当你本意是返回某些值时,你很容易会不经意间引入反作用。
出于这个缘由,我我的养成了在 then() 函数内部 永远返回或抛出 的习惯。我建议你也这样作。
抛出同步异常
谈到 throw,这是让 promises 更加赞的一点。好比咱们但愿在用户已经登出时,抛出一个同步异常。这会很是简单:
getUserByName('nolan').then(function (user) { if (user.isLoggedOut()) { throw new Error('user logged out!'); // throwing a synchronous error! } if (inMemoryCache[user.id]) { return inMemoryCache[user.id]; // returning a synchronous value! } return getUserAccountById(user.id); // returning a promise! }).then(function (userAccount) { // I got a user account! }).catch(function (err) { // Boo, I got an error! });
若是用户已经登出,咱们的 catch() 会接收到一个同步异常,而且若是 后续的 promise 中出现异步异常,他也会接收到。再强调一次,这个函数并不须要关心这个异常是同步仍是异步返回的。
这种特性很是有用,所以它可以在开发过程当中帮助定位代码问题。举例来讲,若是在 then() 函数内部中的任何地方,咱们执行 JSON.parse(),若是 JSON 格式是错误的,那么它就会抛出一个异常。若是是使用回调风格,这个错误极可能就会被吃掉,可是使用 promises,咱们能够轻易的在 catch() 函数中处理它了。
咱们能够作什么呢?有三种事情:
return 另外一个 promise
return 一个同步的值 (或者 undefined)
throw 一个同步异常