├── .gitignore ├── LICENSE ├── README.md └── sample ├── FileSystem.js ├── all.js ├── asynchronous-operation.js ├── await.js ├── callback-hell.js ├── catch-then.js ├── error-reject.js ├── error.js ├── fetch-api.js ├── fulfilled-then.js ├── halls-test.js ├── map.js ├── maxfile.js ├── modal.js ├── nested-then.js ├── promise.js ├── race.js ├── reject.js ├── resolve.js ├── spider.js ├── timeout.js ├── timeout2.js ├── timeout3.js └── wrap.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | \.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Merrier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # imooc-promise-sample 2 | 幕课网Promise入门视频源码(https://www.imooc.com/learn/949) 3 | 4 | ## 目录 5 | 6 | > 依照视频的讲解顺序,可直接跳转至代码页 7 | 8 | * [异步操作的常见语法](https://github.com/merrier/imooc-promise-sample/blob/master/sample/asynchronous-operation.js) 9 | 10 | * [回调地狱](https://github.com/merrier/imooc-promise-sample/blob/master/sample/callback-hell.js) 11 | 12 | * [遍历目录,找出最大的一个文件](https://github.com/merrier/imooc-promise-sample/blob/master/sample/maxfile.js) 13 | 14 | * [Promise的设计](https://github.com/merrier/imooc-promise-sample/blob/master/sample/promise.js) 15 | 16 | * [简单的范例-定时执行](https://github.com/merrier/imooc-promise-sample/blob/master/sample/timeout.js) 17 | 18 | * [分两次,顺序依次执行](https://github.com/merrier/imooc-promise-sample/blob/master/sample/timeout2.js) 19 | 20 | * [假如一个Promise已经完成了,再.then()会怎样?](https://github.com/merrier/imooc-promise-sample/blob/master/sample/fulfilled-then.js) 21 | 22 | * [假如在.then()的函数里面不返回新的Promise,会怎样?](https://github.com/merrier/imooc-promise-sample/blob/master/sample/timeout3.js) 23 | 24 | * [嵌套.then()](https://github.com/merrier/imooc-promise-sample/blob/master/sample/nested-then.js) 25 | 26 | * [随堂小测试](https://github.com/merrier/imooc-promise-sample/blob/master/sample/halls-test.js) 27 | 28 | * [Promise会自动捕获内部异常,并交给rejected响应函数处理-catch捕获](https://github.com/merrier/imooc-promise-sample/blob/master/sample/error.js) 29 | 30 | * [Promise会自动捕获内部异常,并交给rejected响应函数处理-reject响应捕获](https://github.com/merrier/imooc-promise-sample/blob/master/sample/error-reject.js) 31 | 32 | * [.catch() + .then()](https://github.com/merrier/imooc-promise-sample/blob/master/sample/catch-then.js) 33 | 34 | * [使用`Promise.all()`包装多个Promise实例](https://github.com/merrier/imooc-promise-sample/blob/master/sample/all.js) 35 | 36 | * [遍历目录,找出最大的一个文件-通过Promise.all()和.map()](https://github.com/merrier/imooc-promise-sample/blob/master/sample/map.js) 37 | 38 | * [开发一个爬虫,爬取某网站。(半成品)](https://github.com/merrier/imooc-promise-sample/blob/master/sample/spider.js) 39 | 40 | * [Promise.resolve()](https://github.com/merrier/imooc-promise-sample/blob/master/sample/resolve.js) 41 | 42 | * [Promise.reject()](https://github.com/merrier/imooc-promise-sample/blob/master/sample/reject.js) 43 | 44 | * [Promise.race()](https://github.com/merrier/imooc-promise-sample/blob/master/sample/race.js) 45 | 46 | * [把回调包装成Promise](https://github.com/merrier/imooc-promise-sample/blob/master/sample/wrap.js) 47 | 48 | * [使用JS包装readFile](https://github.com/merrier/imooc-promise-sample/blob/master/sample/FileSystem.js) 49 | 50 | * [把任何异步操作包装成Promise](https://github.com/merrier/imooc-promise-sample/blob/master/sample/modal.js) 51 | 52 | * [Fetch API](https://github.com/merrier/imooc-promise-sample/blob/master/sample/fetch-api.js) 53 | 54 | * [async/await](https://github.com/merrier/imooc-promise-sample/blob/master/sample/await.js) 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /sample/FileSystem.js: -------------------------------------------------------------------------------- 1 | // 使用JS包装readFile 2 | // https://www.imooc.com/video/16628 3 | 4 | 5 | 6 | const fs = require('fs'); 7 | 8 | module.exports = { 9 | readDir: function (path, options) { 10 | return new Promise( resolve => { 11 | fs.readdir(path, options, (err, files) => { 12 | if (err) { 13 | throw err; 14 | } 15 | resolve(files); 16 | }); 17 | }); 18 | }, 19 | readFile: function (path, options) { 20 | return new Promise( resolve => { 21 | fs.readFile(path, options, (err, content) => { 22 | if (err) { 23 | throw err; 24 | } 25 | resolve(content); 26 | }); 27 | }); 28 | } 29 | }; -------------------------------------------------------------------------------- /sample/all.js: -------------------------------------------------------------------------------- 1 | // 使用`Promise.all()`包装多个Promise实例 2 | // https://www.imooc.com/video/16634 3 | 4 | 5 | 6 | console.log('here we go'); 7 | Promise.all([1, 2, 3]) 8 | .then( all => { 9 | console.log('1:', all); 10 | return Promise.all([ function () { 11 | console.log('ooxx'); 12 | }, 'xxoo', false]); 13 | }) 14 | .then( all => { 15 | console.log('2:', all); 16 | let p1 = new Promise( resolve => { 17 | setTimeout(() => { 18 | resolve('I\'m P1'); 19 | }, 1500); 20 | }); 21 | let p2 = new Promise( (resolve, reject) => { 22 | setTimeout(() => { 23 | resolve('I\'m P2'); 24 | }, 1000); 25 | }); 26 | let p3 = new Promise( (resolve, reject) => { 27 | setTimeout(() => { 28 | resolve('I\'m P3'); 29 | }, 3000); 30 | }); 31 | return Promise.all([p1, p2, p3]); 32 | }) 33 | .then( all => { 34 | console.log('all', all); 35 | }) 36 | .catch( err => { 37 | console.log('Catch:', err); 38 | }); -------------------------------------------------------------------------------- /sample/asynchronous-operation.js: -------------------------------------------------------------------------------- 1 | // 异步操作的常见语法 2 | // https://www.imooc.com/video/16610 3 | 4 | // 事件侦听与响应 5 | document.getElementById('start').addEventListener('click', start, false); 6 | 7 | function start() { 8 | // 响应事件,进行相应的操作 9 | } 10 | 11 | // jQuery 用 `.on()` 也是事件侦听 12 | $('#start').on('click', start); 13 | 14 | 15 | // 回调 16 | // 比较常见的有ajax 17 | $.ajax('http://baidu.com', { 18 | success: function (res) { 19 | // 这里就是回调函数了 20 | } 21 | }); 22 | 23 | // 或者在页面加载完毕后回调 24 | $(function(){ 25 | // 这里也是回调函数 26 | }); 27 | -------------------------------------------------------------------------------- /sample/await.js: -------------------------------------------------------------------------------- 1 | // async/await 2 | // https://www.imooc.com/video/16631 3 | 4 | 5 | function resolveAfter2Seconds(x) { 6 | return new Promise(resolve => { 7 | setTimeout(() => { 8 | resolve(x); 9 | }, 2000); 10 | }); 11 | } 12 | 13 | async function f1() { 14 | var x = await resolveAfter2Seconds(10); 15 | console.log(x); // 10 16 | } 17 | f1(); -------------------------------------------------------------------------------- /sample/callback-hell.js: -------------------------------------------------------------------------------- 1 | // 回调地狱 2 | // https://www.imooc.com/video/16611 3 | 4 | a(function (resultsFromA) { 5 | b(resultsFromA, function (resultsFromB) { 6 | c(resultsFromB, function (resultsFromC) { 7 | d(resultsFromC, function (resultsFromD) { 8 | e(resultsFromD, function (resultsFromE) { 9 | f(resultsFromE, function (resultsFromF) { 10 | console.log(resultsFromF); 11 | }) 12 | }) 13 | }) 14 | }) 15 | }) 16 | }); -------------------------------------------------------------------------------- /sample/catch-then.js: -------------------------------------------------------------------------------- 1 | // .catch() + .then() 2 | // https://www.imooc.com/video/16621 3 | 4 | 5 | 6 | console.log('here we go'); 7 | 8 | new Promise(resolve => { 9 | setTimeout(() => { 10 | resolve(); 11 | }, 1000); 12 | }) 13 | .then( () => { 14 | console.log('start'); 15 | throw new Error('test error'); 16 | }) 17 | .catch( err => { 18 | console.log('I catch:', err); 19 | 20 | // 下面这一行的注释将引发不同的走向 21 | // throw new Error('another error'); 22 | }) 23 | .then( () => { 24 | console.log('arrive here'); 25 | }) 26 | .then( () => { 27 | console.log('... and here'); 28 | }) 29 | .catch( err => { 30 | console.log('No, I catch:', err); 31 | }); -------------------------------------------------------------------------------- /sample/error-reject.js: -------------------------------------------------------------------------------- 1 | // Promise会自动捕获内部异常,并交给rejected响应函数处理-reject响应捕获 2 | // https://www.imooc.com/video/16620 3 | 4 | console.log('here we go'); 5 | new Promise( (resolve, reject) => { 6 | setTimeout( () => { 7 | reject('bye'); 8 | }, 2000); 9 | }) 10 | .then( value => { 11 | console.log( value + ' world'); 12 | }, value => { 13 | console.log( 'Error:', value); 14 | }); -------------------------------------------------------------------------------- /sample/error.js: -------------------------------------------------------------------------------- 1 | // Promise会自动捕获内部异常,并交给rejected响应函数处理-catch捕获 2 | // https://www.imooc.com/video/16620 3 | 4 | console.log('here we go'); 5 | new Promise( resolve => { 6 | setTimeout( () => { 7 | throw new Error('bye'); 8 | }, 2000); 9 | }) 10 | .then( value => { 11 | console.log( value + ' world'); 12 | }) 13 | .catch( error => { 14 | console.log( 'Error:', error.message); 15 | }); -------------------------------------------------------------------------------- /sample/fetch-api.js: -------------------------------------------------------------------------------- 1 | // Fetch API 2 | // https://www.imooc.com/video/16630 3 | 4 | 5 | fetch('some.json') 6 | .then( response => { 7 | return response.json(); 8 | }) 9 | .then( json => { 10 | // do something with the json 11 | }) 12 | .catch( err => { 13 | console.log(err); 14 | }); -------------------------------------------------------------------------------- /sample/fulfilled-then.js: -------------------------------------------------------------------------------- 1 | // 假如一个Promise已经完成了,再.then()会怎样? 2 | // https://www.imooc.com/video/16615 3 | 4 | 5 | console.log('start'); 6 | 7 | let promise = new Promise(resolve => { 8 | setTimeout(() => { 9 | console.log('the promise fulfilled'); 10 | resolve('hello, world'); 11 | }, 1000); 12 | }); 13 | 14 | setTimeout(() => { 15 | promise.then( value => { 16 | console.log(value); 17 | }); 18 | }, 3000); -------------------------------------------------------------------------------- /sample/halls-test.js: -------------------------------------------------------------------------------- 1 | // 随堂小测试 2 | // https://www.imooc.com/video/16619 3 | // 假设doSomething和doSomethingElse返回的都是一个Promise实例 4 | // 原问题地址:http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html 5 | // 译文地址:http://fex.baidu.com/blog/2015/07/we-have-a-problem-with-promises/ 6 | 7 | // 问题一 8 | doSomething() 9 | .then(function () { 10 | return doSomethingElse(); 11 | }) 12 | .then(finalHandler); 13 | 14 | // 答案 15 | // doSomething 16 | // |-----------| 17 | // doSomethingElse(undefined) 18 | // |------------| 19 | // finalHandler(resultOfDoSomethingElse) 20 | // |------------| 21 | 22 | 23 | // 问题二 24 | doSomething() 25 | .then(function () { 26 | doSomethingElse(); 27 | }) 28 | .then(finalHandler); 29 | 30 | // 答案 31 | // doSomething 32 | // |------------------| 33 | // doSomethingElse(undefined) 34 | // |------------------| 35 | // finalHandler(undefined) 36 | // |------------------| 37 | 38 | 39 | // 问题三 40 | doSomething() 41 | .then(doSomethingElse()) 42 | .then(finalHandler); 43 | 44 | // 答案 45 | // doSomething 46 | // |------------------| 47 | // doSomethingElse(undefined) 48 | // |----------------------------------| 49 | // finalHandler(resultOfDoSomething) 50 | // |------------------| 51 | 52 | 53 | // 问题四 54 | doSomething() 55 | .then(doSomethingElse) 56 | .then(finalHandler); 57 | 58 | // 答案 59 | // doSomething 60 | // |-----------| 61 | // doSomethingElse(resultOfDoSomething) 62 | // |------------| 63 | // finalHandler(resultOfDoSomethingElse) 64 | // |------------------| 65 | -------------------------------------------------------------------------------- /sample/map.js: -------------------------------------------------------------------------------- 1 | // 遍历目录,找出最大的一个文件-通过Promise.all()和.map() 2 | // https://www.imooc.com/video/16622 3 | 4 | 5 | const fs = require('fs'); 6 | const path = require('path'); 7 | const FileSystem = require('./FileSystem'); 8 | 9 | function findLargest(dir) { 10 | return FileSystem.readDir(dir, 'utf-8') 11 | .then( files => { 12 | return Promise.all( files.map( file => { 13 | return new Promise (resolve => { 14 | fs.stat(path.join(dir, file), (err, stat) => { 15 | if (err) throw err; 16 | if (stat.isDirectory()) { 17 | return resolve({ 18 | size: 0 19 | }); 20 | } 21 | stat.file = file; 22 | resolve(stat); 23 | }); 24 | }); 25 | })); 26 | }) 27 | .then( stats => { 28 | let biggest = stats.reduce( (memo, stat) => { 29 | if(memo.size < stat.size) { 30 | return stat; 31 | } 32 | return memo; 33 | }); 34 | return biggest.file; 35 | }) 36 | } -------------------------------------------------------------------------------- /sample/maxfile.js: -------------------------------------------------------------------------------- 1 | // 遍历目录,找出最大的一个文件 2 | // https://www.imooc.com/video/16611 3 | 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | 7 | function findLargest(dir, callback) { 8 | fs.readdir(dir, function (err, files) { 9 | if (err) return callback(err); // [1] 10 | let count = files.length; // [2] 11 | let errored = false; 12 | let stats = []; 13 | files.forEach( file => { 14 | fs.stat(path.join(dir, file), (err, stat) => { 15 | if (errored) return; // [1] 16 | if (err) { 17 | errored = true; 18 | return callback(err); 19 | } 20 | stats.push(stat); // [2] 21 | 22 | if (--count === 0) { 23 | let largest = stats 24 | .filter(function (stat) { return stat.isFile(); }) 25 | .reduce(function (prev, next) { 26 | if (prev.size > next.size) return prev; 27 | return next; 28 | }); 29 | callback(null, files[stats.indexOf(largest)]); 30 | } 31 | }); 32 | }); 33 | }); 34 | } 35 | 36 | findLargest('./path/to/dir', function (err, filename) { 37 | if (err) return console.error(err); 38 | console.log('largest file was:', filename); 39 | }); -------------------------------------------------------------------------------- /sample/modal.js: -------------------------------------------------------------------------------- 1 | // 把任何异步操作包装成Promise 2 | // https://www.imooc.com/video/16629 3 | 4 | 5 | // 弹出窗体 6 | let confirm = popupManager.confirm('您确定么?'); 7 | confirm.promise 8 | .then(() => { 9 | // do confirm staff 10 | }) 11 | .catch(() => { 12 | // do cancel staff 13 | }); 14 | 15 | // 窗体的构造函数 16 | class Confirm { 17 | constructor() { 18 | this.promise = new Promise( (resolve, reject) => { 19 | this.confirmButton.onClick = resolve; 20 | this.cancelButton.onClick = reject; 21 | }) 22 | } 23 | } -------------------------------------------------------------------------------- /sample/nested-then.js: -------------------------------------------------------------------------------- 1 | // 嵌套.then() 2 | // https://www.imooc.com/video/16618 3 | 4 | console.log('start'); 5 | new Promise( resolve => { 6 | console.log('Step 1'); 7 | setTimeout(() => { 8 | resolve(100); 9 | }, 1000); 10 | }) 11 | .then( value => { 12 | return new Promise(resolve => { 13 | console.log('Step 1-1'); 14 | setTimeout(() => { 15 | resolve(110); 16 | }, 1000); 17 | }) 18 | .then( value => { 19 | console.log('Step 1-2'); 20 | return value; 21 | }) 22 | .then( value => { 23 | console.log('Step 1-3'); 24 | return value; 25 | }); 26 | }) 27 | .then(value => { 28 | console.log(value); 29 | console.log('Step 2'); 30 | }); -------------------------------------------------------------------------------- /sample/promise.js: -------------------------------------------------------------------------------- 1 | // Promise的设计 2 | // https://www.imooc.com/video/16612 3 | 4 | new Promise( 5 | /* 执行器 executor */ 6 | function (resolve, reject) { 7 | // 一段耗时很长的异步操作 8 | 9 | resolve(); // 数据处理完成 10 | 11 | reject(); // 数据处理出错 12 | } 13 | ) 14 | .then(function A() { 15 | // 成功,下一步 16 | }, function B() { 17 | // 失败,做相应处理 18 | }); -------------------------------------------------------------------------------- /sample/race.js: -------------------------------------------------------------------------------- 1 | // Promise.race() 2 | // https://www.imooc.com/video/16627 3 | 4 | 5 | console.log('start'); 6 | 7 | let p1 = new Promise(resolve => { 8 | // 这是一个长时间的调用 9 | setTimeout(() => { 10 | resolve('I\'m P1'); 11 | }, 10000); 12 | }); 13 | let p2 = new Promise(resolve => { 14 | // 这是个稍短的调用 15 | setTimeout(() => { 16 | resolve('I\'m P2'); 17 | }, 2000) 18 | }); 19 | Promise.race([p1, p2]) 20 | .then(value => { 21 | console.log(value); 22 | }); -------------------------------------------------------------------------------- /sample/reject.js: -------------------------------------------------------------------------------- 1 | // Promise.reject() 2 | // https://www.imooc.com/video/16626 3 | 4 | 5 | let promise = Promise.reject('something wrong'); 6 | 7 | promise 8 | .then( () => { 9 | console.log('it\'s ok'); 10 | }) 11 | .catch( () => { 12 | console.log('no, it\'s not ok'); 13 | 14 | return Promise.reject({ 15 | then() { 16 | console.log('it will be ok'); 17 | }, 18 | catch() { 19 | console.log('not yet'); 20 | } 21 | }); 22 | }); -------------------------------------------------------------------------------- /sample/resolve.js: -------------------------------------------------------------------------------- 1 | // Promise.resolve() 2 | // https://www.imooc.com/video/16625 3 | 4 | 5 | console.log('start'); 6 | 7 | Promise.resolve() 8 | .then( () => { 9 | console.log('Step 1'); 10 | return Promise.resolve('Hello'); 11 | }) 12 | .then( value => { 13 | console.log(value, 'World'); 14 | return Promise.resolve(new Promise( resolve => { 15 | setTimeout(() => { 16 | resolve('Good'); 17 | }, 2000); 18 | })); 19 | }) 20 | .then( value => { 21 | console.log(value, ' evening'); 22 | return Promise.resolve({ 23 | then() { 24 | console.log(', everyone'); 25 | } 26 | }) 27 | }) -------------------------------------------------------------------------------- /sample/spider.js: -------------------------------------------------------------------------------- 1 | // 开发一个爬虫,爬取某网站。(半成品) 2 | // https://www.imooc.com/video/16624 3 | 4 | let url = ['http://blog.meathill.com/']; 5 | function fetchAll(urls) { 6 | return urls.reduce((promise, url) => { 7 | return promise.then( () => { 8 | return fetch(url); 9 | }); 10 | }, Promise.resolve()); 11 | } 12 | function fetch(url) { 13 | return spider.fetch(url) 14 | .then( content => { 15 | return saveOrOther(content); 16 | }) 17 | .then( content => { 18 | let links = spider.findLinks(content); 19 | return fetchAll(links); 20 | }); 21 | } 22 | fetchAll(url); -------------------------------------------------------------------------------- /sample/timeout.js: -------------------------------------------------------------------------------- 1 | // 简单的范例-定时执行 2 | // https://www.imooc.com/video/16613 3 | 4 | console.log('here we go'); 5 | new Promise( resolve => { 6 | setTimeout( () => { 7 | resolve('hello'); 8 | }, 2000); 9 | }) 10 | .then( value => { 11 | console.log( value + ' world'); 12 | }); -------------------------------------------------------------------------------- /sample/timeout2.js: -------------------------------------------------------------------------------- 1 | // 分两次,顺序依次执行 2 | // https://www.imooc.com/video/16614] 3 | 4 | console.log('here we go'); 5 | new Promise( resolve => { 6 | setTimeout( () => { 7 | resolve('hello'); 8 | }, 2000); 9 | }) 10 | .then( value => { 11 | console.log(value); 12 | return new Promise( resolve => { 13 | setTimeout( () => { 14 | resolve('world'); 15 | }, 2000); 16 | }); 17 | }) 18 | .then( value => { 19 | console.log( value + ' world'); 20 | }); -------------------------------------------------------------------------------- /sample/timeout3.js: -------------------------------------------------------------------------------- 1 | // 假如在.then()的函数里面不返回新的Promise,会怎样? 2 | // https://www.imooc.com/video/16616 3 | 4 | console.log('here we go'); 5 | new Promise(resolve => { 6 | setTimeout( () => { 7 | resolve('hello'); 8 | }, 2000); 9 | }) 10 | .then( value => { 11 | console.log(value); 12 | console.log('everyone'); 13 | (function () { 14 | return new Promise(resolve => { 15 | setTimeout(() => { 16 | console.log('Mr.Laurence'); 17 | resolve('Merry Xmas'); 18 | }, 2000); 19 | }); 20 | }()); 21 | return false; 22 | }) 23 | .then( value => { 24 | console.log(value + ' world'); 25 | }); -------------------------------------------------------------------------------- /sample/wrap.js: -------------------------------------------------------------------------------- 1 | // 把回调包装成Promise 2 | // https://www.imooc.com/video/16628 3 | 4 | 5 | 6 | const fs = require('./FileSystem'); 7 | 8 | fs.readFile('../README.md', 'utf-8') 9 | .then(content => { 10 | console.log(content); 11 | }); --------------------------------------------------------------------------------