• <sub id="xcyjv"></sub><nav id="xcyjv"><code id="xcyjv"><meter id="xcyjv"></meter></code></nav>
      <nav id="xcyjv"></nav>
    1. <form id="xcyjv"><th id="xcyjv"></th></form><nav id="xcyjv"><mark id="xcyjv"></mark></nav>

        Learn JavaScript promises in about 70 minutes

        by qntm

        Because twenty-five other explanations weren't enough, here I will explain JavaScript promises. This tutorial is intended for people who already understand JavaScript.

        Previous educational essays of mine are Perl in 2 hours 30 minutes and regular expressions in 55 minutes.

        Contents

        The problem

        JavaScript is single-threaded. It will only ever do at most one thing at once. There is no concurrency.

        For example, if x is a global variable of some kind, then it is impossible for the value of x to change between these two lines of code:

        console.log(x);
        console.log(x);
        

        This is because there are no other threads which could modify x while these two lines are executing.

        *

        JavaScript is event-based. It maintains a queue of messages. "A function is associated with each message. When the [call] stack is empty, a message is taken out of the queue and processed. The processing consists of calling the associated function (and thus creating an initial stack frame). The message processing ends when the stack becomes empty again."

        We do not have the ability to inspect the queue, reorder it or remove messages from it.

        Typically in JavaScript a message takes (or should take) an extremely small amount of time to process, of the order of milliseconds. This ensures that the application continues to appear responsive. If a message takes a very long time to process, or forever:

        while(true) { }
        

        then no other messages can be processed, and the application becomes unresponsive. Commonly this leaves us with no choice but to kill the application entirely (e.g. by closing the browser tab).

        *

        Now suppose we want to make a HTTP request. What we would like to write is something like this:

        // BAD CODE DO NOT USE
        var xhr = new XMLHttpRequest();
        xhr.open("GET", "some/resource.json", false);
        xhr.send();
        
        console.log(xhr.responseText);
        

        This is how we make a synchronous HTTP request. The call to xhr.send() blocks until the HTTP request is completed, after which we are free to inspect the XMLHttpRequest object to see the response.

        But if we do this, then every other message gets blocked up behind this HTTP request. If the server takes a noticeable amount of time to respond, then the application stutters. If the server never responds, then the application locks up forever. Code like this is strongly discouraged due to the negative effect it has on the user experience.

        Instead, we must write code asynchronously.

        // GOOD CODE USE THIS INSTEAD
        var xhr = new XMLHttpRequest();
        
        xhr.addEventListener("load", function() {
        	console.log(this.responseText);
        });
        
        xhr.open("GET", "some/resource.json");
        xhr.send();
        

        Here, the xhr.send() call returns immediately, and JavaScript continues working, while carrying out the real HTTP request in the background (i.e. on a thread to which we, the JavaScript programmer, do not have programmatic access). This is called non-blocking I/O.

        Later, when (if) the HTTP request is completed, a new message will be placed in the message queue. The message will be associated with that listener function:

        function() {
        	console.log(this.responseText);
        }
        

        and, when JavaScript eventually reaches that message in the queue, the function will be called.

        *

        Now, how can we turn this HTTP request-making code into a callable function? What we want to write in our calling code is something like:

        var responseText = get("some/resource.json");
        

        But neither of these approaches works:

        var get = function(resource) {
        	var xhr = new XMLHttpRequest();
        	xhr.addEventListener("load", function() {
        		return this.responseText; // this value goes nowhere
        	});
        	xhr.open("GET", resource);
        	xhr.send();
        	return xhr.responseText; // returns `undefined`
        };
        

        The solution is callbacks. When calling get, we pass in our URL but also a callback function. When — at some nebulous future time — get has finished its task, it will call that function, passing the result in.

        var get = function(resource, callback) {
        	var xhr = new XMLHttpRequest();
        	xhr.addEventListener("load", function() {
        		callback(this.responseText);
        	});
        	xhr.open("GET", resource);
        	xhr.send();
        };
        

        Usage:

        get("some/resource.json", function(responseText) {
        	console.log(responseText);
        });
        

        This is called continuation-passing style. As a general pattern, this works well, but it is not very pretty. It means that all later code has to be placed inside, or called from, that callback.

        *

        Interestingly, this pattern can even find use in functions which would not normally be asynchronous. A function like:

        var parseJson = function(json) {
        	var obj = JSON.parse(json);
        	return obj;
        };
        

        becomes:

        var parseJson = function(json, callback) {
        	setTimeout(function() {
        		var obj = JSON.parse(json);
        		callback(obj);
        	}, 0);
        };
        

        Here, setTimeout() is simply putting a message on the queue right away, without any delay. Although the interval specified is 0 milliseconds, this does not mean that

        function() {
        	var obj = JSON.parse(json);
        	callback(obj);
        }
        

        will be invoked immediately; other messages which have been queued up in the meantime will be handled first. We might do this if we are carrying out a long single calculation and we want to break it up into smaller messages.

        Note that parseJson no longer explicitly returns anything, which is another way of saying that it returns undefined. The same is true of get and any other function employing this pattern.

        *

        This pattern of callbacks becomes troublesome when we need to carry out several tasks in sequence:

        get("some/resource.json", function(responseText) {
        	parseJson(responseText, function(obj) {
        		extractFnord(obj, function(fnord) {
        			console.log(fnord);
        		});
        	});
        });
        

        Note the increasingly severe indentation. This is called callback hell.

        The worse problem

        How do we handle errors in this scenario? There are several ways to do this, but they both tend to make the situation even less readable.

        Asynchronous error handling technique 1

        One technique for handling errors is this:

        var get = function(resource, callback) {
        	var xhr = new XMLHttpRequest();
        	xhr.addEventListener("load", function() {
        		if(this.status === 200) {
        			callback(undefined, this.responseText);
        		} else {
        			callback(Error());
        		}
        	});
        	xhr.addEventListener("error", function() {
        		callback(Error());
        	});
        	xhr.open("GET", resource);
        	xhr.send();
        };
        

        And:

        var parseJson = function(json, callback) {
        	setTimeout(function() {
        		try {
        			var obj = JSON.parse(json);
        			callback(undefined, obj);
        		} catch(e) {
        			callback(e);
        		}
        	}, 0);
        };
        

        Here we pass two arguments to the callback, the first of which is an error. Customarily, if nothing goes wrong, then err is falsy.

        Usage:

        get("some/resource.json", function(err1, responseText) {
        	if(err1) {
        		console.error(err1);
        		return;
        	}
        	parseJson(responseText, function(err2, obj) {
        		if(err2) {
        			console.error(err2);
        			return;
        		}
        		extractFnord(obj, function(err3, fnord) {
        			if(err3) {
        				console.error(err3);
        				return;
        			}
        			console.log(fnord);
        		});
        	});
        });
        

        This approach is seen very commonly. As a prime example, take a look at the fs module in Node.js, which carries out filesystem operations, another form of I/O. Compare this blocking I/O function:

        var str = fs.readFileSync("example.txt", "utf8");
        console.log(str);
        

        with this non-blocking version:

        fs.readFile("example.txt", "utf8", function(err, str) {
        	if(err) {
        		console.error(err);
        		return;
        	}
        	console.log(str);
        });
        

        Asynchronous error handling technique 2

        The other way to handle errors is to pass two callbacks into the calculation. One is for success, and the other is for failure:

        var get = function(resource, callback, errback) {
        	var xhr = new XMLHttpRequest();
        	xhr.addEventListener("load", function() {
        		if(this.status === 200) {
        			callback(this.responseText);
        		} else {
        			errback(Error());
        		}
        	});
        	xhr.addEventListener("error", function() {
        		errback(Error());
        	});
        	xhr.open("GET", resource);
        	xhr.send();
        };
        

        And:

        var parseJson = function(json, callback, errback) {
        	setTimeout(function() {
        		try {
        			var obj = JSON.parse(json);
        			callback(obj);
        		} catch(e) {
        			errback(e);
        		}
        	}, 0);
        };
        

        Usage:

        get("some/resource.json", function(responseText) {
        	parseJson(responseText, function(obj) {
        		extractFnord(obj, function(fnord) {
        			console.log(fnord);
        		}, function(err3) {
        			console.error(err3);
        		});
        	}, function(err2) {
        		console.error(err2);
        	});
        }, function(err1) {
        	console.error(err1);
        });
        

        This is marginally better, but still pretty ghastly. Both approaches have drawbacks and some inflexibility, as well as bloating argument lists. There must be a better way!

        Introducing promises

        Let's do some refactoring. Rewrite get like so:

        var get = function(resource) {
        	return new Promise(function(resolve, reject) {
        		var xhr = new XMLHttpRequest();
        		xhr.addEventListener("load", function() {
        			if(this.status === 200) {
        				resolve(this.responseText);
        			} else {
        				reject(Error());
        			}
        		});
        		xhr.addEventListener("error", function() {
        			reject(Error());
        		});
        		xhr.open("GET", resource);
        		xhr.send();
        	});
        };
        

        And similarly parseJson:

        var parseJson = function(json) {
        	return new Promise(function(resolve, reject) {
        		setTimeout(function() {
        			try {
        				var obj = JSON.parse(json);
        				resolve(obj);
        			} catch(e) {
        				reject(e);
        			}
        		}, 0);
        	});
        };
        

        The asynchronous functions no longer accept callbacks, either for success or for failure. But they do return something now. The object returned is called a promise. The promise represents the task which get or parseJson (or extractFnord) has promised to do. It has three states: pending, fulfilled or rejected.

        A promise starts out pending. The inner function(resolve, reject) { ... }, which we supply, is called the executor callback. The promise calls this function, passing in two arguments, resolve and reject. When the task has been done, we call resolve to fulfill the promise i.e. mark the task as completed. Or, if the task has failed, we call reject to reject the promise i.e. mark the task as failed. A promise which is fulfilled or rejected is called settled.

        By interacting with this promise object, we can register success and error callbacks to be called when it settles. But first, some bullet points!

        Most of these little guarantees just serve to make promises simpler and more robust in their behaviour. Notice that there were no such guarantees in our original asynchronous functions definitions; there was nothing to stop us from, say, calling callback twice with two different values. Promises protect us from such weirdness and from the boilerplate code which would be required to manually handle such weirdness.

        And also introducing then()

        Now here's a very important point: there is no way to directly inspect the current state of a promise, or the value it fulfilled with (if any), or the error it rejected with (if any).

        Instead, we call then(callback, errback) on a promise to register a success callback and an error callback. And so our usage now looks like this:

        get("some/resource.json").then(function(responseText) {
        	parseJson(responseText).then(function(obj) {
        		extractFnord(obj).then(function(fnord) {
        			console.log(fnord);
        		}, function(err3) {
        			console.error(err3);
        		});
        	}, function(err2) {
        		console.error(err2);
        	});
        }, function(err1) {
        	console.error(err1);
        });
        

        This still isn't great, but we're gradually getting closer to something good. First, more bullet points:

        Promise chaining

        Calling then(callback, errback) on a promise returns a new promise. The way in which the new promise settles depends on two things:

        1. The way in which the first promise settles.
        2. What happens inside the success or error callback.

        Here are some examples.

        *

        In a success or error callback, we can return or throw nearly any value we like. If we don't return anything, this is the same as returning undefined, so the fulfilled value of the new promise is undefined, which is fine. There's one special case, which we may remember from earlier:

        If we fulfill a promise with a second promise, the first promise settles the same way as the second

        This applies no matter what method we use to fulfill that first promise, be it Promise.resolve():

        Promise.resolve("foo")                                   // fulfills with "foo"
        Promise.reject("bar")                                    // rejects with "bar"
        Promise.resolve(Promise.resolve("foo"))                  // fulfills with "foo"
        Promise.resolve(Promise.reject("bar"))                   // rejects with "bar"
        Promise.resolve(Promise.resolve(Promise.resolve("foo"))) // fulfills with "foo"
        Promise.resolve(Promise.resolve(Promise.reject("bar")))  // rejects with "bar"
        // and so on
        

        Or the executor callback:

        new Promise(function(resolve, reject) { resolve("foo"); })                  // fulfills with "foo"
        new Promise(function(resolve, reject) { reject("bar"); })                   // rejects with "bar"
        new Promise(function(resolve, reject) { resolve(Promise.resolve("foo")); }) // fulfills with "foo"
        new Promise(function(resolve, reject) { resolve(Promise.reject("foo")); })  // rejects with "bar"
        // and so on
        

        Or a success or error callback:

        Promise.resolve().then(function() { return "foo"; })                  // fulfills with "foo"
        Promise.resolve().then(function() { throw "bar"; })                   // rejects with "bar"
        Promise.resolve().then(function() { return Promise.resolve("foo"); }) // fulfills with "foo"
        Promise.resolve().then(function() { return Promise.reject("bar"); })  // rejects with "bar"
        // and so on
        

        (Note that it's totally okay to reject a promise with a second promise:

        Promise.reject(Promise.resolve("foo"))                                      // rejects with `Promise.resolve("foo")`
        new Promise(function(resolve, reject) { reject(Promise.resolve("foo")); }); // rejects with `Promise.resolve("foo")`
        Promise.resolve().then(function() { throw Promise.resolve("foo"); })        // rejects with `Promise.resolve("foo")`
        // and so on
        

        But this is a rather odd thing to do...)

        *

        Why is this so significant?

        Because it means that we can asynchronously transform values as well. Which allows us to suddenly turn this code:

        get("some/resource.json").then(function(responseText) {
        	parseJson(responseText).then(function(obj) {
        		extractFnord(obj).then(function(fnord) {
        			console.log(fnord);
        		}, function(err3) {
        			console.error(err3);
        		});
        	}, function(err2) {
        		console.error(err2);
        	});
        }, function(err1) {
        	console.error(err1);
        });
        

        into this:

        get("some/resource.json").then(function(responseText) {
        	return parseJson(responseText);
        }).then(function(obj) {
        	return extractFnord(obj);
        }).then(function(fnord) {
        	console.log(fnord);
        }).catch(function(err) {
        	console.error(err);
        });
        

        And boom! We're out of callback hell!

        *

        Let's break our new asynchronous code down. There are five promises in the main chain.

        *

        One more thing. Since the callback functions are guaranteed to be called with only a single argument, and the value of this passed will be undefined, and our intermediate functions parseJson and extractFnord don't use this internally, our code may be simplified even further:

        get("some/resource.json")
        	.then(parseJson)
        	.then(extractFnord)
        	.then(function(fnord) {
        		console.log(fnord);
        	}).catch(function(err) {
        		console.error(err);
        	});
        

        In some browsers, console.log and console.error aren't sensitive to the value of this either, so we can even go as far as:

        get("some/resource.json")
        	.then(parseJson)
        	.then(extractFnord)
        	.then(console.log)
        	.catch(console.error);
        

        Amazing!

        To take maximum advantage of this pattern, write functions (and methods!) which

        1. Accept only a single argument
        2. Do not use this (or, use this but also use bind() to fix its value)
        3. Return a promise

        *

        So here's a fun edge case. If we fulfill a promise with a second promise, the first promise settles the same way as the second. What if the second promise is the first promise?

        var p = new Promise(function(resolve, reject) {
        	setTimeout(function() {
        		resolve(p);
        	}, 0);
        });
        

        (Note that setTimeout must be used here, since the executor callback is called synchronously at Promise construction time, at which time the value of p is still undefined.)

        Answer: this promise rejects with a TypeError because of the cycle that has been introduced.

        Let's use this to segue into the topic of error handling.

        Error handling in a promise chain

        If a promise rejects, execution passes to the next available error callback. To demonstrate how this works, we'll start with a basic promise chain:

        Promise.resolve("foo").then(function(str) {
        	return str + str;
        }).then(function(str) {
        	console.log(str);
        }, function(err) {
        	console.error(err);
        });
        

        and see what happens if we introduce errors — which is to say, cause promises to reject — at various points.

        This code:

        Promise.reject("bar").then(function(str) {
        	return str + str;
        }).then(function(str) {
        	console.log(str);
        }, function(err) {
        	console.error(err);
        });
        

        hits none of the success callbacks, and immediately errors out printing "bar".

        This code:

        Promise.resolve("foo").then(function(str) {
        	throw str + str;
        }).then(function(str) {
        	console.log(str);
        }, function(err) {
        	console.error(err);
        });
        

        hits the first success callback, then errors out printing "foofoo". The second success callback is not hit.

        And finally, this code:

        Promise.resolve("foo").then(function(str) {
        	return str + str;
        }).then(function(str) {
        	throw str;
        }, function(err) {
        	console.error(err);
        });
        

        prints nothing at all!

        Remember: when we use then(callback, errback), either the success callback or the error callback will be called, never both. errback does not handle exceptions thrown by callback. callback and errback are both intended to handle the outcome from the previous promise, not from each other.

        Because of this potential for "leaking" an error, I think it is good practice to never call then(callback, errback), passing in both callbacks. It's safer to always use then(callback), passing in only one callback, or, when handling errors at the tail end of a chain, to use catch(errback):

        Promise.resolve("foo").then(function(str) {
        	return str + str;
        }).then(function(str) {
        	throw str;
        }).catch(function(err) {
        	console.error(err);
        });
        

        And in general, we should always conclude a promise chain with a catch() call, because otherwise errors in the chain will disappear and never be detected.

        Of course, if an exception is thrown during an error callback, then we may be out of luck entirely, but that's a standing problem with all of error handling...

        Implementation variations

        Throughout this document we have been using the native Promise implementation which is present in many JavaScript engines. This is a relatively new feature of JavaScript and does not have universal support; in particular, it is not available in Internet Explorer. However, there are numerous third-party implementations of promises which work in a basically identical way, such as Q and Bluebird.

        All these implementations conform to a technical specification called Promises/A+. This specification only really specifies the behaviour of the then() method. The then() method will work identically in all conforming implementations.

        Everything else is left up to implementers. For example, the APIs for:

        are not specified by Promises/A+. The native Promise implementation specified in ES6 works like this, and other implementations generally work similarly, but these APIs are not necessarily universal.

        Different implementations are also at liberty to offer whatever additional functionality they wish. Promise offers two other methods worth mentioning, Promise.all() and Promise.race(), both of which accept an array of promises run "in parallel". Promise.all() fulfills with an array containing the fulfilled values from all the inner promises, Promise.race() fulfills with the value of the first inner promise to fulfill. Other implementations usually offer equivalent functionality and often offer much more functionality.

        Summary of promise settling behaviour

        Promise Attempted settle method Value/error New state Value/error
        new Promise(function(resolve, reject) { resolve( "foo" ); }) Fulfilled "foo"
        new Promise(function(resolve, reject) { resolve( Promise.resolve("X") ); }) Fulfilled "X"
        new Promise(function(resolve, reject) { resolve( Promise.reject("Y") ); }) Rejected "Y"
        new Promise(function(resolve, reject) { reject( "foo" ); }) Rejected "foo"
        new Promise(function(resolve, reject) { reject( Promise.resolve("X") ); }) Rejected Promise.resolve("X")
        new Promise(function(resolve, reject) { reject( Promise.reject("Y") ); }) Rejected Promise.reject("Y")
        new Promise(function(resolve, reject) { return  "foo" ; }) Pending none
        new Promise(function(resolve, reject) { return  Promise.resolve("X") ; }) Pending none
        new Promise(function(resolve, reject) { return  Promise.reject("Y") ; }) Pending none
        new Promise(function(resolve, reject) { throw  "foo" ; }) Rejected "foo"
        new Promise(function(resolve, reject) { throw  Promise.resolve("X") ; }) Rejected Promise.resolve("X")
        new Promise(function(resolve, reject) { throw  Promise.reject("Y") ; }) Rejected Promise.reject("Y")
        Promise.resolve().then(function() { resolve( "foo" ); }) Rejected ReferenceError("resolve is not defined")
        Promise.resolve().then(function() { resolve( Promise.resolve("X") ); }) Rejected ReferenceError("resolve is not defined")
        Promise.resolve().then(function() { resolve( Promise.reject("Y") ); }) Rejected ReferenceError("resolve is not defined")
        Promise.resolve().then(function() { reject( "foo" ); }) Rejected ReferenceError("reject is not defined")
        Promise.resolve().then(function() { reject( Promise.resolve("X") ); }) Rejected ReferenceError("reject is not defined")
        Promise.resolve().then(function() { reject( Promise.reject("Y") ); }) Rejected ReferenceError("reject is not defined")
        Promise.resolve().then(function() { return  "foo" ; }) Fulfilled "foo"
        Promise.resolve().then(function() { return  Promise.resolve("X") ; }) Fulfilled "X"
        Promise.resolve().then(function() { return  Promise.reject("Y") ; }) Rejected "Y"
        Promise.resolve().then(function() { throw  "foo" ; }) Rejected "foo"
        Promise.resolve().then(function() { throw  Promise.resolve("X") ; }) Rejected Promise.resolve("X")
        Promise.resolve().then(function() { throw  Promise.reject("Y") ; }) Rejected Promise.reject("Y")

        Conclusion

        I find promises to be heck of complicated and it wasn't until I sat down and tried to write this that I realised just how poorly I understood them. Not pictured here is the lengthy interlude where I gave up and, as a learning exercise, attempted to read, understand and implement the Promises/A+ specification myself, which nearly caused my head to explode. Anyway, I think I have a pretty good handle on them now, and I hope you do too.

        Back to Things Of Interest

        01彩票网app
      1. <sub id="xcyjv"></sub><nav id="xcyjv"><code id="xcyjv"><meter id="xcyjv"></meter></code></nav>
          <nav id="xcyjv"></nav>
        1. <form id="xcyjv"><th id="xcyjv"></th></form><nav id="xcyjv"><mark id="xcyjv"></mark></nav>
            崇左 | 顺德 | 庆阳 | 达州 | 邵阳 | 武安 | 海安 | 辽源 | 广汉 | 天水 | 新泰 | 保亭 | 黑河 | 白沙 | 汉川 | 衡水 | 承德 | 漳州 | 安康 | 丽水 | 滨州 | 三沙 | 抚州 | 顺德 | 南京 | 陇南 | 安顺 | 文山 | 晋城 | 临猗 | 玉环 | 楚雄 | 丽水 | 长兴 | 延边 | 新余 | 眉山 | 南平 | 海南海口 | 偃师 | 迪庆 | 毕节 | 赣州 | 天水 | 舟山 | 燕郊 | 莱芜 | 赵县 | 清徐 | 涿州 | 周口 | 眉山 | 毕节 | 阿坝 | 瓦房店 | 陕西西安 | 灌南 | 安徽合肥 | 定西 | 嘉峪关 | 香港香港 | 汕头 | 泰兴 | 鹤壁 | 和县 | 永康 | 温岭 | 兴安盟 | 西藏拉萨 | 钦州 | 聊城 | 仙桃 | 泰州 | 三亚 | 盐城 | 许昌 | 博罗 | 邳州 | 郴州 | 东莞 | 湖北武汉 | 灵宝 | 承德 | 鹤岗 | 宁德 | 任丘 | 温州 | 宁波 | 资阳 | 云浮 | 如皋 | 山西太原 | 毕节 | 泰安 | 亳州 | 阿里 | 玉环 | 昆山 | 灵宝 | 黄山 | 四平 | 东方 | 大同 | 海西 | 甘肃兰州 | 攀枝花 | 周口 | 东莞 | 呼伦贝尔 | 溧阳 | 商洛 | 青州 | 自贡 | 丽江 | 长兴 | 云浮 | 丹东 | 深圳 | 苍南 | 辽宁沈阳 | 广元 | 江苏苏州 | 石狮 | 延边 | 陇南 | 日照 | 仁怀 | 焦作 | 常德 | 兴化 | 泉州 | 绥化 | 泰兴 | 锦州 | 黄南 | 瓦房店 | 延边 | 广元 | 克孜勒苏 | 滁州 | 吉林长春 | 德州 | 日喀则 | 慈溪 | 安吉 | 黑河 | 济南 | 商丘 | 牡丹江 | 大连 | 顺德 | 海安 | 淮北 | 运城 | 沭阳 | 保山 | 临沧 | 石河子 | 吴忠 | 公主岭 | 广汉 | 滁州 | 枣阳 | 兴安盟 | 铜仁 | 宜春 | 岳阳 | 文昌 | 三河 | 南安 | 崇左 | 河池 | 六安 | 厦门 | 海安 | 大连 | 昌吉 | 包头 | 长葛 | 枣阳 | 丽江 | 阿坝 | 凉山 | 黔南 | 阳江 | 芜湖 | 广汉 | 永康 | 大连 | 蓬莱 | 宣城 | 宣城 | 广汉 | 克拉玛依 | 定安 | 沭阳 | 海门 | 余姚 | 海西 | 日土 | 衡水 | 肇庆 | 渭南 | 沛县 | 聊城 | 燕郊 | 南安 | 汕头 | 河池 | 滨州 | 昌吉 | 昌吉 | 黔南 | 岳阳 | 湖北武汉 | 葫芦岛 | 池州 | 莱州 | 烟台 | 黔东南 | 仁怀 | 崇左 | 芜湖 | 惠东 | 日喀则 | 海宁 | 池州 | 阿勒泰 | 嘉兴 | 建湖 | 无锡 | 长兴 | 余姚 | 锦州 | 五指山 | 东莞 | 沧州 | 潜江 | 固原 | 宁夏银川 | 廊坊 | 漳州 | 三河 | 伊犁 | 阜阳 | 保山 | 河池 | 邹城 | 延边 | 洛阳 | 池州 | 湘西 | 曹县 | 石狮 | 兴化 | 绍兴 | 承德 | 屯昌 | 广西南宁 | 秦皇岛 | 随州 | 海东 | 宁波 | 中山 | 鹤岗 | 吐鲁番 | 平顶山 | 洛阳 | 桐乡 | 赣州 | 仁怀 | 平凉 | 慈溪 | 宜春 | 贺州 | 舟山 | 海西 | 伊犁 | 顺德 | 盘锦 | 汝州 | 昭通 | 白城 | 河南郑州 | 武威 | 湖州 | 赵县 | 桓台 | 晋江 | 洛阳 | 十堰 | 眉山 | 永州 | 黄山 | 湘西 | 泗洪 | 苍南 | 南通 | 七台河 | 铜仁 | 商丘 | 衡阳 | 梅州 | 长垣 | 岳阳 | 三门峡 | 溧阳 | 亳州 | 庄河 | 嘉兴 | 北海 | 扬中 | 鸡西 | 和县 | 山南 | 梅州 | 仁怀 | 甘孜 | 沧州 | 台湾台湾 | 商洛 | 丹阳 | 贵州贵阳 | 新泰 | 招远 | 东台 | 佳木斯 | 晋城 | 内蒙古呼和浩特 | 南充 | 淮安 | 湘西 | 铜仁 | 白城 | 宁德 | 辽阳 | 南安 | 馆陶 | 永新 | 随州 | 怒江 | 平凉 | 乐平 | 吉安 | 铁岭 | 绵阳 | 南京 | 七台河 | 巴音郭楞 | 海北 | 洛阳 | 江西南昌 | 十堰 | 阿拉善盟 | 汕头 | 中山 | 淄博 | 绍兴 | 巴音郭楞 | 东莞 | 营口 | 枣庄 | 平顶山 | 台南 | 许昌 | 汕头 | 张家界 | 六安 | 包头 | 宜宾 | 宁波 | 遵义 | 南京 | 新疆乌鲁木齐 | 金坛 | 周口 | 铁岭 | 儋州 | 邹平 | 德州 | 东阳 | 河北石家庄 | 南平 | 石狮 | 珠海 | 鹤壁 | 泗阳 | 唐山 | 台北 | 烟台 | 新余 | 安岳 | 柳州 | 张家口 | 博尔塔拉 | 扬州 | 遵义 | 扬中 | 西藏拉萨 | 台山 | 武威 | 台北 | 威海 | 大丰 | 博尔塔拉 | 山西太原 | 鹤壁 | 崇左 | 黄冈 | 巴音郭楞 | 安顺 | 长兴 | 张北 | 定州 | 湖州 | 漳州 | 绵阳 | 长治 | 黄冈 | 桐城 | 长葛 | 台中 | 包头 | 乐平 | 贺州 | 任丘 | 鹤岗 | 泰兴 | 肇庆 | 象山 | 石嘴山 | 浙江杭州 | 玉树 | 吴忠 | 晋城 | 黔西南 | 锡林郭勒 | 潮州 | 濮阳 | 迪庆 | 巴中 | 德阳 | 乌兰察布 | 鹤壁 | 陵水 | 鹤岗 | 燕郊 | 曲靖 | 屯昌 | 文山 | 汕头 | 德清 | 禹州 | 景德镇 | 漳州 | 赵县 | 三门峡 | 永州 | 楚雄 | 日土 | 泰州 | 招远 | 高雄 | 宁夏银川 | 亳州 | 儋州 | 黄冈 | 定安 | 张北 | 玉环 | 保山 | 内江 | 本溪 | 临沂 | 绥化 | 乐清 | 桂林 | 锡林郭勒 | 大丰 | 南阳 | 定西 | 南京 | 简阳 | 东阳 | 黔南 | 长葛 | 汝州 | 昌吉 | 衢州 | 自贡 | 鹤壁 | 酒泉 | 张掖 | 阿拉尔 | 宣城 | 内蒙古呼和浩特 | 丹阳 | 汉川 | 临汾 | 文山 | 黔西南 | 泰兴 | 屯昌 | 博尔塔拉 | 新余 | 张掖 | 巴中 | 昭通 | 新乡 | 锡林郭勒 | 文山 | 西藏拉萨 | 黄山 | 十堰 | 温州 | 宁波 | 大庆 | 姜堰 | 黄山 | 惠州 | 陇南 | 定州 | 惠州 | 潍坊 | 安岳 | 深圳 | 天水 | 湖州 | 驻马店 | 清远 | 保定 | 咸阳 | 黔西南 | 宁波 | 桐城 | 酒泉 | 三门峡 | 山西太原 | 吉安 | 瓦房店 | 湛江 | 菏泽 | 玉林 | 桂林 | 舟山 | 齐齐哈尔 | 六安 | 昌吉 | 阿拉善盟 | 新疆乌鲁木齐 | 阿里 | 海安 | 娄底 | 崇左 | 金坛 | 黔南 | 吉安 | 嘉善 | 项城 | 武威 | 黑龙江哈尔滨 | 醴陵 | 厦门 | 东阳 | 铁岭 | 福建福州 | 铜川 | 章丘 | 山东青岛 | 仁怀 | 林芝 | 武威 | 广元 | 如东 | 宁国 | 宿迁 | 高雄 | 广饶 | 贺州 | 石狮 | 宝应县 | 偃师 | 济宁 | 余姚 | 石狮 | 鄂州 | 绵阳 | 瓦房店 | 汕尾 | 威海 | 巴彦淖尔市 | 河北石家庄 | 曹县 | 泰州 | 涿州 | 新疆乌鲁木齐 | 固原 | 襄阳 | 三明 | 抚顺 | 曲靖 | 淮安 | 广元 | 滁州 | 河源 | 襄阳 | 明港 | 松原 | 慈溪 | 河池 | 运城 | 包头 | 怀化 | 东营 | 天门 | 齐齐哈尔 | 宣城 | 江苏苏州 | 永新 | 赣州 | 白山 | 崇左 | 常州 | 海拉尔 | 广西南宁 | 阿里 | 黔东南 | 海北 | 乐山 | 如皋 | 益阳 | 滨州 | 阿克苏 | 承德 | 海安 | 泰州 | 宜都 | 顺德 | 台州 | 湘潭 | 山西太原 | 大庆 | 芜湖 | 定州 | 庆阳 | 象山 | 山西太原 | 山南 | 盐城 | 梧州 | 绥化 | 丽水 | 建湖 | 柳州 | 鄂尔多斯 | 肥城 | 赣州 | 辽源 | 海丰 | 铜陵 | 黑龙江哈尔滨 | 吴忠 | 南通 | 四平 | 东莞 | 大理 | 佳木斯 | 迁安市 | 万宁 | 日土 | 楚雄 | 阳泉 | 漳州 | 白沙 | 安岳 | 曲靖 | 安岳 | 乐山 | 神农架 | 章丘 | 日土 | 阿克苏 | 正定 | 巴中 | 陵水 | 贺州 | 招远 | 黔南 | 山南 | 张家界 | 柳州 | 湛江 | 亳州 | 泸州 | 福建福州 | 博罗 | 张掖 | 日照 | 宁夏银川 | 朝阳 | 果洛 | 淮南 | 通化 | 琼海 | 通辽 | 乌兰察布 | 长治 | 滁州 | 巢湖 | 韶关 | 基隆 | 馆陶 | 泗洪 | 七台河 | 吐鲁番 | 江门 | 天水 | 鄂州 | 定州 | 广西南宁 | 吉林 | 澄迈 | 五指山 | 湘潭 | 库尔勒 | 陕西西安 | 平凉 | 安吉 | 云南昆明 | 醴陵 | 辽阳 | 扬中 | 抚顺 | 怒江 | 廊坊 | 燕郊 | 保定 | 库尔勒 | 泰兴 | 吴忠 | 项城 | 海西 | 商丘 | 那曲 | 石狮 | 甘肃兰州 | 玉林 | 菏泽 | 南充 | 韶关 | 铜陵 | 曲靖 | 顺德 | 定州 | 大同 | 图木舒克 | 德州 | 池州 | 如东 | 潍坊 | 扬州 | 安岳 | 鞍山 | 醴陵 | 泰安 | 驻马店 | 日照 | 武威 | 云浮 | 庆阳 | 平潭 | 开封 | 潜江 | 泰州 | 榆林 | 红河 | 宝鸡 | 莆田 | 玉树 | 河源 | 四平 | 醴陵 | 石河子 | 单县 | 宿迁 | 长葛 | 邢台 | 包头 | 乌兰察布 | 东莞 | 沭阳 | 海丰 | 单县 | 六安 | 景德镇 | 德宏 | 济南 | 马鞍山 | 澳门澳门 | 安岳 | 五家渠 | 德阳 | 阿勒泰 | 象山 | 焦作 | 伊犁 | 娄底 | 蚌埠 | 景德镇 | 内江 | 烟台 | 西双版纳 | 阿拉尔 | 醴陵 | 黄山 | 图木舒克 | 泗洪 | 文昌 | 鸡西 | 喀什 | 阳泉 | 神木 | 白沙 | 长垣 | 清远 | 乳山 | 海南海口 | 楚雄 | 台湾台湾 | 襄阳 | 桐乡 | 高雄 | 大兴安岭 | 阿拉尔 | 苍南 | 嘉兴 | 安庆 | 漳州 | 阿拉善盟 | 昌都 | 瓦房店 | 黑河 | 阿里 | 昌吉 | 湘潭 | 阿里 | 新乡 | 醴陵 | 酒泉 | 广汉 | 百色 | 潮州 | 荆州 | 长治 | 醴陵 | 宝鸡 | 荆门 | 镇江 | 鞍山 | 宁波 | 吉林长春 | 绍兴 | 江西南昌 | 泸州 | 巴音郭楞 | 阳泉 | 周口 | 山西太原 | 海北 | 韶关 | 海北 | 万宁 | 宜宾 | 平潭 | 惠州 | 邳州 | 图木舒克 | 马鞍山 | 烟台 | 海南 | 白城 | 克拉玛依 | 新沂 | 保定 | 毕节 | 三亚 | 淮北 | 博罗 | 德阳 | 枣庄 | 海丰 | 邳州 | 吐鲁番 | 宜宾 | 泉州 | 自贡 | 汕头 | 漯河 | 安岳 | 海东 | 迁安市 | 晋江 | 徐州 | 朔州 | 秦皇岛 | 防城港 | 金坛 | 丹东 | 庄河 | 贵港 | 南通 | 台山 | 萍乡 | 珠海 | 吴忠 | 池州 | 曲靖 | 长兴 | 仙桃 | 桓台 | 周口 | 贺州 | 枣庄 | 营口 | 台山 | 株洲 | 连云港 | 山南 | 南平 | 五家渠 | 海东 | 靖江 | 三亚 | 桐乡 | 安顺 | 雅安 | 洛阳 | 嘉兴 | 韶关 | 沭阳 | 白银 | 泉州 | 昭通 | 吐鲁番 | 广饶 | 酒泉 | 曲靖 | 沭阳 | 高密 | 泰兴 | 泰州 | 白银 | 广安 | 锡林郭勒 | 甘孜 | 山南 | 铁岭 | 七台河 | 徐州 | 克孜勒苏 | 乌兰察布 | 阿勒泰 | 宜春 | 宝鸡 | 连云港 | 博罗 | 临汾 | 保定 | 永康 | 建湖 | 荆门 | 新乡 | 连云港 | 肇庆 | 焦作 | 溧阳 | 通辽 | 钦州 | 咸宁 | 芜湖 | 洛阳 | 灌云 | 七台河 | 新余 | 红河 | 石狮 | 克拉玛依 | 牡丹江 | 绵阳 | 东海 | 湛江 | 黔西南 | 九江 | 昌吉 | 鄢陵 | 随州 | 章丘 | 海西 | 鹤岗 | 龙口 | 喀什 | 长治 | 东阳 | 临汾 | 明港 | 宁夏银川 | 鄂尔多斯 | 沭阳 | 新疆乌鲁木齐 | 蓬莱 | 永新 | 资阳 | 禹州 | 吉林 | 灌南 | 广饶 | 九江 | 桐乡 | 菏泽 | 泸州 | 仁怀 | 儋州 | 黔南 | 昭通 | 庄河 | 桐乡 | 海西 | 楚雄 | 徐州 | 包头 | 定州 | 辽宁沈阳 | 台北 | 漯河 | 安庆 | 禹州 | 丽水 | 果洛 | 德宏 | 芜湖 | 黄山 | 海南海口 | 玉林 | 菏泽 | 鄂尔多斯 | 万宁 | 黔东南 | 鹤壁 | 天长 | 琼海 | 海南 | 内江 | 临猗 | 玉溪 | 衡阳 | 博罗 | 辽源 | 白城 | 河北石家庄 | 蓬莱 | 洛阳 | 克孜勒苏 | 丽江 | 怀化 | 琼中 | 香港香港 | 邢台 | 石河子 | 通辽 | 大理 | 铁岭 | 日照 | 安岳 | 信阳 | 运城 | 库尔勒 | 连云港 | 陇南 | 台北 | 淮安 |